Merge commit 'a66a6cb102a3de96a9a19a032d820e168b4b8cf4' into remote

Conflicts:
	Android.mk
	src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
	src/com/android/server/telecom/Call.java
	src/com/android/server/telecom/CallsManager.java
	src/com/android/server/telecom/ConnectionServiceWrapper.java
	src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
	src/com/android/server/telecom/ParcelableCallUtils.java
	src/com/android/server/telecom/TelecomSystem.java
	src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
	src/com/android/server/telecom/components/TelecomService.java
	tests/Android.mk
	tests/src/com/android/server/telecom/tests/TelecomSystemTest.java

Change-Id: Ia19fc06f6fbbb91e79edfa87b2d774f076eeab71
diff --git a/Android.mk b/Android.mk
index 6ccd06b..3308e04 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,12 +6,16 @@
 LOCAL_JAVA_LIBRARIES := telephony-common telephony-ext ims-common
 LOCAL_STATIC_JAVA_LIBRARIES := ims-ext-common
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under, proto)
 LOCAL_SRC_FILES += \
        src/org/codeaurora/btmultisim/IBluetoothDsdaService.aidl
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/proto/
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
 LOCAL_PACKAGE_NAME := Telecom
 
 LOCAL_CERTIFICATE := platform
diff --git a/proto/telecom.proto b/proto/telecom.proto
new file mode 100644
index 0000000..06dd394
--- /dev/null
+++ b/proto/telecom.proto
@@ -0,0 +1,280 @@
+syntax = "proto2";
+
+package com.android.server.telecom;
+
+option java_package = "com.android.server.telecom";
+option java_outer_classname = "TelecomLogClass";
+
+// The information about the telecom events.
+message TelecomLog {
+
+  // Information about each call.
+  repeated CallLog call_logs = 1;
+
+  // Timing information for the logging sessions
+  repeated LogSessionTiming session_timings = 2;
+}
+
+message LogSessionTiming {
+  enum SessionEntryPoint {
+    ICA_ANSWER_CALL = 1;
+    ICA_REJECT_CALL = 2;
+    ICA_DISCONNECT_CALL = 3;
+    ICA_HOLD_CALL = 4;
+    ICA_UNHOLD_CALL = 5;
+    ICA_MUTE = 6;
+    ICA_SET_AUDIO_ROUTE = 7;
+    ICA_CONFERENCE = 8;
+
+    CSW_HANDLE_CREATE_CONNECTION_COMPLETE = 100;
+    CSW_SET_ACTIVE = 101;
+    CSW_SET_RINGING = 102;
+    CSW_SET_DIALING = 103;
+    CSW_SET_DISCONNECTED = 104;
+    CSW_SET_ON_HOLD = 105;
+    CSW_REMOVE_CALL = 106;
+    CSW_SET_IS_CONFERENCED = 107;
+    CSW_ADD_CONFERENCE_CALL = 108;
+  }
+
+  // The entry point into Telecom code that this session tracks.
+  optional SessionEntryPoint sessionEntryPoint = 1;
+  // The time it took for this session to finish.
+  optional int64 time_millis = 2;
+}
+
+message Event {
+  // From android.telecom.ParcelableAnalytics
+  enum EventName {
+    SET_SELECT_PHONE_ACCOUNT = 0;
+    SET_ACTIVE = 1;
+    SET_DISCONNECTED = 2;
+    START_CONNECTION = 3;
+    SET_DIALING = 4;
+    BIND_CS = 5;
+    CS_BOUND = 6;
+    REQUEST_ACCEPT = 7;
+    REQUEST_REJECT = 8;
+
+    SCREENING_SENT = 100;
+    SCREENING_COMPLETED = 101;
+    DIRECT_TO_VM_INITIATED = 102;
+    DIRECT_TO_VM_FINISHED = 103;
+    BLOCK_CHECK_INITIATED = 104;
+    BLOCK_CHECK_FINISHED = 105;
+    FILTERING_INITIATED = 106;
+    FILTERING_COMPLETED = 107;
+    FILTERING_TIMED_OUT = 108;
+
+    SKIP_RINGING = 200;
+    SILENCE = 201;
+    MUTE = 202;
+    UNMUTE = 203;
+    AUDIO_ROUTE_BT = 204;
+    AUDIO_ROUTE_EARPIECE = 205;
+    AUDIO_ROUTE_HEADSET = 206;
+    AUDIO_ROUTE_SPEAKER = 207;
+
+    CONFERENCE_WITH = 300;
+    SPLIT_CONFERENCE = 301;
+    SET_PARENT = 302;
+
+    REQUEST_HOLD = 400;
+    REQUEST_UNHOLD = 401;
+    REMOTELY_HELD = 402;
+    REMOTELY_UNHELD = 403;
+    SET_HOLD = 404;
+    SWAP = 405;
+
+    REQUEST_PULL = 500;
+  }
+
+  // The ID of the event.
+  optional EventName event_name = 1;
+
+  // The elapsed time since the last event, rounded to one significant digit.
+  // If the event is the first, this will be negative.
+  optional int64 time_since_last_event_millis = 2;
+}
+
+message VideoEvent {
+  // From android.telecom.ParcelableCallAnalytics
+  enum VideoEventName {
+    SEND_LOCAL_SESSION_MODIFY_REQUEST = 0;
+    SEND_LOCAL_SESSION_MODIFY_RESPONSE = 1;
+    RECEIVE_REMOTE_SESSION_MODIFY_REQUEST = 2;
+    RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE = 3;
+  }
+
+  // From android.telecom.VideoProfile
+  enum VideoState {
+     STATE_AUDIO_ONLY = 0;
+     STATE_TX_ENABLED = 1;
+     STATE_RX_ENABLED = 2;
+     STATE_BIDIRECTIONAL = 3;
+     STATE_PAUSED = 4;
+  }
+
+  // The ID of the event.
+  optional VideoEventName event_name = 1;
+
+  // The elapsed time since the last event, rounded to one significant digit.
+  // If the event is the first, this will be negative.
+  optional int64 time_since_last_event_millis = 2;
+
+  // The video state
+  optional int32 video_state = 3;
+}
+
+message EventTimingEntry {
+  enum EventTimingName {
+    ACCEPT_TIMING = 0;
+    REJECT_TIMING = 1;
+    DISCONNECT_TIMING = 2;
+    HOLD_TIMING = 3;
+    UNHOLD_TIMING = 4;
+    OUTGOING_TIME_TO_DIALING_TIMING = 5;
+    BIND_CS_TIMING = 6;
+    SCREENING_COMPLETED_TIMING = 7;
+    DIRECT_TO_VM_FINISHED_TIMING = 8;
+    BLOCK_CHECK_FINISHED_TIMING = 9;
+    FILTERING_COMPLETED_TIMING = 10;
+    FILTERING_TIMED_OUT_TIMING = 11;
+  }
+
+  // The name of the event timing.
+  optional EventTimingName timing_name = 1;
+
+  // The number of milliseconds that this event pair took.
+  optional int64 time_millis = 2;
+}
+
+message InCallServiceInfo {
+  // Keep this up-to-date with com.android.server.telecom.InCallController.
+  enum InCallServiceType {
+    IN_CALL_SERVICE_TYPE_INVALID = 0;
+    IN_CALL_SERVICE_TYPE_DIALER_UI = 1;
+    IN_CALL_SERVICE_TYPE_SYSTEM_UI = 2;
+    IN_CALL_SERVICE_TYPE_CAR_MODE_UI = 3;
+    IN_CALL_SERVICE_TYPE_NON_UI = 4;
+  }
+
+  // The shortened component name of the in-call service.
+  optional string in_call_service_name = 1;
+
+  // The type of the in-call service
+  optional InCallServiceType in_call_service_type = 2;
+}
+
+// Information about each call.
+message CallLog {
+
+  // Information on call-types.
+  enum CallType {
+
+    // Call type is not known.
+    CALLTYPE_UNKNOWN = 0;
+
+    // Incoming call.
+    CALLTYPE_INCOMING = 1;
+
+    // Outgoing call.
+    CALLTYPE_OUTGOING = 2;
+  }
+
+  // Termination code.
+  enum CallTerminationCode {
+
+    // Disconnected because of an unknown or unspecified reason.
+    CALL_TERMINATION_CODE_UNKNOWN = 0;
+
+    // Disconnected because there was an error, such as a problem
+    // with the network.
+    CALL_TERMINATION_CODE_ERROR = 1;
+
+    // Disconnected because of a local user-initiated action,
+    // such as hanging up.
+    CALL_TERMINATION_CODE_LOCAL = 2;
+
+    // Disconnected because of a remote user-initiated action,
+    // such as the other party hanging up.
+    CALL_TERMINATION_CODE_REMOTE = 3;
+
+    // Disconnected because it has been canceled.
+    CALL_TERMINATION_CODE_CANCELED = 4;
+
+    // Disconnected because there was no response to an incoming call.
+    CALL_TERMINATION_CODE_MISSED = 5;
+
+    // Disconnected because the user rejected an incoming call.
+    CALL_TERMINATION_CODE_REJECTED = 6;
+
+    // Disconnected because the other party was busy.
+    CALL_TERMINATION_CODE_BUSY = 7;
+
+    // Disconnected because of a restriction on placing the call,
+    // such as dialing in airplane mode.
+    CALL_TERMINATION_CODE_RESTRICTED = 8;
+
+    // Disconnected for reason not described by other disconnect codes.
+    CALL_TERMINATION_CODE_OTHER = 9;
+
+    // Disconnected because the connection manager did not support the call.
+    // The call will be tried again without a connection manager.
+    CONNECTION_MANAGER_NOT_SUPPORTED = 10;
+  }
+
+  // Start time of the connection.
+  // Rounded to the nearest 5 minute interval.
+  optional int64 start_time_5min = 1;
+
+  // Duration in millis.
+  optional int64 call_duration_millis = 2;
+
+  // Call type.
+  optional CallType type  = 3;
+
+  // True if the call interrupted an in-progress call, whether it was the
+  // user dialing out during a call or an incoming call during another call.
+  optional bool is_additional_call = 4 [default = false];
+
+  // True if the call was interrupted by another call.
+  optional bool is_interrupted = 5 [default = false];
+
+  // A bitmask with bits corresponding to call technologies that were used
+  // during the call. The ones that we will record are CDMA, GSM, IMS, SIP,
+  // and third-party.
+  // See the com.android.server.telecom.Analytics.*_PHONE constants.
+  optional int32 call_technologies = 6;
+
+  // Indicates the call termination code.
+  optional CallTerminationCode call_termination_code = 7;
+
+  // A list of the package names of connection services used.
+  repeated string connection_service = 9;
+
+  // Set to true if the call was created from createCallForExistingConnection.
+  optional bool is_created_from_existing_connection = 10 [default = false];
+
+  // Set to true if its an emergency call.
+  optional bool is_emergency_call = 11 [default = false];
+
+  // A list of the events that occur during the call.
+  repeated Event call_events = 12;
+
+  // A map from the names of latency timings to the timings.
+  repeated EventTimingEntry call_timings = 13;
+
+  // Whether this call has ever been a video call
+  optional bool is_video_call = 14 [default = false];
+
+  // A list of the video events during the call.
+  repeated VideoEvent video_events = 15;
+
+  // A list of the in-call services bound during the call.
+  repeated InCallServiceInfo in_call_services = 16;
+
+  // A bitmask of the properties that were set at any point during the call.
+  // Bits are defined by android.telecom.Connection.PROPERTY_* constants.
+  optional int32 connection_properties = 17;
+}
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index e46f852..2109cef 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Vermiste stemboodskapnommer"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Geen stemboodskapnommer is op die SIM-kaart gestoor nie."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Voeg nommer by"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Verander verstekbellerprogram?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Gebruik <xliff:g id="NEW_APP">%1$s</xliff:g> eerder as <xliff:g id="CURRENT_APP">%2$s</xliff:g> as jou verstekbellerprogram?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Gebruik <xliff:g id="NEW_APP">%s</xliff:g> as jou verstekbellerprogram?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Maak <xliff:g id="NEW_APP">%s</xliff:g> jou verstek-Foon-program?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Stel verstek"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Kanselleer"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> sal oproepe kan maak en alle aspekte daarvan beheer. Net programme wat jy vertrou, moet as die verstek-Foon-program gestel word."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Geblokkeerde nommers"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Jy sal nie oproepe of boodskappe vanaf geblokkeerde nommers ontvang nie."</string>
     <string name="block_number" msgid="1101252256321306179">"Voeg \'n nommer by"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 3c62c86..41f8b2d 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> የስልክዎ ነባሪ መተግበሪያ ይደረግ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ነባሪ አዘጋጅ"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ይቅር"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 40b895d..8e3abbe 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"هل تريد تعيين <xliff:g id="NEW_APP">%s</xliff:g> باعتباره تطبيق الهاتف الافتراضي؟"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"تعيين كافتراضي"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"إلغاء"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"سيتمكن <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>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 21936d8..850e121 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Səsli poçt nömrəsi çatışmır"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartda heç bir səsli poçt nömrəsi yoxdur."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Nömrə əlavə edin"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Defolt nömrə yığan tətbiqi dəyişdirilsin?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Defolt nömrə yığan tətbiqi kimi <xliff:g id="CURRENT_APP">%2$s</xliff:g> əvəzinə <xliff:g id="NEW_APP">%1$s</xliff:g> işlədilsin?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Defolt nömrə yığan tətbiqi kimi <xliff:g id="NEW_APP">%s</xliff:g> işlədilsin?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> tətbiüi defolt Phone tətbiqi təyin edilsin?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Defolt ayarlayın"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Ləğv edin"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> bütün zəngləri edə və nəzarətdə saxlaya biləcək. Yalnız güvəndiyiniz tətbiqləri Telefon tətbiqi kimi ayarlaya bilərsiniz."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Bloklanmış nömrələr"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Blok edilmiş nömrədən zənglər və ya mesajlar almayacaqsınız."</string>
     <string name="block_number" msgid="1101252256321306179">"Nömrə əlavə edin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 4af952b..b59c29c 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj za govornu poštu"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Nije uskladišten nijedan broj govorne pošte na SIM kartici."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Promeniti podrazumevanu aplikaciju Telefon?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Želite li da koristite aplikaciju <xliff:g id="NEW_APP">%1$s</xliff:g> umesto aplikacije <xliff:g id="CURRENT_APP">%2$s</xliff:g> kao podrazumevanu aplikaciju za pozivanje telefonskih brojeva?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Želite li da koristite aplikaciju <xliff:g id="NEW_APP">%s</xliff:g> kao podrazumevanu aplikaciju za pozivanje telefonskih brojeva?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Želite li da <xliff:g id="NEW_APP">%s</xliff:g> postane podrazumevana aplikacija Telefon?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Postavi kao podrazumevano"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Otkaži"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> će moći da upućuje pozive i kontroliše sve njihove aspekte. Aplikaciju podesite kao podrazumevanu za telefoniranje samo ako je smatrate pouzdanom."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokirani brojevi"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nećete primati pozive ni SMS-ove sa blokiranih brojeva."</string>
     <string name="block_number" msgid="1101252256321306179">"Dodaj broj"</string>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
index 4f04a38..5d44ed9 100644
--- a/res/values-be-rBY/strings.xml
+++ b/res/values-be-rBY/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Зрабіць <xliff:g id="NEW_APP">%s</xliff:g> вашай стандартнай тэлефоннай праграмай?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Задаць як стандартную"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Скасаваць"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> зможа вызначаць і кантраляваць усе аспекты выклікаў. Стандартнымі тэлефоннымі праграмамі павінны прызначацца толькі праграмы, якім вы давяраеце."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Заблакіраваныя нумары"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Вы не будзеце атрымліваць выклікі ці SMS з заблакаваных нумароў."</string>
     <string name="block_number" msgid="1101252256321306179">"Дадаць нумар"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 605f6ca..bbe04b8 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> да бъде ли стандартното ви приложение за телефон?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Задаване като стандартно"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Отказ"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> ще може да извършва обаждания и да контролира всички аспекти на обажданията. Като стандартно приложение за телефон задавайте само приложения, на които имате доверие."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Блокирани номера"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Няма да получавате обаждания или SMS от блокираните номера."</string>
     <string name="block_number" msgid="1101252256321306179">"Добавяне на номер"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 1ce7c85..088ca2a 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"ভয়েসমেল নম্বর অনুপস্থিত"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"সিম কার্ডটিতে কোনো ভয়েসমেল নম্বর সংরক্ষিত নেই৷"</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="CURRENT_APP">%2$s</xliff:g> পরিবর্তে <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> কে আপনার ডিফল্ট ফোন অ্যাপ বানাতে চান?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ডিফল্ট হিসাবে সেট করুন"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"বাতিল করুন"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index 0d27e3a..fd5beff 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Postaviti aplikaciju <xliff:g id="NEW_APP">%s</xliff:g> kao zadanu aplikaciju za telefon?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Postavi zadano"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Otkaži"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> će moći upućivati pozive i kontrolirati sve vezano za njih. Zadana aplikacija treba biti samo aplikacija koju smatrate pouzdanom."</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>
     <string name="block_number" msgid="1101252256321306179">"Dodaj broj"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index fc92f36..9504895 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Falta el número de la bústia de veu"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No hi ha cap número de bústia de veu emmagatzemat a la targeta SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Afegeix número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vols canviar l\'aplicació de marcador predeterminada?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Vols fer servir <xliff:g id="NEW_APP">%1$s</xliff:g> en lloc de <xliff:g id="CURRENT_APP">%2$s</xliff:g> com a aplicació de marcador predeterminada?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Vols fer servir <xliff:g id="NEW_APP">%s</xliff:g> com a aplicació de marcador predeterminada?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Vols que <xliff:g id="NEW_APP">%s</xliff:g> sigui l\'aplicació per a mòbils predetermin.?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Defineix com a predeterminat"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel·la"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> podrà fer les teves trucades i controlar-ne tots els aspectes. Només les aplicacions de confiança s\'han de definir com a l\'aplicació per a mòbils predeterminada."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloquejats"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"No rebràs trucades ni missatges de text dels números bloquejats."</string>
     <string name="block_number" msgid="1101252256321306179">"Afegeix un número"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 8f4e4fc..ac77aac 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Chybí číslo hlasové schránky"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM kartě není uloženo žádné číslo hlasové schránky."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Přidat číslo"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Změnit výchozí aplikaci vytáčení?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Chcete aplikaci <xliff:g id="NEW_APP">%1$s</xliff:g> použít jako výchozí aplikaci vytáčení místo aplikace <xliff:g id="CURRENT_APP">%2$s</xliff:g>?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Chcete aplikaci <xliff:g id="NEW_APP">%s</xliff:g> použít jako výchozí aplikaci vytáčení?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Nastavit <xliff:g id="NEW_APP">%s</xliff:g> jako výchozí aplikaci na telefonování?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Nastavit jako výchozí"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Zrušit"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Aplikace <xliff:g id="NEW_APP">%s</xliff:g> bude moci uskutečňovat hovory a spravovat všechny jejich aspekty. Jako výchozí aplikaci na telefonování byste měli nastavit jen aplikaci, které věříte."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokovaná čísla"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Ze zablokovaných čísel už nebudete přijímat hovory ani zprávy SMS."</string>
     <string name="block_number" msgid="1101252256321306179">"Přidat číslo"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index f90cecf..48fba35 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Telefonsvarernummer mangler"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Der er ikke gemt noget telefonsvarernummer på SIM-kortet."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Tilføj nummer"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vil du skifte standardappen til opkald?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Brug <xliff:g id="NEW_APP">%1$s</xliff:g> i stedet for <xliff:g id="CURRENT_APP">%2$s</xliff:g> som din standardapp til opkald?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Brug <xliff:g id="NEW_APP">%s</xliff:g> som din standardapp til opkald?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Vil du gøre <xliff:g id="NEW_APP">%s</xliff:g> til din standardapp til opkald?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Indstil standard"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Annuller"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> kan foretage og administrere alle aspekter af opkald. Du bør kun indstille en app til din standardapp til opkald, hvis du har tillid til den."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokerede telefonnumre"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Du modtager ikke opkald eller sms-beskeder fra blokerede numre."</string>
     <string name="block_number" msgid="1101252256321306179">"Tilføj et nummer"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 71949ea..7993f35 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Fehlende Mailbox-Nummer"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Auf der SIM-Karte ist keine Mailbox-Nummer gespeichert."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Nummer hinzufügen"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Standard-App für Telefonie ändern?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g> statt <xliff:g id="CURRENT_APP">%2$s</xliff:g> als Standard-App für Telefonie verwenden?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g> als Standard-App für Telefonie verwenden?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> als Standard-Telefon-App festlegen?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Als Standard festlegen"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Abbrechen"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> wird alle Anruffunktionen steuern. Nur vertrauenswürdige Apps sollten als Standard-Telefon-App festgelegt werden."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blockierte Nummern"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Du erhältst keine Anrufe oder SMS von blockierten Nummern."</string>
     <string name="block_number" msgid="1101252256321306179">"Nummer hinzufügen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index c39387a..06ee5ab 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -45,9 +45,10 @@
     <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">"Αλλαγή της προεπιλεγμένης εφαρμογής Dialer;"</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> ως προεπιλεγμένης εφαρμογής Dialer;"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Χρήση της εφαρμογής <xliff:g id="NEW_APP">%s</xliff:g> ως προεπιλεγμένης εφαρμογής Dialer;"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Ορισμός <xliff:g id="NEW_APP">%s</xliff:g> ως προεπιλεγμένης εφαρμογής τηλεφώνου;"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Ορισμός ως προεπιλογή"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Ακύρωση"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Το <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>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 661ceee..0d01605 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Change default Dialer app?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Use <xliff:g id="NEW_APP">%1$s</xliff:g> instead of <xliff:g id="CURRENT_APP">%2$s</xliff:g> as your default dialler app?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Use <xliff:g id="NEW_APP">%s</xliff:g> as your default dialler app?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Make <xliff:g id="NEW_APP">%s</xliff:g> your default Phone app?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Set Default"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> will be able to place and control all aspects of calls. Only apps that you trust should be set as the default Phone app."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blocked numbers"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"You won\'t receive calls or texts from blocked numbers."</string>
     <string name="block_number" msgid="1101252256321306179">"Add a number"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 661ceee..0d01605 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Change default Dialer app?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Use <xliff:g id="NEW_APP">%1$s</xliff:g> instead of <xliff:g id="CURRENT_APP">%2$s</xliff:g> as your default dialler app?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Use <xliff:g id="NEW_APP">%s</xliff:g> as your default dialler app?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Make <xliff:g id="NEW_APP">%s</xliff:g> your default Phone app?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Set Default"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> will be able to place and control all aspects of calls. Only apps that you trust should be set as the default Phone app."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blocked numbers"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"You won\'t receive calls or texts from blocked numbers."</string>
     <string name="block_number" msgid="1101252256321306179">"Add a number"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 661ceee..0d01605 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Change default Dialer app?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Use <xliff:g id="NEW_APP">%1$s</xliff:g> instead of <xliff:g id="CURRENT_APP">%2$s</xliff:g> as your default dialler app?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Use <xliff:g id="NEW_APP">%s</xliff:g> as your default dialler app?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Make <xliff:g id="NEW_APP">%s</xliff:g> your default Phone app?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Set Default"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancel"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> will be able to place and control all aspects of calls. Only apps that you trust should be set as the default Phone app."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blocked numbers"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"You won\'t receive calls or texts from blocked numbers."</string>
     <string name="block_number" msgid="1101252256321306179">"Add a number"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index a791c8a..6768c48 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Falta el número de correo de voz"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No hay un número de correo de voz almacenado en la tarjeta SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Agregar número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"¿Quieres cambiar la aplicación Marcador predeterminada?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"¿Quieres usar <xliff:g id="NEW_APP">%1$s</xliff:g> en lugar de <xliff:g id="CURRENT_APP">%2$s</xliff:g> como la aplicación de marcado predeterminada?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"¿Quieres usar <xliff:g id="NEW_APP">%s</xliff:g> como la aplicación de marcado predeterminada?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"¿Establecer <xliff:g id="NEW_APP">%s</xliff:g> como la app de teléfono predeterminada?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Establecer como predeterminada"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> podrá realizar llamadas y controlar todos los aspectos relacionados con ellas. Establece solamente una app de confianza como la app de teléfono predeterminada."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"No recibirás llamadas ni mensajes de texto de los números bloqueados."</string>
     <string name="block_number" msgid="1101252256321306179">"Agregar un número"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index b793ca7..f9be28b 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Falta el número del buzón de voz."</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"No se ha almacenado ningún número de buzón de voz en la tarjeta SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Añadir número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"¿Cambiar el marcador predeterminado?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"¿Quieres utilizar <xliff:g id="NEW_APP">%1$s</xliff:g> en lugar de <xliff:g id="CURRENT_APP">%2$s</xliff:g> como marcador predeterminado?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"¿Quieres utilizar <xliff:g id="NEW_APP">%s</xliff:g> como marcador predeterminado?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"¿Quieres que <xliff:g id="NEW_APP">%s</xliff:g> sea tu aplicación de teléfono predeterminada?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Configurar como predeterminada"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> podrá llamar y controlar todo lo relacionado con las llamadas. Te aconsejamos que solo configures una aplicación como predeterminada si es de confianza."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"No recibirás llamadas ni SMS de los números bloqueados."</string>
     <string name="block_number" msgid="1101252256321306179">"Añadir un número"</string>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index ff37ee4..506ba31 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Puudub kõnepostinumber"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-kaardile pole salvestatud ühtegi kõnepostinumbrit."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Lisa number"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Kas muuta helistamise vaikerakendust?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Kas kasutada rakendust <xliff:g id="NEW_APP">%1$s</xliff:g> rakenduse <xliff:g id="CURRENT_APP">%2$s</xliff:g> asemel helistamise vaikerakendusena?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Kas kasutada rakendust <xliff:g id="NEW_APP">%s</xliff:g> helistamise vaikerakendusena?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Kas muuta rakendus <xliff:g id="NEW_APP">%s</xliff:g> telefoni vaikerakenduseks?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Määra vaikeseadeks"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Tühista"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Rakendus <xliff:g id="NEW_APP">%s</xliff:g> saab helistada ja juhtida kõiki kõnede aspekte. Määrake telefoni vaikerakenduseks vaid usaldusväärsed rakendused."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokeeritud numbrid"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Te ei saa blokeeritud numbritelt kõnesid ega tekstsõnumeid."</string>
     <string name="block_number" msgid="1101252256321306179">"Lisa number"</string>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 3a3bdd9..7f2ef59 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Erantzungailuaren zenbakia falta da"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Ez da erantzungailuaren zenbakirik gorde SIM txartelean."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Gehitu zenbakia"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Telefono-aplikazio lehenetsia aldatu nahi duzu?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="CURRENT_APP">%2$s</xliff:g> aplikazioaren ordez <xliff:g id="NEW_APP">%1$s</xliff:g> erabili nahi duzu telefono-aplikazio lehenetsi gisa?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g> telefono-aplikazio lehenetsi gisa erabili nahi duzu?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> telefonoaren aplikazio lehenetsia izatea nahi duzu?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Ezarri lehenetsi gisa"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Utzi"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Deien aspektu guztiak erabili eta kontrolatu ahal izango ditu <xliff:g id="NEW_APP">%s</xliff:g> aplikazioak. Fidagarriak diren aplikazioak bakarrik erabili beharko lirateke telefonoaren aplikazio lehenetsi gisa."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokeatutako zenbakiak"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Ez duzu jasoko deirik edo testu-mezurik blokeatutako zenbakietatik."</string>
     <string name="block_number" msgid="1101252256321306179">"Gehitu zenbakia"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index aec0966..78acda1 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"عدم وجود شماره پست صوتی"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"شماره پست صوتی در سیم کارت ذخیره نشده است."</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> را به برنامه تلفن پیش‌فرضتان تبدیل می‌کنید؟"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"تنظیم پیش‌فرض"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"لغو"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 5481e47..b810ac5 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Puhelinvastaajan numero puuttuu"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-kortille ei ole tallennettu puhelinvastaajan numeroa."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Lisää numero"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vaihdetaanko oletuspuhelusovellus?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Asetetaanko oletuspuhelusovellukseksi <xliff:g id="NEW_APP">%1$s</xliff:g> sovelluksen <xliff:g id="CURRENT_APP">%2$s</xliff:g> sijaan?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Asetetaanko <xliff:g id="NEW_APP">%s</xliff:g> oletuspuhelusovellukseksi?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Valitaanko <xliff:g id="NEW_APP">%s</xliff:g> oletuspuhelinsovellukseksi?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Aseta oletukseksi"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Peruuta"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> voi hallita kaikkia puhelutoimintoja. Aseta oletuspuhelinsovellukseksi vain luotettava sovellus."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Estetyt numerot"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Et voi vastaanottaa puheluita tai tekstiviestejä estetyistä numeroista."</string>
     <string name="block_number" msgid="1101252256321306179">"Lisää numero"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index f1f6f14..d41cb2d 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Numéro de messagerie vocale manquant"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Aucun numéro de messagerie vocale n\'est enregistré sur la carte SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Ajouter un numéro"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Changer l\'application de composition par défaut?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Utiliser <xliff:g id="NEW_APP">%1$s</xliff:g> au lieu de <xliff:g id="CURRENT_APP">%2$s</xliff:g> comme application de composition par défaut?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Utiliser <xliff:g id="NEW_APP">%s</xliff:g> comme application de composition par défaut?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Définir <xliff:g id="NEW_APP">%s</xliff:g> comme votre application de téléphonie par défaut?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Définir comme application de téléphonie par défaut"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Annuler"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> sera en mesure de passer des appels et de contrôler tous les aspects des appels. Seules les applications auxquelles vous avez confiance doivent être définies comme l\'application de téléphonie par défaut."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Numéros bloqués"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Vous ne recevrez pas d\'appels ni de messages texte provenant des numéros bloqués."</string>
     <string name="block_number" msgid="1101252256321306179">"Ajouter un numéro"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index f641545..57df3d0 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Numéro de messagerie vocale manquant"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Aucun numéro de messagerie vocale n\'est enregistré sur la carte SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Ajouter un numéro"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Modifier l\'application de clavier par défaut ?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Utiliser <xliff:g id="NEW_APP">%1$s</xliff:g> et non plus <xliff:g id="CURRENT_APP">%2$s</xliff:g> comme application de clavier par défaut ?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Utiliser <xliff:g id="NEW_APP">%s</xliff:g> comme application de clavier par défaut ?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Définir <xliff:g id="NEW_APP">%s</xliff:g> comme application de téléphone par défaut ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Définir l\'application par défaut"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Annuler"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> sera en mesure de passer des appels et d\'en contrôler tous les détails. Ne définissez qu\'une application de confiance comme application de téléphone par défaut."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Numéros bloqués"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Vous ne recevrez plus les appels ni les SMS émis depuis les numéros bloqués."</string>
     <string name="block_number" msgid="1101252256321306179">"Ajouter un numéro"</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index ae89a83..c6786c2 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Falta o número de correo de voz"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Non hai ningún número de correo de voz almacenado na tarxeta SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Engadir número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Queres cambiar a aplicación predeterminada do marcador?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Queres usar <xliff:g id="NEW_APP">%1$s</xliff:g> en lugar de <xliff:g id="CURRENT_APP">%2$s</xliff:g> como a túa aplicación de marcador predeterminada?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Queres usar <xliff:g id="NEW_APP">%s</xliff:g> como a túa aplicación de marcador predeterminada?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Establecer <xliff:g id="NEW_APP">%s</xliff:g> como aplicación de teléfono predeterminada?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Establecer como predeterminada"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> poderá facer chamadas e controlar todo o referente a estas. Só deberías establecer como aplicación de teléfono predeterminada aplicacións nas que confíes."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Non recibirás chamadas nin mensaxes de texto desde números bloqueados."</string>
     <string name="block_number" msgid="1101252256321306179">"Engadir un número"</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 3442516..afaebe4 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> ને બદલે <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"શું <xliff:g id="NEW_APP">%s</xliff:g> ને તમારી ડિફૉલ્ટ ફોન ઍપ્લિકેશન બનાવીએ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ડિફૉલ્ટ સેટ કરો"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"રદ કરો"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index c011b4a..874712d 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"गुम वॉयस मेल नंबर"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्ड पर कोई वॉयस मेल नंबर संग्रहीत नहीं है."</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="CURRENT_APP">%2$s</xliff:g> के बजाय <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> को अपना डिफ़ॉल्ट ऐप्लिकेशन बनाएं?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"डिफ़ॉल्ट सेट करें"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"अभी नहीं"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 6e7fb3a..86e06ed 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj govorne pošte"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM kartici nije spremljen broj govorne pošte."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Želite li promijeniti zadanu aplikaciju brojčanika?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Želite li upotrebljavati <xliff:g id="NEW_APP">%1$s</xliff:g> umjesto aplikacije <xliff:g id="CURRENT_APP">%2$s</xliff:g> kao zadanu aplikaciju brojčanika?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Želite li upotrebljavati <xliff:g id="NEW_APP">%s</xliff:g> kao zadanu aplikaciju brojčanika?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Želite li postaviti <xliff:g id="NEW_APP">%s</xliff:g> kao zadanu aplikaciju telefona?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Postavi zadano"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Odustani"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> će moći uspostaviti poziv i upravljati svim njegovim aspektima. Kao zadanu aplikaciju telefona postavite samo aplikaciju koju smatrate pouzdanom."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokirani brojevi"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nećete primati ni pozive ni poruke s blokiranih brojeva."</string>
     <string name="block_number" msgid="1101252256321306179">"Dodaj broj"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 72476bc..6266e54 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Hiányzik a hangposta száma"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Nincs hangpostaszám a SIM kártyán."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Szám hozzáadása"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Módosítja az alapértelmezett tárcsázó alkalmazást?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Legyen a(z) <xliff:g id="NEW_APP">%1$s</xliff:g> az alapértelmezett tárcsázó alkalmazás a(z) <xliff:g id="CURRENT_APP">%2$s</xliff:g> helyett?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Legyen a(z) <xliff:g id="NEW_APP">%s</xliff:g> az alapértelmezett tárcsázó alkalmazás?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Beállítja a(z) <xliff:g id="NEW_APP">%s</xliff:g> alkalmazást alapértelmezettként?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Beállítás alapértelmezettként"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Mégse"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> jogosult lesz hívások indítására és a hívásokkal kapcsolatos minden beállítás vezérlésére. Csak megbízható alkalmazást állítson be alapértelmezett telefonalkalmazásként."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Letiltott számok"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"A jövőben nem kap hívásokat vagy SMS-eket a letiltott számokról."</string>
     <string name="block_number" msgid="1101252256321306179">"Szám hozzáadása"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 1061754..7c6d12b 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Նշե՞լ <xliff:g id="NEW_APP">%s</xliff:g>-ը որպես Հեռախոսի կանխադրված հավելված:"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Սահմանել որպես կանխադրված"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Չեղարկել"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> հավելվածը կկատարի զանգերի հետ կապված բոլոր գործառույթները: Որպես Հեռախոսի կանխադրված հավելված նշեք միայն վստահելի հավելվածներ:"</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Արգելափակված համարներ"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Արգելափակված համարներից զանգեր կամ SMS–ներ չեք ստանա:"</string>
     <string name="block_number" msgid="1101252256321306179">"Ավելացնել համար"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index edb0731..780c94b 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nomor kotak pesan hilang"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Tidak ada nomor kotak pesan tersimpan pada kartu SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Tambahkan nomor"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Ubah aplikasi Pemanggil default?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Gunakan <xliff:g id="NEW_APP">%1$s</xliff:g>, bukan <xliff:g id="CURRENT_APP">%2$s</xliff:g> sebagai aplikasi pemanggil default?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Gunakan <xliff:g id="NEW_APP">%s</xliff:g> sebagai aplikasi pemanggil default?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Jadikan <xliff:g id="NEW_APP">%s</xliff:g> sebagai aplikasi Telepon default?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Setel Default"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Batal"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> dapat melakukan panggilan dan mengontrol semua aspek panggilan. Hanya aplikasi yang Anda percaya boleh disetel sebagai aplikasi Telepon default."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Nomor yang diblokir"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Anda tidak akan menerima telepon atau SMS dari nomor yang diblokir."</string>
     <string name="block_number" msgid="1101252256321306179">"Tambah nomor"</string>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index 928a74e..bc43950 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Talhólfsnúmer vantar"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Ekkert talhólfsnúmer er vistað á SIM-kortinu."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Bæta númeri við"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Viltu skipta um sjálfgefið hringiforrit?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Nota <xliff:g id="NEW_APP">%1$s</xliff:g> í stað <xliff:g id="CURRENT_APP">%2$s</xliff:g> sem sjálfgefið hringiforrit?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Nota <xliff:g id="NEW_APP">%s</xliff:g> sem sjálfgefið hringiforrit?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Gera <xliff:g id="NEW_APP">%s</xliff:g> að sjálfgefnu símaforriti?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Velja sem sjálfgefið"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Hætta við"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> getur framkvæmt og stjórnað öllu sem tengist símtölum. Einungis forrit sem þú treystir ættu að vera stillt sem sjálfgefið símaforrit."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Númer á bannlista"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Þú færð ekki símtöl eða skilaboð frá númerum á bannlista."</string>
     <string name="block_number" msgid="1101252256321306179">"Bæta við númeri"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index bddb598..716f765 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Numero segreteria mancante"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Nessun numero di segreteria presente nella SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Aggiungi numero"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Modificare l\'app tastiera predefinita?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Utilizzare <xliff:g id="NEW_APP">%1$s</xliff:g> invece di <xliff:g id="CURRENT_APP">%2$s</xliff:g> come app tastiera predefinita?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Utilizzare <xliff:g id="NEW_APP">%s</xliff:g> come app tastiera predefinita?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Rendere <xliff:g id="NEW_APP">%s</xliff:g> l\'app predefinita del tuo telefono?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Imposta come predefinita"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Annulla"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> potrà effettuare e controllare tutti gli aspetti delle chiamate. L\'app predefinita del telefono dovrebbe essere un\'app di cui ti fidi."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Numeri bloccati"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Non riceverai chiamate o SMS da numeri bloccati."</string>
     <string name="block_number" msgid="1101252256321306179">"Aggiungi un numero"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 24fa715..a730121 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"האם להפוך את <xliff:g id="NEW_APP">%s</xliff:g> לברירת המחדל לאפליקציית \'טלפון\'?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"הגדר כברירת מחדל"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ביטול"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 1977b02..256d926 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> をデフォルトの電話アプリにしますか?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"デフォルトに設定"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"キャンセル"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 520913b..1e48ae1 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g>-ის ნაცვლად <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"გახდეს <xliff:g id="NEW_APP">%s</xliff:g> თქვენი ნაგულისხმევი ტელეფონის აპი?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ნაგულისხმევად დაყენება"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"გაუქმება"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 524203f..5a49e4d 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> орнына <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> қолданбасын әдепкі Телефон қолданбасы ретінде сақтайсыз ба?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Әдепкі ретінде орнату"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Тоқтату"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 93dac37..f3fa21b 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"បាត់​​ចំនួន​​សារ​ជា​សំឡេង"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"គ្មាន​ចំនួន​សារ​ជា​សំឡេង​​ត្រូវ​បាន​រក្សា​ទុក​នៅ​លើ​ស៊ី​ម​កាត​ទេ​។"</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"ធ្វើ​ <xliff:g id="NEW_APP">%s</xliff:g> ជា​កម្មវិធី​ទូរសព្ទ​លំនាំដើម​របស់​អ្នក​ដែរ ឬ​ទេ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"កំណត់​លំនាំដើម"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"បោះបង់"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 0117849..7ae3a29 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -33,7 +33,7 @@
     <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_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>
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"ಧ್ವನಿಮೇಲ್‌ ಸಂಖ್ಯೆಯು ಕಾಣೆಯಾಗಿದೆ"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"ಸಿಮ್‌ ಕಾರ್ಡ್‌ನಲ್ಲಿ ಯಾವುದೇ ಧ್ವನಿಮೇಲ್‌ ಸಂಖ್ಯೆಯನ್ನು ಸಂಗ್ರಹಿಸಿಲ್ಲ."</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="CURRENT_APP">%2$s</xliff:g> ಬದಲಿಗೆ <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> ಅನ್ನು ನಿಮ್ಮ ಡಿಫಾಲ್ಟ್ ಫೋನ್ ಅಪ್ಲಿಕೇಶನ್ ಆಗಿ ಮಾಡುವುದೇ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ಡಿಫಾಲ್ಟ್ ಹೊಂದಿಸಿ"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ರದ್ದುಮಾಡು"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 8b347b5..9cf688a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> 대신 <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g>을(를) 기본 전화 앱으로 설정하나요?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"기본으로 설정"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"취소"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index f0ddb39..31d81df 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> колдонмонун ордуна <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> колдонмосун демейки телефон колдонмосу кыласызбы?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Демейки шартта колдонуу"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Жокко чыгаруу"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index ac8ed8c..adc0d1a 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"ບໍ່ມີເບີຂໍ້ຄວາມສຽງ"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"ບໍ່ມີເບີຂໍ້ຄວາມສຽງຖືກບັນທຶກໃນ SIM card."</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"ຕັ້ງໃຫ້ <xliff:g id="NEW_APP">%s</xliff:g> ເປັນແອັບໂທລະສັບເລີ່ມຕົ້ນຂອງທ່ານບໍ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ຍົກເລີກ"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index c1146fd..00bc892 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Trūksta balso pašto numerio"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kortelėje nėra išsaugoto balso pašto numerio."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Pridėti numerį"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Pakeisti numatytąją numerio rinkiklio programą?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Naudoti „<xliff:g id="NEW_APP">%1$s</xliff:g>“ vietoje „<xliff:g id="CURRENT_APP">%2$s</xliff:g>“ kaip numatytąją numerio rinkiklio programą?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Naudoti „<xliff:g id="NEW_APP">%s</xliff:g>“ kaip numatytąją numerio rinkiklio programą?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Nustatyti „<xliff:g id="NEW_APP">%s</xliff:g>“ kaip numatytąją telefono programą?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Nustatyti numatytuosius nustatymus"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Atšaukti"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"„<xliff:g id="NEW_APP">%s</xliff:g>“ galės atlikti ir valdyti įvairius skambučius. Tik patikimą programą turėtumėte nustatyti kaip numatytąją telefono programą."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Užblokuoti numeriai"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Negausite skambučių ar teksto pranešimų iš užblokuotų numerių."</string>
     <string name="block_number" msgid="1101252256321306179">"Pridėti numerį"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 0bee0f2..2238f9d 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Trūkst balss pasta numura"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartē neviens balss pasta numurs nav saglabāts."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Pievienot numuru"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vai mainīt numura sastādītāja noklusējuma lietotni?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Vai lietotnes <xliff:g id="CURRENT_APP">%2$s</xliff:g> vietā izmantot <xliff:g id="NEW_APP">%1$s</xliff:g> kā numura sastādītāja noklusējuma lietotni?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Vai izmantot <xliff:g id="NEW_APP">%s</xliff:g> kā numura sastādītāja noklusējuma lietotni?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Vai iestatīt <xliff:g id="NEW_APP">%s</xliff:g> kā tālruņa noklusējuma lietotni?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Iestatīt kā noklusējumu"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Atcelt"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Lietotne <xliff:g id="NEW_APP">%s</xliff:g> varēs veikt zvanus un kontrolēt visas zvanu funkcijas. Tālruņa noklusējuma lietotnes iestatīšanai izmantojiet tikai uzticamas lietotnes."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Bloķētie numuri"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Jūs nesaņemsiet zvanus vai īsziņas no bloķētajiem numuriem."</string>
     <string name="block_number" msgid="1101252256321306179">"Pievienot numuru"</string>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 33a7b73..bc47335 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Недостасува број на говорна пошта"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Нема мемориран број на говорна пошта на СИМ картичката."</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Да се направи <xliff:g id="NEW_APP">%s</xliff:g> ваша стандардна апликација Телефон?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Поставете стандардна"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Откажете"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> ќе може да ги поставува и контролира сите аспекти на повикувањето. Само апликации на кои им веруваш треба да се поставуваат како стандардната апликација Телефон."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Блокирани броеви"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Нема да добивате повици или SMS од блокирани броеви."</string>
     <string name="block_number" msgid="1101252256321306179">"Додај број"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index b2a87bd..d16e447 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"വോയ്‌സ്മെയിൽ നമ്പർ കാണുന്നില്ല"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"സിം കാർഡിൽ വോയ്‌സ്‌മെയിൽ നമ്പറൊന്നും സംഭരിച്ചിട്ടില്ല."</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="CURRENT_APP">%2$s</xliff:g> എന്നതിനുപകരം <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> എന്നതിനെ നിങ്ങളുടെ ഡിഫോൾട്ട് ഫോൺ ആപ്പാക്കണോ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ഡിഫോൾട്ട് ഫോൺ ആപ്പ് സജ്ജമാക്കുക"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"റദ്ദാക്കുക"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index cfe39d0..8e0b39b 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g>-г өөрийн өгөгдмөл Утасны апп болгох уу?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Өгөгдмөл болгох"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Цуцлах"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 3dfcd34..a4f55fb 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"व्हॉइसमेल नंबर गहाळ"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्डवर कोणताही व्हॉइसमेल नंबर संचयित केला नाही."</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="CURRENT_APP">%2$s</xliff:g> ऐवजी <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> ला आपला डीफॉल्ट अॅप बनवायचा?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"डीफॉल्ट म्हणून सेट करा"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"रद्द करा"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index c77f2bb..208dcb1 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nombor mel suara tiada"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Tidak ada nombor mel suara disimpan pada kad SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Tambah nombor"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Tukar apl Pendail lalai?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Gunakan <xliff:g id="NEW_APP">%1$s</xliff:g> dan bukannya <xliff:g id="CURRENT_APP">%2$s</xliff:g> sebagai apl pendail lalai anda?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Gunakan <xliff:g id="NEW_APP">%s</xliff:g> sebagai apl pendail lalai anda?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Jadikan <xliff:g id="NEW_APP">%s</xliff:g> apl Telefon lalai anda?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Tetapkan Lalai"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Batal"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> akan dapat membuat dan mengawal semua aspek panggilan. Hanya apl yang anda percayai sahaja yang seharusnya ditetapkan sebagai apl Telefon lalai."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Nombor yang disekat"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Anda tidak akan menerima panggilan atau teks daripada nombor yang disekat."</string>
     <string name="block_number" msgid="1101252256321306179">"Tambahkan nombor"</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 1eccf5e..da191da 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"အသံစာပို့စနစ် နံပါတ် ပျောက်နေပါသည်"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"ဆင်းမ်ကဒ်ပေါ်တွင် အသံစာပို့စနစ် နံပါတ် သိမ်းဆည်ထားခြင်း မရှိပါ"</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="CURRENT_APP">%2$s</xliff:g> အစား <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> ကို သင့်ဖုန်း၏မူရင်းအက်ပ်အဖြစ် ထားမလား။"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"မူရင်း သတ်မှတ်ရန်"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"မလုပ်တော့"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> သည် ခေါ်ဆိုမှုများကို ဘက်စုံပြုလုပ်ထိန်းချုပ်သွားနိုင်မည်ဖြစ်သည်။ သင်ယုံကြည်သော အက်ပ်များကိုသာ မူရင်း Phone အက်ပ်အဖြစ် သတ်မှတ်သင့်ပါသည်။"</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"ပိတ်ဆို့ထားသည့် နံပါတ်များ"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"သင်သည် ဘလော့ခ်လုပ်ထားသော နံပါတ်များမှ ဖုန်းခေါ်ခြင်း (သို့) စာသားပို့ခြင်းတို့ကို လက်ခံရရှိမည် မဟုတ်ပါ။"</string>
     <string name="block_number" msgid="1101252256321306179">"နံပါတ်တစ်ခု ထည့်ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 1af23ae..230e9c3 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Mangler nummer til talepostkasse"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Det er ikke lagret noe nummer for talepostkasse på SIM-kortet."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Legg til nummer"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vil du endre standard telefonapp?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Vil du bruke <xliff:g id="NEW_APP">%1$s</xliff:g> i stedet for <xliff:g id="CURRENT_APP">%2$s</xliff:g> som standard telefonapp?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Vil du bruke <xliff:g id="NEW_APP">%s</xliff:g> som standard telefonapp?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Vil du bruke <xliff:g id="NEW_APP">%s</xliff:g> som standard telefonapp?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Angi som standard"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Avbryt"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> kan håndtere alt som har med telefonanrop å gjøre. Bruk bare apper du stoler på som standard telefonapp."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokkerte numre"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Du mottar ingen anrop eller tekstmeldinger fra blokkerte numre."</string>
     <string name="block_number" msgid="1101252256321306179">"Legg til et nummer"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 3becfb9..7ed47f4 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g>को सट्टामा <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"तपाईंको पूर्वनिर्धारित फोन अनुप्रयोग <xliff:g id="NEW_APP">%s</xliff:g> बनाउने हो?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"पूर्वनिर्धारित रूपमा सेट गर्नुहोस्"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"रद्द गर्नुहोस्"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index b50b111..7f8821a 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Voicemailnummer ontbreekt"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Er is geen voicemailnummer op de SIM-kaart opgeslagen."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Nummer toevoegen"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Standaard kiezerapp wijzigen?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g> in plaats van <xliff:g id="CURRENT_APP">%2$s</xliff:g> gebruiken als standaard kiezerapp?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g> gebruiken als standaard kiezerapp?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Wil je <xliff:g id="NEW_APP">%s</xliff:g> instellen als je standaard telefoon-app?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Standaard instellen"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Annuleren"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> kan oproepen plaatsen en alle aspecten hiervan beheren. Stel alleen apps in als je standaard telefoon-app als je ze vertrouwt."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Geblokkeerde nummers"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Je ontvangt geen oproepen of sms\'jes van geblokkeerde nummers."</string>
     <string name="block_number" msgid="1101252256321306179">"Een nummer toevoegen"</string>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 738f992..73800d9 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> ਦੀ ਬਜਾਏ <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"ਕੀ <xliff:g id="NEW_APP">%s</xliff:g> ਨੂੰ ਆਪਣੀ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਫ਼ੋਨ ਐਪ ਬਣਾਉਣਾ ਹੈ?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈੱਟ ਕਰੋ"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ਰੱਦ ਕਰੋ"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index c6567ec..e460463 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Brakuje numeru poczty głosowej"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Na karcie SIM nie ma zapisanego numeru poczty głosowej."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj numer"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Zmienić domyślną aplikację telefonu?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Zmienić <xliff:g id="CURRENT_APP">%2$s</xliff:g> na <xliff:g id="NEW_APP">%1$s</xliff:g> jako domyślną aplikację telefonu?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Ustawić <xliff:g id="NEW_APP">%s</xliff:g> jako domyślną aplikację telefonu?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Ustawić <xliff:g id="NEW_APP">%s</xliff:g> jako domyślną aplikację telefoniczną?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Ustaw jako aplikację domyślną"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Anuluj"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> uzyska możliwość nawiązywania połączeń i kontrolowania wszystkich ich aspektów. Tylko zaufane aplikacje powinny być ustawiane jako domyślna aplikacja telefoniczna."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Zablokowane numery"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nie będziesz otrzymywać połączeń ani SMS-ów z zablokowanych numerów."</string>
     <string name="block_number" msgid="1101252256321306179">"Dodaj numer"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 8f45672..b2e576e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Número do correio de voz em falta"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Não existe um número de correio de voz armazenado no cartão SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Adicionar número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Alterar aplicação de Telefone predefinida?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Utilizar <xliff:g id="NEW_APP">%1$s</xliff:g> em vez de <xliff:g id="CURRENT_APP">%2$s</xliff:g> como a aplicação de telefone predefinida?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Utilizar <xliff:g id="NEW_APP">%s</xliff:g> como a aplicação de telefone predefinida?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Predefinir <xliff:g id="NEW_APP">%s</xliff:g> como a sua aplicação Telefone?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Predefinir"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"A aplicação <xliff:g id="NEW_APP">%s</xliff:g> poderá efetuar chamadas e controlar todos os aspetos das mesmas. Apenas as aplicações em que confia devem ser escolhidas como a aplicação de telefone predefinida."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Não irá receber chamadas ou mensagens de texto de números bloqueados."</string>
     <string name="block_number" msgid="1101252256321306179">"Adicionar um número"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index e2dc815..6d4271c 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Número correio de voz ausente"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Não há um número correio de voz armazenado no cartão SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Adicionar número"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Alterar o app discador padrão?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Usar <xliff:g id="NEW_APP">%1$s</xliff:g> em vez de <xliff:g id="CURRENT_APP">%2$s</xliff:g> como seu app discador padrão?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Usar <xliff:g id="NEW_APP">%s</xliff:g> como seu app discador padrão?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Usar o <xliff:g id="NEW_APP">%s</xliff:g> como seu aplicativo de smartphone padrão?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Definir padrão"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"O <xliff:g id="NEW_APP">%s</xliff:g> poderá ligar e controlar todos os aspectos das chamadas. Defina como aplicativo de smartphone padrão somente aqueles em que você confia."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Você não receberá chamadas nem mensagens de texto dos números bloqueados."</string>
     <string name="block_number" msgid="1101252256321306179">"Adicionar um número"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index ccad8e3..4c204fb 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Lipsește numărul mesageriei vocale"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Niciun număr de mesagerie vocală nu este stocat pe cardul SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Adăugați numărul"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Schimbați aplicația Telefon prestabilită?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Folosiți <xliff:g id="NEW_APP">%1$s</xliff:g> și nu <xliff:g id="CURRENT_APP">%2$s</xliff:g> ca aplicație de telefonie prestabilită?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Folosiți <xliff:g id="NEW_APP">%s</xliff:g> ca aplicație de telefonie prestabilită?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Setați <xliff:g id="NEW_APP">%s</xliff:g> ca aplicație prestabilită a telefonului?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Setați ca prestabilită"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Anulați"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> va putea iniția apeluri și va putea controla toate aspectele acestora. E recomandat să setați ca aplicație prestabilită a telefonului numai aplicații în care aveți încredere."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Numere blocate"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nu veți primi apeluri sau mesaje text de la numerele blocate."</string>
     <string name="block_number" msgid="1101252256321306179">"Adăugați un număr"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 1f6f5af..b7b9edf 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Сделать <xliff:g id="NEW_APP">%s</xliff:g> приложением по умолчанию для звонков?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Использовать по умолчанию"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Отмена"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 78badfa..6a445bb 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> වෙනුවට <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> ඔබේ පෙරනිමි දුරකථන යෙදුම කරන්නද?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"පෙරනිමිය සකසන්න"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"අවලංගු කරන්න"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5da7467..9dbb232 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Chýba číslo hlasovej schránky"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM karte nie je uložené žiadne číslo hlasovej schránky."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Pridať číslo"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Chcete zmeniť predvolenú aplikáciu vytáčania?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Chcete použiť aplikáciu <xliff:g id="NEW_APP">%1$s</xliff:g> namiesto aplikácie <xliff:g id="CURRENT_APP">%2$s</xliff:g> ako predvolenú aplikáciu vytáčania?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Chcete použiť aplikáciu <xliff:g id="NEW_APP">%s</xliff:g> ako predvolenú aplikáciu vytáčania?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Nastaviť <xliff:g id="NEW_APP">%s</xliff:g> ako predvolanú aplikáciu na telefonovanie?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Nastaviť ako predvolené"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Zrušiť"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> bude môcť uskutočňovať hovory a ovládať všetky aspekty hovorov. Ako predvolenú aplikáciu na telefonovanie by ste si mali nastaviť len aplikáciu, ktorej dôverujete."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokované čísla"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Z blokovaných čísel nebudete prijímať hovory ani textové správy."</string>
     <string name="block_number" msgid="1101252256321306179">"Pridať číslo"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 00a811b..b328c69 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Manjkajoča številka glasovne pošte"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Na kartici SIM ni shranjena številka glasovne pošte."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj številko"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Želite spremeniti privzeto aplikacijo za klicanje?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Želite <xliff:g id="NEW_APP">%1$s</xliff:g> uporabljati kot privzeto aplikacijo za klicanje namesto <xliff:g id="CURRENT_APP">%2$s</xliff:g>?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Želite <xliff:g id="NEW_APP">%s</xliff:g> uporabljati kot privzeto aplikacijo za klicanje?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Želite, da je <xliff:g id="NEW_APP">%s</xliff:g> privzeta aplikacija za klicanje?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Nastavi za privzeto"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Prekliči"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"V aplikaciji <xliff:g id="NEW_APP">%s</xliff:g> bo mogoče opravljati klice in nadzirati vse vidike klicev. Kot privzeto aplikacijo za klicanje nastavite samo aplikacije, ki jim zaupate."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blokirane številke"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Z blokiranih številk ne boste prejemali klicev ali sporočil SMS."</string>
     <string name="block_number" msgid="1101252256321306179">"Dodaj številko"</string>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index b13c2ab..00660d0 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Mungon numri i postës zanore"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Nuk ka numër të ruajtur në kartën SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Shto numër"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Të ndryshohet apl. parazgjedhur i formuesit të numrave?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Të përdoret <xliff:g id="NEW_APP">%1$s</xliff:g> në vend të <xliff:g id="CURRENT_APP">%2$s</xliff:g> si aplikacioni i parazgjedhur i formuesit të numrave?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Të përdoret <xliff:g id="NEW_APP">%s</xliff:g> si aplikacioni i parazgjedhur i formuesit të numrave?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Të bëhet <xliff:g id="NEW_APP">%s</xliff:g> aplikacioni yt i parazgjedhur në telefon?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Vendos të parazgjedhurën"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Anulo"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> do të mund të bëjë dhe kontrollojë të gjitha aspektet e telefonatave. Vetëm aplikacionet të cilave u beson duhet të caktohen si aplikacioni Telefon i parazgjedhur."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Numrat e bllokuar"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nuk do të marrësh telefonata ose mesazhe me tekst nga numrat e bllokuar."</string>
     <string name="block_number" msgid="1101252256321306179">"Shto një numër"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 1fd28f2..23c2441 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Желите ли да <xliff:g id="NEW_APP">%s</xliff:g> постане подразумевана апликација Телефон?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Постави као подразумевано"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Откажи"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> ће моћи да упућује позиве и контролише све њихове аспекте. Апликацију подесите као подразумевану за телефонирање само ако је сматрате поузданом."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Блокирани бројеви"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Нећете примати позиве ни SMS-ове са блокираних бројева."</string>
     <string name="block_number" msgid="1101252256321306179">"Додај број"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index ac22da8..1ecd70d 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nummer till röstbrevlåda saknas"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Det finns inget nummer till röstbrevlådan sparat på SIM-kortet."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Lägg till nummer"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Vill du byta standardapp för uppringning?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Vill du använda <xliff:g id="NEW_APP">%1$s</xliff:g> i stället för <xliff:g id="CURRENT_APP">%2$s</xliff:g> som standardapp för uppringning?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Vill du använda <xliff:g id="NEW_APP">%s</xliff:g> som standardapp för uppringning?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Gör <xliff:g id="NEW_APP">%s</xliff:g> till standardtelefonapp?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Ange standard"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Avbryt"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> kan ringa och styra allt omkring samtal. Endast appar du litar på bör ställas in som standardtelefonapp."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Blockerade nummer"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Du kommer inte ta emot samtal eller sms från blockerade nummer."</string>
     <string name="block_number" msgid="1101252256321306179">"Lägg till ett telefonnummer"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 58d8e24..ce01517 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nambari ya sauti inayokosekana"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Hakuna nambari ya ujumbe wa sauti iliyohifadhiwa katika SIM kadi."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Ongeza nambari"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Ungependa kubadilisha programu chaguo-msingi ya simu?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Ungependa kutumia <xliff:g id="NEW_APP">%1$s</xliff:g> badala ya <xliff:g id="CURRENT_APP">%2$s</xliff:g> kama programu ya chaguo-msingi ya kupigia simu?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Ungependa kutumia <xliff:g id="NEW_APP">%s</xliff:g> kama programu ya chaguo-msingi ya kupigia simu?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Unataka kufanya <xliff:g id="NEW_APP">%s</xliff:g> iwe programu chaguo-msingi ya simu?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Fanya iwe Chaguo-Msingi"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Ghairi"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> itaweza kupiga simu na kudhibiti kila kipengele cha simu. Unastahili kuweka programu unazoziamini tu kama programu chaguo-msingi ya kupiga simu."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Nambari zilizozuiwa"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Hutapokea simu au SMS kutoka kwa nambari zilizozuiwa."</string>
     <string name="block_number" msgid="1101252256321306179">"Ongeza nambari"</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index b68a98f..e39a199 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"குரலஞ்சல் எண் இல்லை"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"சிம் கார்டில் குரலஞ்சலுக்கான எண் எதுவும் சேமிக்கப்படவில்லை."</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g>ஐ இயல்புநிலை ஃபோன் பயன்பாடாக அமைக்கவா?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"இயல்புநிலையாக அமை"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ரத்துசெய்"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"அழைப்புகளின் எல்லா அம்சங்களையும் <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>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index e6d8156..09bc4cf 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"వాయిస్ మెయిల్ నంబర్ లేదు"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"సిమ్ కార్డులో వాయిస్ మెయిల్ నంబర్ ఏదీ నిల్వ చేయబడలేదు."</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="CURRENT_APP">%2$s</xliff:g> బదులు <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g>ని మీ డిఫాల్ట్ ఫోన్ అనువర్తనంగా చేయాలా?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"డిఫాల్ట్‌గా సెట్ చేయండి"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"రద్దు చేయి"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 5a7cf4f..2acead3 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"ไม่มีหมายเลขข้อความเสียง"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"ไม่มีหมายเลขข้อความเสียงจัดเก็บอยู่ในซิมการ์ด"</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="change_default_dialer_dialog_title" msgid="9101655962941740507">"ต้องการตั้งค่าให้ <xliff:g id="NEW_APP">%s</xliff:g> เป็นแอปโทรศัพท์เริ่มต้นหรือไม่"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ตั้งเป็นค่าเริ่มต้น"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"ยกเลิก"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index b658c36..b711f07 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Nawawala ang numero ng voicemail"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Walang nakaimbak na numero ng voicemail sa SIM card."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Magdagdag ng numero"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Baguhin ang iyong default na Dialer app?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Gamitin ang <xliff:g id="NEW_APP">%1$s</xliff:g> sa halip na <xliff:g id="CURRENT_APP">%2$s</xliff:g> bilang default na dialer app mo?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Gamitin ang <xliff:g id="NEW_APP">%s</xliff:g> bilang default na dialer app mo?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Gawing iyong default na app na Telepono ang <xliff:g id="NEW_APP">%s</xliff:g>?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Magtakda ng Default"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Kanselahin"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"Ang <xliff:g id="NEW_APP">%s</xliff:g> ay magagawang tumawag at kontrolin ang lahat ng aspeto ng tawag. Mga app na pinagkakatiwalaan mo lang ang dapat itakda bilang default na app na Telepono."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Mga naka-block na numero"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Hindi ka makakatanggap ng mga tawag o mga text mula sa mga naka-block na numero."</string>
     <string name="block_number" msgid="1101252256321306179">"Magdagdag ng numero"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 229cf0f..5c20656 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Eksik sesli mesaj numarası"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartta depolanan sesli mesaj numarası yok."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Numara ekle"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Varsayılan Numara Çeviri uygulaması değiştirilsin mi?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Varsayılan numara çevirici uygulamanız olarak <xliff:g id="CURRENT_APP">%2$s</xliff:g> yerine <xliff:g id="NEW_APP">%1$s</xliff:g> kullanılsın mı?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Varsayılan numara çevirici uygulamanız olarak <xliff:g id="NEW_APP">%s</xliff:g> kullanılsın mı?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> varsayılan Telefon uygulamanız yapılsın mı?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Varsayılan Uygulamayı Ayarla"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"İptal"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> uygulaması üzerinden çağrı yapabilecek ve çağrıları her yönüyle kontrol edebileceksiniz. Yalnızca güvendiğiniz uygulamalar varsayılan Telefon uygulaması olarak ayarlanmalıdır."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Engellenen numaralar"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Engellenen numaralardan gelen çağrıları veya kısa mesajları almazsınız."</string>
     <string name="block_number" msgid="1101252256321306179">"Numara ekle"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 384413e..036ea40 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"Зробити <xliff:g id="NEW_APP">%s</xliff:g> додатком для викликів за умовчанням?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Установити за умовчанням"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Скасувати"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"За допомогою додатка <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>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index f880d83..b917066 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -45,9 +45,10 @@
     <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="CURRENT_APP">%2$s</xliff:g> کی بجائے <xliff:g id="NEW_APP">%1$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="change_default_dialer_dialog_title" msgid="9101655962941740507">"<xliff:g id="NEW_APP">%s</xliff:g> کو اپنی ڈیفالٹ فون ایپ بنائیں؟"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"ڈیفالٹ سیٹ کریں"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"منسوخ کریں"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index ecfbf3b..8e8ab26 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Ovozli pochta raqami ko‘rsatilmagan"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartada birorta ham ovozli pochta raqami yo‘q."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Raqam qo‘shish"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Birlamchi raqam terish ilovasi o‘zgartirilsinmi?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Raqam terish uchun birlamchi ilova sifatida <xliff:g id="CURRENT_APP">%2$s</xliff:g> o‘rniga <xliff:g id="NEW_APP">%1$s</xliff:g> ilovasi tanlansinmi?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g> raqam terish uchun birlamchi ilova sifatida tanlansinmi?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Qo‘ng‘iroq. uchun <xliff:g id="NEW_APP">%s</xliff:g> asosiy ilova sifatida o‘rnatilsinmi?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Asosiy ilova sifatida o‘rnatish"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Bekor qilish"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> ilovasi qo‘ng‘iroq qilishga yodam beradi va qo‘ng‘iroqlarga tegishli boshqa barcha parametrlarni boshqaradi. Qo‘ng‘iroqlar uchun faqat ishonarli ilovani asosiy ilova qilib o‘rnatish lozim."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Bloklangan raqamlar"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Bloklangan raqamlardan keladigan qo‘ng‘iroq yoki SMS xabarlar qabul qilinmaydi."</string>
     <string name="block_number" msgid="1101252256321306179">"Raqam qo‘shish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index ec10471..2308246 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Thiếu số thư thoại"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Không có số thư thoại nào được lưu trữ trên thẻ SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Thêm số điện thoại"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Thay đổi ứng dụng Trình quay số mặc định?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Sử dụng <xliff:g id="NEW_APP">%1$s</xliff:g> làm ứng dụng trình quay số mặc định của bạn thay vì <xliff:g id="CURRENT_APP">%2$s</xliff:g>?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Sử dụng <xliff:g id="NEW_APP">%s</xliff:g> làm ứng dụng trình quay số mặc định của bạn?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Đặt <xliff:g id="NEW_APP">%s</xliff:g> làm ứng dụng Điện thoại mặc định của bạn?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Đặt làm mặc định"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Hủy"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> sẽ có thể đặt và kiểm soát mọi khía cạnh của cuộc gọi. Chỉ nên đặt những ứng dụng mà bạn tin cậy làm ứng dụng Điện thoại mặc định."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Số bị chặn"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Bạn sẽ không nhận được cuộc gọi hoặc tin nhắn từ các số bị chặn."</string>
     <string name="block_number" msgid="1101252256321306179">"Thêm số điện thoại"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index a324513..13be3c0 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -25,7 +25,7 @@
     <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="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>
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"要将 <xliff:g id="NEW_APP">%s</xliff:g> 设为默认电话应用吗?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"设为默认电话应用"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"取消"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<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>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index b9cc761..072b723 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"要將<xliff:g id="NEW_APP">%s</xliff:g>設為預設電話應用程式嗎?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"設為預設"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"取消"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"「<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>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 4231e1f..faf0328 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -45,9 +45,10 @@
     <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="change_default_dialer_dialog_title" msgid="9101655962941740507">"確定要將 <xliff:g id="NEW_APP">%s</xliff:g> 設為預設電話應用程式嗎?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"設為預設電話應用程式"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"取消"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"這樣一來,<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>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 00c7e14..b65700c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -45,9 +45,10 @@
     <string name="no_vm_number" msgid="4164780423805688336">"Inombolo engekho yomyalezo wezwi"</string>
     <string name="no_vm_number_msg" msgid="1300729501030053828">"Ayikho inombolo yomlayezo wezwi egcinwe ekhadini le-SIM."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"Engeza inombolo"</string>
-    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Guqula uhlelo lwakho lokusebenza oluzenzakalelayo lokudayela?"</string>
-    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Sebenzisa i-<xliff:g id="NEW_APP">%1$s</xliff:g> esikhundleni se-<xliff:g id="CURRENT_APP">%2$s</xliff:g> njengohlelo lwakho lokusebenza oluzenzakalelayo lokokudayela?"</string>
-    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Sebenzisa i-<xliff:g id="NEW_APP">%s</xliff:g> njengohlelo lwakho lokusebenza oluzenzakalelayo lokokudayela?"</string>
+    <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Yenza i-<xliff:g id="NEW_APP">%s</xliff:g> uhlelo lwakho lwefoni oluzenzakalelayo?"</string>
+    <string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Setha okuzenzakalelayo"</string>
+    <string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Khansela"</string>
+    <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"<xliff:g id="NEW_APP">%s</xliff:g> Uzokwazi ukubeka nokulawula zonke izinto zamakholi. Izinhlelo zokusebenza kuphela ozithembayo ezingasethwa njengohlelo lokusebenza oluzenzakalelayo lefoni."</string>
     <string name="blocked_numbers" msgid="2751843139572970579">"Izinombolo ezivinjiwe"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Ngeke uthole amakholi noma imibhalo kusuka kuzinombolo ezivinjelwe."</string>
     <string name="block_number" msgid="1101252256321306179">"Engeza inombolo"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 75b8352..b0bcd3c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -15,11 +15,11 @@
   -->
 
 <resources>
-    <color name="theme_color">#0288d1</color>
+    <color name="theme_color">#2a56c6</color>
 
     <color name="dialer_settings_actionbar_text_color">#ffffff</color>
     <color name="dialer_settings_actionbar_background_color">@color/theme_color</color>
-    <color name="dialer_settings_color_dark">#0277bd</color>
+    <color name="dialer_settings_color_dark">#1c3aa9</color>
 
     <color name="blocked_numbers_divider_color">#e5e5e5</color>
     <color name="blocked_numbers_butter_bar_color">#f5f5f5</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 01e7052..1fdcf2d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -109,12 +109,13 @@
 
     <!-- Title of dialog used to comfirm whether the user intends to change the default dialer
             application [CHAR LIMIT=55]-->
-    <string name="change_default_dialer_dialog_title">Change default Dialer app?</string>
-    <!-- Text in dialog used to confirm whether or not the user intends to change the default dialer, if a different default dialer has been previously set. -->
-    <string name="change_default_dialer_with_previous_app_set_text">Use <xliff:g id="new_app">%1$s</xliff:g> instead of <xliff:g id="current_app">%2$s</xliff:g> as your default dialer app?</string>
-    <!-- Text in dialog used to confirm whether or not the user intends to change the default dialer, if a different default dialer has not been previously set. -->
-    <string name="change_default_dialer_no_previous_app_set_text">Use <xliff:g id="new_app">%s</xliff:g> as your default dialer app?</string>
-
+    <string name="change_default_dialer_dialog_title">Make <xliff:g id="new_app">%s</xliff:g> your default Phone app?</string>
+    <!-- Confirmation text that a user taps on to change the Default Phone App-->
+    <string name="change_default_dialer_dialog_affirmative">Set Default</string>
+    <!-- Cancel text that a user taps on to not change the Default Phone App-->
+    <string name="change_default_dialer_dialog_negative">Cancel</string>
+    <!-- Warning message indicating what may happen if a user allows a 3rd party app to become the default dialer.-->
+    <string name="change_default_dialer_warning_message"><xliff:g id="new_app">%s</xliff:g> will be able to place and control all aspects of calls. Only apps you trust should be set as the default Phone app.</string>
 
     <!-- Blocked numbers -->
     <string name="blocked_numbers">Blocked numbers</string>
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 1d76dfc..4456734 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -16,45 +16,172 @@
 
 package com.android.server.telecom;
 
-import android.os.Parcelable;
-import android.telecom.ParcelableCallAnalytics;
+import android.telecom.Connection;
 import android.telecom.DisconnectCause;
+import android.telecom.ParcelableCallAnalytics;
+import android.telecom.TelecomAnalytics;
+import android.util.Base64;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.CallerInfo;
 import com.android.internal.util.IndentingPrintWriter;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
+
+import static android.telecom.ParcelableCallAnalytics.AnalyticsEvent;
+import static android.telecom.TelecomAnalytics.SessionTiming;
 
 /**
  * A class that collects and stores data on how calls are being made, in order to
  * aggregate these into useful statistics.
  */
 public class Analytics {
-   public static class CallInfo {
-        void setCallStartTime(long startTime) {
+    public static final String ANALYTICS_DUMPSYS_ARG = "analytics";
+    private static final String CLEAR_ANALYTICS_ARG = "clear";
+
+    public static final Map<String, Integer> sLogEventToAnalyticsEvent =
+            new HashMap<String, Integer>() {{
+                put(Log.Events.SET_SELECT_PHONE_ACCOUNT, AnalyticsEvent.SET_SELECT_PHONE_ACCOUNT);
+                put(Log.Events.REQUEST_HOLD, AnalyticsEvent.REQUEST_HOLD);
+                put(Log.Events.REQUEST_UNHOLD, AnalyticsEvent.REQUEST_UNHOLD);
+                put(Log.Events.SWAP, AnalyticsEvent.SWAP);
+                put(Log.Events.SKIP_RINGING, AnalyticsEvent.SKIP_RINGING);
+                put(Log.Events.CONFERENCE_WITH, AnalyticsEvent.CONFERENCE_WITH);
+                put(Log.Events.SPLIT_FROM_CONFERENCE, AnalyticsEvent.SPLIT_CONFERENCE);
+                put(Log.Events.SET_PARENT, AnalyticsEvent.SET_PARENT);
+                put(Log.Events.MUTE, AnalyticsEvent.MUTE);
+                put(Log.Events.UNMUTE, AnalyticsEvent.UNMUTE);
+                put(Log.Events.AUDIO_ROUTE_BT, AnalyticsEvent.AUDIO_ROUTE_BT);
+                put(Log.Events.AUDIO_ROUTE_EARPIECE, AnalyticsEvent.AUDIO_ROUTE_EARPIECE);
+                put(Log.Events.AUDIO_ROUTE_HEADSET, AnalyticsEvent.AUDIO_ROUTE_HEADSET);
+                put(Log.Events.AUDIO_ROUTE_SPEAKER, AnalyticsEvent.AUDIO_ROUTE_SPEAKER);
+                put(Log.Events.SILENCE, AnalyticsEvent.SILENCE);
+                put(Log.Events.SCREENING_COMPLETED, AnalyticsEvent.SCREENING_COMPLETED);
+                put(Log.Events.BLOCK_CHECK_FINISHED, AnalyticsEvent.BLOCK_CHECK_FINISHED);
+                put(Log.Events.DIRECT_TO_VM_FINISHED, AnalyticsEvent.DIRECT_TO_VM_FINISHED);
+                put(Log.Events.REMOTELY_HELD, AnalyticsEvent.REMOTELY_HELD);
+                put(Log.Events.REMOTELY_UNHELD, AnalyticsEvent.REMOTELY_UNHELD);
+                put(Log.Events.REQUEST_PULL, AnalyticsEvent.REQUEST_PULL);
+                put(Log.Events.REQUEST_ACCEPT, AnalyticsEvent.REQUEST_ACCEPT);
+                put(Log.Events.REQUEST_REJECT, AnalyticsEvent.REQUEST_REJECT);
+                put(Log.Events.SET_ACTIVE, AnalyticsEvent.SET_ACTIVE);
+                put(Log.Events.SET_DISCONNECTED, AnalyticsEvent.SET_DISCONNECTED);
+                put(Log.Events.SET_HOLD, AnalyticsEvent.SET_HOLD);
+                put(Log.Events.SET_DIALING, AnalyticsEvent.SET_DIALING);
+                put(Log.Events.START_CONNECTION, AnalyticsEvent.START_CONNECTION);
+                put(Log.Events.BIND_CS, AnalyticsEvent.BIND_CS);
+                put(Log.Events.CS_BOUND, AnalyticsEvent.CS_BOUND);
+                put(Log.Events.SCREENING_SENT, AnalyticsEvent.SCREENING_SENT);
+                put(Log.Events.DIRECT_TO_VM_INITIATED, AnalyticsEvent.DIRECT_TO_VM_INITIATED);
+                put(Log.Events.BLOCK_CHECK_INITIATED, AnalyticsEvent.BLOCK_CHECK_INITIATED);
+                put(Log.Events.FILTERING_INITIATED, AnalyticsEvent.FILTERING_INITIATED);
+                put(Log.Events.FILTERING_COMPLETED, AnalyticsEvent.FILTERING_COMPLETED);
+                put(Log.Events.FILTERING_TIMED_OUT, AnalyticsEvent.FILTERING_TIMED_OUT);
+            }};
+
+    public static final Map<String, Integer> sLogSessionToSessionId =
+            new HashMap<String, Integer> () {{
+                put(Log.Sessions.ICA_ANSWER_CALL, SessionTiming.ICA_ANSWER_CALL);
+                put(Log.Sessions.ICA_REJECT_CALL, SessionTiming.ICA_REJECT_CALL);
+                put(Log.Sessions.ICA_DISCONNECT_CALL, SessionTiming.ICA_DISCONNECT_CALL);
+                put(Log.Sessions.ICA_HOLD_CALL, SessionTiming.ICA_HOLD_CALL);
+                put(Log.Sessions.ICA_UNHOLD_CALL, SessionTiming.ICA_UNHOLD_CALL);
+                put(Log.Sessions.ICA_MUTE, SessionTiming.ICA_MUTE);
+                put(Log.Sessions.ICA_SET_AUDIO_ROUTE, SessionTiming.ICA_SET_AUDIO_ROUTE);
+                put(Log.Sessions.ICA_CONFERENCE, SessionTiming.ICA_CONFERENCE);
+                put(Log.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
+                        SessionTiming.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
+                put(Log.Sessions.CSW_SET_ACTIVE, SessionTiming.CSW_SET_ACTIVE);
+                put(Log.Sessions.CSW_SET_RINGING, SessionTiming.CSW_SET_RINGING);
+                put(Log.Sessions.CSW_SET_DIALING, SessionTiming.CSW_SET_DIALING);
+                put(Log.Sessions.CSW_SET_DISCONNECTED, SessionTiming.CSW_SET_DISCONNECTED);
+                put(Log.Sessions.CSW_SET_ON_HOLD, SessionTiming.CSW_SET_ON_HOLD);
+                put(Log.Sessions.CSW_REMOVE_CALL, SessionTiming.CSW_REMOVE_CALL);
+                put(Log.Sessions.CSW_SET_IS_CONFERENCED, SessionTiming.CSW_SET_IS_CONFERENCED);
+                put(Log.Sessions.CSW_ADD_CONFERENCE_CALL, SessionTiming.CSW_ADD_CONFERENCE_CALL);
+
+            }};
+
+    public static final Map<String, Integer> sLogEventTimingToAnalyticsEventTiming =
+            new HashMap<String, Integer>() {{
+                put(Log.Events.Timings.ACCEPT_TIMING,
+                        ParcelableCallAnalytics.EventTiming.ACCEPT_TIMING);
+                put(Log.Events.Timings.REJECT_TIMING,
+                        ParcelableCallAnalytics.EventTiming.REJECT_TIMING);
+                put(Log.Events.Timings.DISCONNECT_TIMING,
+                        ParcelableCallAnalytics.EventTiming.DISCONNECT_TIMING);
+                put(Log.Events.Timings.HOLD_TIMING,
+                        ParcelableCallAnalytics.EventTiming.HOLD_TIMING);
+                put(Log.Events.Timings.UNHOLD_TIMING,
+                        ParcelableCallAnalytics.EventTiming.UNHOLD_TIMING);
+                put(Log.Events.Timings.OUTGOING_TIME_TO_DIALING_TIMING,
+                        ParcelableCallAnalytics.EventTiming.OUTGOING_TIME_TO_DIALING_TIMING);
+                put(Log.Events.Timings.BIND_CS_TIMING,
+                        ParcelableCallAnalytics.EventTiming.BIND_CS_TIMING);
+                put(Log.Events.Timings.SCREENING_COMPLETED_TIMING,
+                        ParcelableCallAnalytics.EventTiming.SCREENING_COMPLETED_TIMING);
+                put(Log.Events.Timings.DIRECT_TO_VM_FINISHED_TIMING,
+                        ParcelableCallAnalytics.EventTiming.DIRECT_TO_VM_FINISHED_TIMING);
+                put(Log.Events.Timings.BLOCK_CHECK_FINISHED_TIMING,
+                        ParcelableCallAnalytics.EventTiming.BLOCK_CHECK_FINISHED_TIMING);
+                put(Log.Events.Timings.FILTERING_COMPLETED_TIMING,
+                        ParcelableCallAnalytics.EventTiming.FILTERING_COMPLETED_TIMING);
+                put(Log.Events.Timings.FILTERING_TIMED_OUT_TIMING,
+                        ParcelableCallAnalytics.EventTiming.FILTERING_TIMED_OUT_TIMING);
+            }};
+
+    public static final Map<Integer, String> sSessionIdToLogSession = new HashMap<>();
+    static {
+        for (Map.Entry<String, Integer> e : sLogSessionToSessionId.entrySet()) {
+            sSessionIdToLogSession.put(e.getValue(), e.getKey());
+        }
+    }
+
+    public static class CallInfo {
+        public void setCallStartTime(long startTime) {
         }
 
-        void setCallEndTime(long endTime) {
+        public void setCallEndTime(long endTime) {
         }
 
-        void setCallIsAdditional(boolean isAdditional) {
+        public void setCallIsAdditional(boolean isAdditional) {
         }
 
-        void setCallIsInterrupted(boolean isInterrupted) {
+        public void setCallIsInterrupted(boolean isInterrupted) {
         }
 
-        void setCallDisconnectCause(DisconnectCause disconnectCause) {
+        public void setCallDisconnectCause(DisconnectCause disconnectCause) {
         }
 
-        void addCallTechnology(int callTechnology) {
+        public void addCallTechnology(int callTechnology) {
         }
 
-        void setCreatedFromExistingConnection(boolean createdFromExistingConnection) {
+        public void setCreatedFromExistingConnection(boolean createdFromExistingConnection) {
         }
 
-        void setCallConnectionService(String connectionServiceName) {
+        public void setCallConnectionService(String connectionServiceName) {
+        }
+
+        public void setCallEvents(Log.CallEventRecord records) {
+        }
+
+        public void setCallIsVideo(boolean isVideo) {
+        }
+
+        public void addVideoEvent(int eventId, int videoState) {
+        }
+
+        public void addInCallService(String serviceName, int type) {
+        }
+
+        public void addCallProperties(int properties) {
         }
     }
 
@@ -83,6 +210,15 @@
         public String connectionService;
         public boolean isEmergency = false;
 
+        public Log.CallEventRecord callEvents;
+
+        public boolean isVideo = false;
+        public List<TelecomLogClass.VideoEvent> videoEvents;
+        public List<TelecomLogClass.InCallServiceInfo> inCallServiceInfos;
+        public int callProperties = 0;
+
+        private long mTimeOfLastVideoEvent = -1;
+
         CallInfoImpl(String callId, int callDirection) {
             this.callId = callId;
             startTime = 0;
@@ -90,6 +226,8 @@
             this.callDirection = callDirection;
             callTechnologies = 0;
             connectionService = "";
+            videoEvents = new LinkedList<>();
+            inCallServiceInfos = new LinkedList<>();
         }
 
         CallInfoImpl(CallInfoImpl other) {
@@ -103,6 +241,10 @@
             this.createdFromExistingConnection = other.createdFromExistingConnection;
             this.connectionService = other.connectionService;
             this.isEmergency = other.isEmergency;
+            this.callEvents = other.callEvents;
+            this.isVideo = other.isVideo;
+            this.videoEvents = other.videoEvents;
+            this.callProperties = other.callProperties;
 
             if (other.callTerminationReason != null) {
                 this.callTerminationReason = new DisconnectCause(
@@ -167,6 +309,45 @@
         }
 
         @Override
+        public void setCallEvents(Log.CallEventRecord records) {
+            this.callEvents = records;
+        }
+
+        @Override
+        public void setCallIsVideo(boolean isVideo) {
+            this.isVideo = isVideo;
+        }
+
+        @Override
+        public void addVideoEvent(int eventId, int videoState) {
+            long timeSinceLastEvent;
+            long currentTime = System.currentTimeMillis();
+            if (mTimeOfLastVideoEvent < 0) {
+                timeSinceLastEvent = -1;
+            } else {
+                timeSinceLastEvent = roundToOneSigFig(currentTime - mTimeOfLastVideoEvent);
+            }
+            mTimeOfLastVideoEvent = currentTime;
+
+            videoEvents.add(new TelecomLogClass.VideoEvent()
+                    .setEventName(eventId)
+                    .setTimeSinceLastEventMillis(timeSinceLastEvent)
+                    .setVideoState(videoState));
+        }
+
+        @Override
+        public void addInCallService(String serviceName, int type) {
+            inCallServiceInfos.add(new TelecomLogClass.InCallServiceInfo()
+                    .setInCallServiceName(serviceName)
+                    .setInCallServiceType(type));
+        }
+
+        @Override
+        public void addCallProperties(int properties) {
+            this.callProperties |= properties;
+        }
+
+        @Override
         public String toString() {
             return "{\n"
                     + "    startTime: " + startTime + '\n'
@@ -177,28 +358,93 @@
                     + "    callTechnologies: " + getCallTechnologiesAsString() + '\n'
                     + "    callTerminationReason: " + getCallDisconnectReasonString() + '\n'
                     + "    connectionService: " + connectionService + '\n'
+                    + "    isVideoCall: " + isVideo + '\n'
+                    + "    inCallServices: " + getInCallServicesString() + '\n'
+                    + "    callProperties: " + Connection.propertiesToStringShort(callProperties)
+                    + '\n'
                     + "}\n";
         }
 
         public ParcelableCallAnalytics toParcelableAnalytics() {
+            TelecomLogClass.CallLog analyticsProto = toProto();
+            List<ParcelableCallAnalytics.AnalyticsEvent> events =
+                    Arrays.stream(analyticsProto.callEvents)
+                    .map(callEventProto -> new ParcelableCallAnalytics.AnalyticsEvent(
+                                callEventProto.getEventName(),
+                                callEventProto.getTimeSinceLastEventMillis())
+                    ).collect(Collectors.toList());
+
+            List<ParcelableCallAnalytics.EventTiming> timings =
+                    Arrays.stream(analyticsProto.callTimings)
+                    .map(callTimingProto -> new ParcelableCallAnalytics.EventTiming(
+                            callTimingProto.getTimingName(),
+                            callTimingProto.getTimeMillis())
+                    ).collect(Collectors.toList());
+
+            ParcelableCallAnalytics result = new ParcelableCallAnalytics(
+                    // rounds down to nearest 5 minute mark
+                    analyticsProto.getStartTime5Min(),
+                    analyticsProto.getCallDurationMillis(),
+                    analyticsProto.getType(),
+                    analyticsProto.getIsAdditionalCall(),
+                    analyticsProto.getIsInterrupted(),
+                    analyticsProto.getCallTechnologies(),
+                    analyticsProto.getCallTerminationCode(),
+                    analyticsProto.getIsEmergencyCall(),
+                    analyticsProto.connectionService[0],
+                    analyticsProto.getIsCreatedFromExistingConnection(),
+                    events,
+                    timings);
+
+            result.setIsVideoCall(analyticsProto.getIsVideoCall());
+            result.setVideoEvents(Arrays.stream(analyticsProto.videoEvents)
+                    .map(videoEventProto -> new ParcelableCallAnalytics.VideoEvent(
+                            videoEventProto.getEventName(),
+                            videoEventProto.getTimeSinceLastEventMillis(),
+                            videoEventProto.getVideoState())
+                    ).collect(Collectors.toList()));
+
+            return result;
+        }
+
+        public TelecomLogClass.CallLog toProto() {
+            TelecomLogClass.CallLog result = new TelecomLogClass.CallLog();
+            result.setStartTime5Min(
+                    startTime - startTime % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
+
             // Rounds up to the nearest second.
             long callDuration = (endTime == 0 || startTime == 0) ? 0 : endTime - startTime;
             callDuration += (callDuration % MILLIS_IN_1_SECOND == 0) ?
                     0 : (MILLIS_IN_1_SECOND - callDuration % MILLIS_IN_1_SECOND);
-            return new ParcelableCallAnalytics(
-                    // rounds down to nearest 5 minute mark
-                    startTime - startTime % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES,
-                    callDuration,
-                    callDirection,
-                    isAdditionalCall,
-                    isInterrupted,
-                    callTechnologies,
-                    callTerminationReason == null ?
-                            ParcelableCallAnalytics.STILL_CONNECTED :
-                            callTerminationReason.getCode(),
-                    isEmergency,
-                    connectionService,
-                    createdFromExistingConnection);
+            result.setCallDurationMillis(callDuration);
+
+            result.setType(callDirection)
+                    .setIsAdditionalCall(isAdditionalCall)
+                    .setIsInterrupted(isInterrupted)
+                    .setCallTechnologies(callTechnologies)
+                    .setCallTerminationCode(
+                            callTerminationReason == null ?
+                                    ParcelableCallAnalytics.STILL_CONNECTED :
+                                    callTerminationReason.getCode())
+                    .setIsEmergencyCall(isEmergency)
+                    .setIsCreatedFromExistingConnection(createdFromExistingConnection)
+                    .setIsEmergencyCall(isEmergency)
+                    .setIsVideoCall(isVideo)
+                    .setConnectionProperties(callProperties);
+
+            result.connectionService = new String[] {connectionService};
+            if (callEvents != null) {
+                result.callEvents = convertLogEventsToProtoEvents(callEvents.getEvents());
+                result.callTimings = callEvents.extractEventTimings().stream()
+                        .map(Analytics::logEventTimingToProtoEventTiming)
+                        .toArray(TelecomLogClass.EventTimingEntry[]::new);
+            }
+            result.videoEvents =
+                    videoEvents.toArray(new TelecomLogClass.VideoEvent[videoEvents.size()]);
+            result.inCallServices = inCallServiceInfos.toArray(
+                    new TelecomLogClass.InCallServiceInfo[inCallServiceInfos.size()]);
+
+            return result;
         }
 
         private String getCallDirectionString() {
@@ -233,6 +479,21 @@
                 return "NOT SET";
             }
         }
+
+        private String getInCallServicesString() {
+            StringBuilder s = new StringBuilder();
+            s.append("[\n");
+            for (TelecomLogClass.InCallServiceInfo service : inCallServiceInfos) {
+                s.append("    ");
+                s.append("name: ");
+                s.append(service.getInCallServiceName());
+                s.append(" type: ");
+                s.append(service.getInCallServiceType());
+                s.append("\n");
+            }
+            s.append("]");
+            return s.toString();
+        }
     }
     public static final String TAG = "TelecomAnalytics";
 
@@ -248,10 +509,30 @@
     public static final int SIP_PHONE = ParcelableCallAnalytics.SIP_PHONE;
     public static final int THIRD_PARTY_PHONE = ParcelableCallAnalytics.THIRD_PARTY_PHONE;
 
+    // Constants for video events
+    public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST =
+            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_REQUEST;
+    public static final int SEND_LOCAL_SESSION_MODIFY_RESPONSE =
+            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_RESPONSE;
+    public static final int RECEIVE_REMOTE_SESSION_MODIFY_REQUEST =
+            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST;
+    public static final int RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE =
+            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE;
+
     public static final long MILLIS_IN_1_SECOND = ParcelableCallAnalytics.MILLIS_IN_1_SECOND;
 
     private static final Object sLock = new Object(); // Coarse lock for all of analytics
     private static final Map<String, CallInfoImpl> sCallIdToInfo = new HashMap<>();
+    private static final List<SessionTiming> sSessionTimings = new LinkedList<>();
+
+    public static void addSessionTiming(String sessionName, long time) {
+        if (sLogSessionToSessionId.containsKey(sessionName)) {
+            synchronized (sLock) {
+                sSessionTimings.add(new SessionTiming(sLogSessionToSessionId.get(sessionName),
+                        time));
+            }
+        }
+    }
 
     public static CallInfo initiateCallAnalytics(String callId, int direction) {
         Log.d(TAG, "Starting analytics for call " + callId);
@@ -262,26 +543,77 @@
         return callInfo;
     }
 
-    public static ParcelableCallAnalytics[] dumpToParcelableAnalytics() {
-        ParcelableCallAnalytics[] result;
+    public static TelecomAnalytics dumpToParcelableAnalytics() {
+        List<ParcelableCallAnalytics> calls = new LinkedList<>();
+        List<SessionTiming> sessionTimings = new LinkedList<>();
         synchronized (sLock) {
-            result = new ParcelableCallAnalytics[sCallIdToInfo.size()];
-            int idx = 0;
-            for (CallInfoImpl entry : sCallIdToInfo.values()) {
-                result[idx] = entry.toParcelableAnalytics();
-                idx++;
-            }
+            calls.addAll(sCallIdToInfo.values().stream()
+                    .map(CallInfoImpl::toParcelableAnalytics)
+                    .collect(Collectors.toList()));
+            sessionTimings.addAll(sSessionTimings);
             sCallIdToInfo.clear();
+            sSessionTimings.clear();
         }
-        return result;
+        return new TelecomAnalytics(sessionTimings, calls);
+    }
+
+    public static void dumpToEncodedProto(PrintWriter pw, String[] args) {
+        TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
+
+        synchronized (sLock) {
+            result.callLogs = sCallIdToInfo.values().stream()
+                    .map(CallInfoImpl::toProto)
+                    .toArray(TelecomLogClass.CallLog[]::new);
+            result.sessionTimings = sSessionTimings.stream()
+                    .map(timing -> new TelecomLogClass.LogSessionTiming()
+                            .setSessionEntryPoint(timing.getKey())
+                            .setTimeMillis(timing.getTime()))
+                    .toArray(TelecomLogClass.LogSessionTiming[]::new);
+            if (args.length > 1 && CLEAR_ANALYTICS_ARG.equals(args[1])) {
+                sCallIdToInfo.clear();
+                sSessionTimings.clear();
+            }
+        }
+        String encodedProto = Base64.encodeToString(
+                TelecomLogClass.TelecomLog.toByteArray(result), Base64.DEFAULT);
+        pw.write(encodedProto);
     }
 
     public static void dump(IndentingPrintWriter writer) {
         synchronized (sLock) {
-            for (Map.Entry<String, CallInfoImpl> entry : sCallIdToInfo.entrySet()) {
-                writer.printf("Call %s: ", entry.getKey());
-                writer.println(entry.getValue().toString());
+            int prefixLength = CallsManager.TELECOM_CALL_ID_PREFIX.length();
+            List<String> callIds = new ArrayList<>(sCallIdToInfo.keySet());
+            // Sort the analytics in increasing order of call IDs
+            try {
+                Collections.sort(callIds, (id1, id2) -> {
+                    int i1, i2;
+                    try {
+                        i1 = Integer.valueOf(id1.substring(prefixLength));
+                    } catch (NumberFormatException e) {
+                        i1 = Integer.MAX_VALUE;
+                    }
+
+                    try {
+                        i2 = Integer.valueOf(id2.substring(prefixLength));
+                    } catch (NumberFormatException e) {
+                        i2 = Integer.MAX_VALUE;
+                    }
+                    return i1 - i2;
+                });
+            } catch (IllegalArgumentException e) {
+                // do nothing, leave the list in a partially sorted state.
             }
+
+            for (String callId : callIds) {
+                writer.printf("Call %s: ", callId);
+                writer.println(sCallIdToInfo.get(callId).toString());
+            }
+
+            Map<Integer, Double> averageTimings = SessionTiming.averageTimings(sSessionTimings);
+            averageTimings.entrySet().stream()
+                    .filter(e -> sSessionIdToLogSession.containsKey(e.getKey()))
+                    .forEach(e -> writer.printf("%s: %.2f\n",
+                            sSessionIdToLogSession.get(e.getKey()), e.getValue()));
         }
     }
 
@@ -292,8 +624,9 @@
     }
 
     /**
-     * Returns a deep copy of callIdToInfo that's safe to read/write without synchronization
+     * Returns a copy of callIdToInfo. Use only for testing.
      */
+    @VisibleForTesting
     public static Map<String, CallInfoImpl> cloneData() {
         synchronized (sLock) {
             Map<String, CallInfoImpl> result = new HashMap<>(sCallIdToInfo.size());
@@ -303,4 +636,43 @@
             return result;
         }
     }
+
+    private static TelecomLogClass.Event[] convertLogEventsToProtoEvents(
+            List<Log.CallEvent> logEvents) {
+        long timeOfLastEvent = -1;
+        ArrayList<TelecomLogClass.Event> events = new ArrayList<>(logEvents.size());
+        for (Log.CallEvent logEvent : logEvents) {
+            if (sLogEventToAnalyticsEvent.containsKey(logEvent.eventId)) {
+                TelecomLogClass.Event event = new TelecomLogClass.Event();
+                event.setEventName(sLogEventToAnalyticsEvent.get(logEvent.eventId));
+                event.setTimeSinceLastEventMillis(roundToOneSigFig(
+                        timeOfLastEvent < 0 ? -1 : logEvent.time - timeOfLastEvent));
+                events.add(event);
+                timeOfLastEvent = logEvent.time;
+            }
+        }
+        return events.toArray(new TelecomLogClass.Event[events.size()]);
+    }
+
+    private static TelecomLogClass.EventTimingEntry logEventTimingToProtoEventTiming(
+            Log.CallEventRecord.EventTiming logEventTiming) {
+        int analyticsEventTimingName =
+                sLogEventTimingToAnalyticsEventTiming.containsKey(logEventTiming.name) ?
+                        sLogEventTimingToAnalyticsEventTiming.get(logEventTiming.name) :
+                        ParcelableCallAnalytics.EventTiming.INVALID;
+        return new TelecomLogClass.EventTimingEntry()
+                .setTimingName(analyticsEventTimingName)
+                .setTimeMillis(logEventTiming.time);
+    }
+
+    @VisibleForTesting
+    public static long roundToOneSigFig(long val)  {
+        if (val == 0) {
+            return val;
+        }
+        int logVal = (int) Math.floor(Math.log10(val < 0 ? -val : val));
+        double s = Math.pow(10, logVal);
+        double dec =  val / s;
+        return (long) (Math.round(dec) * s);
+    }
 }
diff --git a/src/com/android/server/telecom/BluetoothManager.java b/src/com/android/server/telecom/BluetoothManager.java
index 3819879..d31c69d 100644
--- a/src/com/android/server/telecom/BluetoothManager.java
+++ b/src/com/android/server/telecom/BluetoothManager.java
@@ -121,7 +121,7 @@
 
     private BluetoothHeadsetProxy mBluetoothHeadset;
     private long mBluetoothConnectionRequestTime;
-    private final Runnable mBluetoothConnectionTimeout = new Runnable("BM.cBA") {
+    private final Runnable mBluetoothConnectionTimeout = new Runnable("BM.cBA", null /*lock*/) {
         @Override
         public void loggedRun() {
             if (!isBluetoothAudioConnected()) {
@@ -132,7 +132,7 @@
         }
     };
 
-    private final Runnable mRetryConnectAudio = new Runnable("BM.rCA") {
+    private final Runnable mRetryConnectAudio = new Runnable("BM.rCA", null /*lock*/) {
         @Override
         public void loggedRun() {
             Log.i(this, "Retrying connecting to bluetooth audio.");
diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
index b6960d2..ee71cd4 100644
--- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
+++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
@@ -34,6 +34,7 @@
 import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -118,7 +119,7 @@
                     Log.i(TAG, "BT - answering call");
                     Call call = mCallsManager.getRingingCall();
                     if (call != null) {
-                        mCallsManager.answerCall(call, call.getVideoState());
+                        mCallsManager.answerCall(call, VideoProfile.STATE_AUDIO_ONLY);
                         return true;
                     }
                     return false;
@@ -338,6 +339,9 @@
         @Override
         public void onCallAdded(Call call) {
             Log.d(TAG, "onCallAdded");
+            if (call.isExternalCall()) {
+                return;
+            }
             if (isDsdaEnabled() && call.isConference() &&
                     (call.getChildCalls().size() == 0)) {
                 Log.d(TAG, "Ignore onCallAdded for new parent call" +
@@ -350,6 +354,9 @@
         @Override
         public void onCallRemoved(Call call) {
             Log.d(TAG, "onCallRemoved");
+            if (call.isExternalCall()) {
+                return;
+            }
             mClccIndexMap.remove(call);
             updateHeadsetWithCallState(false /* force */, call);
         }
@@ -374,6 +381,9 @@
         public void onCallStateChanged(Call call, int oldState, int newState) {
             Log.d(TAG, "onCallStateChanged, call: " + call + " oldState: " + oldState +
                     " newState: " + newState);
+            if (call.isExternalCall()) {
+                return;
+            }
             // If onCallStateChanged comes with oldState = newState when DSDA is enabled,
             // check if the call is on ActiveSub. If so, this callback is called for
             // Active Subscription change.
@@ -406,7 +416,7 @@
             // which will send another update at which point we will be in the right state.
             Call anyActiveCall = mCallsManager.getActiveCall();
             if ((anyActiveCall != null) && oldState == CallState.CONNECTING &&
-                    newState == CallState.DIALING) {
+                    newState == CallState.DIALING || newState == CallState.PULLING) {
                 if (!isDsdaEnabled()) {
                     return;
                 } else if (isCallonActiveSub(anyActiveCall)) {
@@ -419,6 +429,9 @@
 
         @Override
         public void onIsConferencedChanged(Call call) {
+            if (call.isExternalCall()) {
+                return;
+            }
             /*
              * Filter certain onIsConferencedChanged callbacks. Unfortunately this needs to be done
              * because conference change events are not atomic and multiple callbacks get fired
@@ -622,6 +635,12 @@
                 return false;
             if (activeCall != null) {
                 mCallsManager.disconnectCall(activeCall);
+                if (ringingCall != null) {
+                    mCallsManager.answerCall(ringingCall, VideoProfile.STATE_AUDIO_ONLY);
+                } else if (heldCall != null) {
+                    mCallsManager.unholdCall(heldCall);
+                }
+                return true;
             }
             if (ringingCall != null) {
                 mCallsManager.answerCall(ringingCall, ringingCall.getVideoState());
@@ -636,7 +655,7 @@
                 updateHeadsetWithCallState(true /* force */, activeCall);
                 return true;
             } else if (ringingCall != null) {
-                mCallsManager.answerCall(ringingCall, ringingCall.getVideoState());
+                mCallsManager.answerCall(ringingCall, VideoProfile.STATE_AUDIO_ONLY);
                 return true;
             } else if (heldCall != null) {
                 // CallsManager will hold any active calls when unhold() is called on a
@@ -1268,6 +1287,7 @@
             case CallState.CONNECTING:
             case CallState.SELECT_PHONE_ACCOUNT:
             case CallState.DIALING:
+            case CallState.PULLING:
                 // Yes, this is correctly returning ALERTING.
                 // "Dialing" for BT means that we have sent information to the service provider
                 // to place the call but there is no confirmation that the call is going through.
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index f065bc6..a203e6c 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -26,6 +26,7 @@
 import android.os.RemoteException;
 import android.os.Trace;
 import android.provider.ContactsContract.Contacts;
+import android.telecom.Conference;
 import android.telecom.DisconnectCause;
 import android.telecom.Connection;
 import android.telecom.GatewayInfo;
@@ -103,7 +104,7 @@
         void onExtrasRemoved(Call c, int source, List<String> keys);
         void onHandleChanged(Call call);
         void onCallerDisplayNameChanged(Call call);
-        void onVideoStateChanged(Call call);
+        void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
         void onTargetPhoneAccountChanged(Call call);
         void onConnectionManagerPhoneAccountChanged(Call call);
         void onPhoneAccountChanged(Call call);
@@ -160,7 +161,7 @@
         @Override
         public void onCallerDisplayNameChanged(Call call) {}
         @Override
-        public void onVideoStateChanged(Call call) {}
+        public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {}
         @Override
         public void onTargetPhoneAccountChanged(Call call) {}
         @Override
@@ -345,6 +346,7 @@
     private final CallsManager mCallsManager;
     private final TelecomSystem.SyncRoot mLock;
     private final String mId;
+    private String mConnectionId;
     private Analytics.CallInfo mAnalytics;
 
     private boolean mWasConferencePreviouslyMerged = false;
@@ -381,6 +383,19 @@
      */
     private boolean mIsVideoCallingSupported = false;
 
+    private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
+
+    /**
+     * For {@link Connection}s or {@link android.telecom.Conference}s added via a ConnectionManager
+     * using the {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
+     * Connection)} or {@link android.telecom.ConnectionService#addConference(Conference)},
+     * indicates the ID of this call as it was referred to by the {@code ConnectionService} which
+     * originally created it.
+     *
+     * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID} for more information.
+     */
+    private String mOriginalConnectionId;
+
     /**
      * Persists the specified parameters and initializes the new instance.
      *
@@ -406,6 +421,7 @@
             ConnectionServiceRepository repository,
             ContactsAsyncHelper contactsAsyncHelper,
             CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
             Uri handle,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle connectionManagerPhoneAccountHandle,
@@ -414,11 +430,13 @@
             boolean shouldAttachToExistingConnection,
             boolean isConference) {
         mId = callId;
+        mConnectionId = callId;
         mState = isConference ? CallState.ACTIVE : CallState.NEW;
         mContext = context;
         mCallsManager = callsManager;
         mLock = lock;
         mRepository = repository;
+        mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
         setHandle(handle);
         mPostDialDigits = handle != null
                 ? PhoneNumberUtils.extractPostDialPortion(handle.getSchemeSpecificPart()) : "";
@@ -432,7 +450,6 @@
         maybeLoadCannedSmsResponses();
         mAnalytics = new Analytics.CallInfo();
 
-        Log.event(this, Log.Events.CREATED);
     }
 
     /**
@@ -461,6 +478,7 @@
             ConnectionServiceRepository repository,
             ContactsAsyncHelper contactsAsyncHelper,
             CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
             Uri handle,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle connectionManagerPhoneAccountHandle,
@@ -470,7 +488,7 @@
             boolean isConference,
             long connectTimeMillis) {
         this(callId, context, callsManager, lock, repository, contactsAsyncHelper,
-                callerInfoAsyncQueryFactory, handle, gatewayInfo,
+                callerInfoAsyncQueryFactory, phoneNumberUtilsAdapter, handle, gatewayInfo,
                 connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection,
                 shouldAttachToExistingConnection, isConference);
 
@@ -503,6 +521,7 @@
                 analyticsDirection = Analytics.UNKNOWN_DIRECTION;
         }
         mAnalytics = Analytics.initiateCallAnalytics(mId, analyticsDirection);
+        Log.event(this, Log.Events.CREATED);
     }
 
     public Analytics.CallInfo getAnalytics() {
@@ -572,6 +591,11 @@
             return false;
         }
 
+        // Only Redial a Call in the case of it being an Emergency Call.
+        if(!isEmergencyCall()) {
+            return false;
+        }
+
         // Make sure that there are additional connection services to process.
         if (mCreateConnectionProcessor == null
             || !mCreateConnectionProcessor.isProcessingComplete()
@@ -597,6 +621,21 @@
     }
 
     /**
+     * Returns the unique ID for this call (see {@link #getId}) along with an attempt indicator that
+     * iterates based on attempts to establish a {@link Connection} using createConnectionProcessor.
+     * @return The call ID with an appended attempt id.
+     */
+    public String getConnectionId() {
+        if(mCreateConnectionProcessor != null) {
+            mConnectionId = mId + "_" +
+                    String.valueOf(mCreateConnectionProcessor.getConnectionAttempt());
+            return mConnectionId;
+        } else {
+            return mConnectionId;
+        }
+    }
+
+    /**
      * Sets the call state. Although there exists the notion of appropriate state transitions
      * (see {@link CallState}), in practice those expectations break down when cellular systems
      * misbehave and they do this very often. The result is that we do not enforce state transitions
@@ -657,6 +696,9 @@
                 case CallState.DIALING:
                     event = Log.Events.SET_DIALING;
                     break;
+                case CallState.PULLING:
+                    event = Log.Events.SET_PULLING;
+                    break;
                 case CallState.DISCONNECTED:
                     event = Log.Events.SET_DISCONNECTED;
                     data = getDisconnectCause();
@@ -992,10 +1034,18 @@
                 connectionCapabilities = removeVideoCapabilities(connectionCapabilities);
             }
 
+            int previousCapabilities = mConnectionCapabilities;
             mConnectionCapabilities = connectionCapabilities;
             for (Listener l : mListeners) {
                 l.onConnectionCapabilitiesChanged(this);
             }
+
+            int xorCaps = previousCapabilities ^ mConnectionCapabilities;
+            Log.event(this, Log.Events.CAPABILITY_CHANGE,
+                    "Current: [%s], Removed [%s], Added [%s]",
+                    Connection.capabilitiesToStringShort(mConnectionCapabilities),
+                    Connection.capabilitiesToStringShort(previousCapabilities & xorCaps),
+                    Connection.capabilitiesToStringShort(mConnectionCapabilities & xorCaps));
         }
     }
 
@@ -1016,12 +1066,21 @@
             if (wasExternal != isExternal) {
                 Log.v(this, "setConnectionProperties: external call changed isExternal = %b",
                         isExternal);
-
+                Log.event(this, Log.Events.IS_EXTERNAL, isExternal);
                 for (Listener l : mListeners) {
                     l.onExternalCallChanged(this, isExternal);
                 }
 
             }
+
+            mAnalytics.addCallProperties(mConnectionProperties);
+
+            int xorProps = previousProperties ^ mConnectionProperties;
+            Log.event(this, Log.Events.PROPERTY_CHANGE,
+                    "Current: [%s], Removed [%s], Added [%s]",
+                    Connection.propertiesToStringShort(mConnectionProperties),
+                    Connection.propertiesToStringShort(previousProperties & xorProps),
+                    Connection.propertiesToStringShort(mConnectionProperties & xorProps));
         }
     }
 
@@ -1085,6 +1144,34 @@
     }
 
     /**
+     * Perform an in-place replacement of the {@link ConnectionServiceWrapper} for this Call.
+     * Removes the call from its former {@link ConnectionServiceWrapper}, ensuring that the
+     * ConnectionService is NOT unbound if the call count hits zero.
+     * This is used by the {@link ConnectionServiceWrapper} when handling {@link Connection} and
+     * {@link Conference} additions via a ConnectionManager.
+     * The original {@link android.telecom.ConnectionService} will directly add external calls and
+     * conferences to Telecom as well as the ConnectionManager, which will add to Telecom.  In these
+     * cases since its first added to via the original CS, we want to change the CS responsible for
+     * the call to the ConnectionManager rather than adding it again as another call/conference.
+     *
+     * @param service The new {@link ConnectionServiceWrapper}.
+     */
+    public void replaceConnectionService(ConnectionServiceWrapper service) {
+        Preconditions.checkNotNull(service);
+
+        if (mConnectionService != null) {
+            ConnectionServiceWrapper serviceTemp = mConnectionService;
+            mConnectionService = null;
+            serviceTemp.removeCall(this);
+            serviceTemp.decrementAssociatedCallCount(true /*isSuppressingUnbind*/);
+        }
+
+        service.incrementAssociatedCallCount();
+        mConnectionService = service;
+        mAnalytics.setCallConnectionService(service.getComponentName().flattenToShortString());
+    }
+
+    /**
      * Clears the associated connection service.
      */
     void clearConnectionService() {
@@ -1306,16 +1393,24 @@
      */
     @VisibleForTesting
     public void answer(int videoState) {
-        Preconditions.checkNotNull(mConnectionService);
-
         // Check to verify that the call is still in the ringing state. A call can change states
         // between the time the user hits 'answer' and Telecom receives the command.
         if (isRinging("answer")) {
+            if (!isVideoCallingSupported() && VideoProfile.isVideo(videoState)) {
+                // Video calling is not supported, yet the InCallService is attempting to answer as
+                // video.  We will simply answer as audio-only.
+                videoState = VideoProfile.STATE_AUDIO_ONLY;
+            }
             // At this point, we are asking the connection service to answer but we don't assume
             // that it will work. Instead, we wait until confirmation from the connectino service
             // that the call is in a non-STATE_RINGING state before changing the UI. See
             // {@link ConnectionServiceAdapter#setActive} and other set* methods.
-            mConnectionService.answer(this, videoState);
+            if (mConnectionService != null) {
+                mConnectionService.answer(this, videoState);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "answer call failed due to null CS callId=%s", getId());
+            }
             Log.event(this, Log.Events.REQUEST_ACCEPT);
         }
     }
@@ -1328,16 +1423,20 @@
      */
     @VisibleForTesting
     public void reject(boolean rejectWithMessage, String textMessage) {
-        Preconditions.checkNotNull(mConnectionService);
-
         // Check to verify that the call is still in the ringing state. A call can change states
         // between the time the user hits 'reject' and Telecomm receives the command.
         if (isRinging("reject")) {
             // Ensure video state history tracks video state at time of rejection.
             mVideoStateHistory |= mVideoState;
 
-            mConnectionService.reject(this, rejectWithMessage, textMessage);
+            if (mConnectionService != null) {
+                mConnectionService.reject(this, rejectWithMessage, textMessage);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "reject call failed due to null CS callId=%s", getId());
+            }
             Log.event(this, Log.Events.REQUEST_REJECT);
+
         }
     }
 
@@ -1345,10 +1444,13 @@
      * Puts the call on hold if it is currently active.
      */
     void hold() {
-        Preconditions.checkNotNull(mConnectionService);
-
         if (mState == CallState.ACTIVE) {
-            mConnectionService.hold(this);
+            if (mConnectionService != null) {
+                mConnectionService.hold(this);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "hold call failed due to null CS callId=%s", getId());
+            }
             Log.event(this, Log.Events.REQUEST_HOLD);
         }
     }
@@ -1357,10 +1459,13 @@
      * Releases the call from hold if it is currently active.
      */
     void unhold() {
-        Preconditions.checkNotNull(mConnectionService);
-
         if (mState == CallState.ON_HOLD) {
-            mConnectionService.unhold(this);
+            if (mConnectionService != null) {
+                mConnectionService.unhold(this);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "unhold call failed due to null CS callId=%s", getId());
+            }
             Log.event(this, Log.Events.REQUEST_UNHOLD);
         }
     }
@@ -1414,7 +1519,12 @@
 
         // If the change originated from an InCallService, notify the connection service.
         if (source == SOURCE_INCALL_SERVICE) {
-            mConnectionService.onExtrasChanged(this, mExtras);
+            if (mConnectionService != null) {
+                mConnectionService.onExtrasChanged(this, mExtras);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "putExtras failed due to null CS callId=%s", getId());
+            }
         }
     }
 
@@ -1444,7 +1554,12 @@
 
         // If the change originated from an InCallService, notify the connection service.
         if (source == SOURCE_INCALL_SERVICE) {
-            mConnectionService.onExtrasChanged(this, mExtras);
+            if (mConnectionService != null) {
+                mConnectionService.onExtrasChanged(this, mExtras);
+            } else {
+                Log.e(this, new NullPointerException(),
+                        "removeExtras failed due to null CS callId=%s", getId());
+            }
         }
     }
 
@@ -1485,7 +1600,12 @@
     }
 
     void postDialContinue(boolean proceed) {
-        mConnectionService.onPostDialContinue(this, proceed);
+        if (mConnectionService != null) {
+            mConnectionService.onPostDialContinue(this, proceed);
+        } else {
+            Log.e(this, new NullPointerException(),
+                    "postDialContinue failed due to null CS callId=%s", getId());
+        }
     }
 
     void conferenceWith(Call otherCall) {
@@ -1501,7 +1621,7 @@
         if (mConnectionService == null) {
             Log.w(this, "splitting from conference call without a connection service");
         } else {
-            Log.event(this, Log.Events.SPLIT_CONFERENCE);
+            Log.event(this, Log.Events.SPLIT_FROM_CONFERENCE);
             mConnectionService.splitFromConference(this);
         }
     }
@@ -1557,7 +1677,7 @@
      * {@link android.telecom.Connection#PROPERTY_IS_EXTERNAL_CALL} property 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 
+     * 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
@@ -1582,7 +1702,7 @@
             return;
         }
 
-        Log.event(this, Log.Events.PULL);
+        Log.event(this, Log.Events.REQUEST_PULL);
         mConnectionService.pullExternalCall(this);
     }
 
@@ -1595,7 +1715,12 @@
      * @param extras Associated extras.
      */
     public void sendCallEvent(String event, Bundle extras) {
-        mConnectionService.sendCallEvent(this, event, extras);
+        if (mConnectionService != null) {
+            mConnectionService.sendCallEvent(this, event, extras);
+        } else {
+            Log.e(this, new NullPointerException(),
+                    "sendCallEvent failed due to null CS callId=%s", getId());
+        }
     }
 
     void setParentCall(Call parentCall) {
@@ -1703,7 +1828,7 @@
             return false;
         }
 
-        if (PhoneNumberUtils.isUriNumber(getHandle().toString())) {
+        if (mPhoneNumberUtilsAdapter.isUriNumber(getHandle().toString())) {
             // The incoming number is actually a URI (i.e. a SIP address),
             // not a regular PSTN phone number, and we can't send SMSes to
             // SIP addresses.
@@ -1777,6 +1902,10 @@
      */
     private void setCallerInfo(Uri handle, CallerInfo callerInfo) {
         Trace.beginSection("setCallerInfo");
+        if (callerInfo == null) {
+            Log.i(this, "CallerInfo lookup returned null, skipping update");
+            return;
+        }
 
         if ((handle != null) && !handle.equals(mHandle)) {
             Log.i(this, "setCallerInfo received stale caller info for an old handle. Ignoring.");
@@ -1915,6 +2044,12 @@
      * @param videoState The video state for the call.
      */
     public void setVideoState(int videoState) {
+        // If the phone account associated with this call does not support video calling, then we
+        // will automatically set the video state to audio-only.
+        if (!isVideoCallingSupported()) {
+            videoState = VideoProfile.STATE_AUDIO_ONLY;
+        }
+
         // Track which video states were applicable over the duration of the call.
         // Only track the call state when the call is active or disconnected.  This ensures we do
         // not include the video state when:
@@ -1926,9 +2061,18 @@
             mVideoStateHistory = mVideoStateHistory | videoState;
         }
 
+        int previousVideoState = mVideoState;
         mVideoState = videoState;
-        for (Listener l : mListeners) {
-            l.onVideoStateChanged(this);
+        if (mVideoState != previousVideoState) {
+            Log.event(this, Log.Events.VIDEO_STATE_CHANGED,
+                    VideoProfile.videoStateToString(videoState));
+            for (Listener l : mListeners) {
+                l.onVideoStateChanged(this, previousVideoState, mVideoState);
+            }
+        }
+
+        if (VideoProfile.isVideo(videoState)) {
+            mAnalytics.setCallIsVideo(true);
         }
     }
 
@@ -2001,6 +2145,8 @@
                 return CallState.ACTIVE;
             case Connection.STATE_DIALING:
                 return CallState.DIALING;
+            case Connection.STATE_PULLING_CALL:
+                return CallState.PULLING;
             case Connection.STATE_DISCONNECTED:
                 return CallState.DISCONNECTED;
             case Connection.STATE_HOLDING:
@@ -2077,6 +2223,7 @@
      * @param extras The extras.
      */
     public void onConnectionEvent(String event, Bundle extras) {
+        Log.event(this, Log.Events.CONNECTION_EVENT, event);
         if (Connection.EVENT_ON_HOLD_TONE_START.equals(event)) {
             mIsRemotelyHeld = true;
             Log.event(this, Log.Events.REMOTELY_HELD);
@@ -2098,6 +2245,24 @@
         }
     }
 
+    public void setOriginalConnectionId(String originalConnectionId) {
+        mOriginalConnectionId = originalConnectionId;
+    }
+
+    /**
+     * For calls added via a ConnectionManager using the
+     * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
+     * Connection)}, or {@link android.telecom.ConnectionService#addConference(Conference)} APIS,
+     * indicates the ID of this call as it was referred to by the {@code ConnectionService} which
+     * originally created it.
+     *
+     * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}.
+     * @return The original connection ID.
+     */
+    public String getOriginalConnectionId() {
+        return mOriginalConnectionId;
+    }
+
     /**
      * Determines if a {@link Call}'s capabilities bitmask indicates that video is supported either
      * remotely or locally.
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 5015618..90ac08a 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -72,6 +72,7 @@
             put(CallState.CONNECTING, mActiveDialingOrConnectingCalls);
             put(CallState.ACTIVE, mActiveDialingOrConnectingCalls);
             put(CallState.DIALING, mActiveDialingOrConnectingCalls);
+            put(CallState.PULLING, mActiveDialingOrConnectingCalls);
             put(CallState.RINGING, mRingingCalls);
             put(CallState.ON_HOLD, mHoldingCalls);
         }};
@@ -105,7 +106,7 @@
         }
 
         updateForegroundCall();
-        if (newState == CallState.DISCONNECTED) {
+        if (shouldPlayDisconnectTone(oldState, newState)) {
             playToneForDisconnectedCall(call);
         }
 
@@ -177,12 +178,20 @@
      */
     @Override
     public void onExternalCallChanged(Call call, boolean isExternalCall) {
-       if (isExternalCall) {
+        if (isExternalCall) {
             Log.d(LOG_TAG, "Removing call which became external ID %s", call.getId());
             removeCall(call);
         } else if (!isExternalCall) {
             Log.d(LOG_TAG, "Adding external call which was pulled with ID %s", call.getId());
             addCall(call);
+
+            if (mCallsManager.isSpeakerphoneAutoEnabledForVideoCalls(call.getVideoState())) {
+                // When pulling a video call, automatically enable the speakerphone.
+                Log.d(LOG_TAG, "Switching to speaker because external video call %s was pulled." +
+                        call.getId());
+                mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
+                        CallAudioRouteStateMachine.SWITCH_SPEAKER);
+            }
         }
     }
 
@@ -314,6 +323,25 @@
                 CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
     }
 
+    @Override
+    public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
+        if (call != getForegroundCall()) {
+            Log.d(LOG_TAG, "Ignoring video state change from %s to %s for call %s -- not " +
+                    "foreground.", VideoProfile.videoStateToString(previousVideoState),
+                    VideoProfile.videoStateToString(newVideoState), call.getId());
+            return;
+        }
+
+        if (!VideoProfile.isVideo(previousVideoState) &&
+                mCallsManager.isSpeakerphoneAutoEnabledForVideoCalls(newVideoState)) {
+            Log.d(LOG_TAG, "Switching to speaker because call %s transitioned video state from %s" +
+                    " to %s", call.getId(), VideoProfile.videoStateToString(previousVideoState),
+                    VideoProfile.videoStateToString(newVideoState));
+            mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
+                    CallAudioRouteStateMachine.SWITCH_SPEAKER);
+        }
+    }
+
     public CallAudioState getCallAudioState() {
         return mCallAudioRouteStateMachine.getCurrentCallAudioState();
     }
@@ -394,8 +422,8 @@
     }
 
     @VisibleForTesting
-    public void startRinging() {
-        mRinger.startRinging(mForegroundCall);
+    public boolean startRinging() {
+        return mRinger.startRinging(mForegroundCall);
     }
 
     @VisibleForTesting
@@ -424,6 +452,11 @@
         return mCallAudioRouteStateMachine;
     }
 
+    @VisibleForTesting
+    public CallAudioModeStateMachine getCallAudioModeStateMachine() {
+        return mCallAudioModeStateMachine;
+    }
+
     void dump(IndentingPrintWriter pw) {
         pw.println("All calls:");
         pw.increaseIndent();
@@ -470,9 +503,13 @@
             case CallState.ON_HOLD:
                 onCallLeavingHold();
                 break;
+            case CallState.PULLING:
+                onCallLeavingActiveDialingOrConnecting();
+                break;
             case CallState.DIALING:
                 stopRingbackForCall(call);
                 onCallLeavingActiveDialingOrConnecting();
+                break;
         }
     }
 
@@ -488,6 +525,9 @@
             case CallState.ON_HOLD:
                 onCallEnteringHold();
                 break;
+            case CallState.PULLING:
+                onCallEnteringActiveDialingOrConnecting();
+                break;
             case CallState.DIALING:
                 onCallEnteringActiveDialingOrConnecting();
                 playRingbackForCall(call);
@@ -662,7 +702,7 @@
         if (shouldPlayHoldTone()) {
             if (mHoldTonePlayer == null) {
                 mHoldTonePlayer = mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
-                mHoldTonePlayer.start();
+                mHoldTonePlayer.startTone();
             }
         } else {
             if (mHoldTonePlayer != null) {
@@ -716,6 +756,15 @@
         }
     }
 
+    private boolean shouldPlayDisconnectTone(int oldState, int newState) {
+        if (newState != CallState.DISCONNECTED) {
+            return false;
+        }
+        return oldState == CallState.ACTIVE ||
+                oldState == CallState.DIALING ||
+                oldState == CallState.ON_HOLD;
+    }
+
     @VisibleForTesting
     public Set<Call> getTrackedCalls() {
         return mCalls;
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index fa211ca..2c9417b 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -201,19 +201,22 @@
         @Override
         public void enter() {
             Log.i(LOG_TAG, "Audio focus entering RINGING state");
-            mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
-            if (mMostRecentMode == AudioManager.MODE_IN_CALL) {
-                // Preserving behavior from the old CallAudioManager.
-                Log.i(LOG_TAG, "Transition from IN_CALL -> RINGTONE."
-                        + "  Resetting to NORMAL first.");
-                mAudioManager.setMode(AudioManager.MODE_NORMAL);
+            if (mCallAudioManager.startRinging()) {
+                mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
+                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+                if (mMostRecentMode == AudioManager.MODE_IN_CALL) {
+                    // Preserving behavior from the old CallAudioManager.
+                    Log.i(LOG_TAG, "Transition from IN_CALL -> RINGTONE."
+                            + "  Resetting to NORMAL first.");
+                    mAudioManager.setMode(AudioManager.MODE_NORMAL);
+                }
+                mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+                mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.RINGING_FOCUS);
+            } else {
+                Log.i(LOG_TAG, "Entering RINGING but not acquiring focus -- silent ringtone");
             }
-            mAudioManager.setMode(AudioManager.MODE_RINGTONE);
 
             mCallAudioManager.stopCallWaiting();
-            mCallAudioManager.startRinging();
-            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.HAS_FOCUS);
         }
 
         @Override
@@ -288,7 +291,7 @@
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(AudioManager.MODE_IN_CALL);
             mMostRecentMode = AudioManager.MODE_IN_CALL;
-            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.HAS_FOCUS);
+            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
 
         @Override
@@ -350,7 +353,7 @@
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
             mMostRecentMode = AudioManager.MODE_IN_COMMUNICATION;
-            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.HAS_FOCUS);
+            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
 
         @Override
@@ -407,7 +410,7 @@
             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(mMostRecentMode);
-            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.HAS_FOCUS);
+            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
 
         @Override
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 50d8b87..7b6c2b5 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -18,7 +18,11 @@
 
 
 import android.app.ActivityManagerNative;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -105,7 +109,15 @@
 
     /** Valid values for mAudioFocusType */
     public static final int NO_FOCUS = 1;
-    public static final int HAS_FOCUS = 2;
+    public static final int ACTIVE_FOCUS = 2;
+    public static final int RINGING_FOCUS = 3;
+
+    private static final SparseArray<String> AUDIO_ROUTE_TO_LOG_EVENT = new SparseArray<String>() {{
+        put(CallAudioState.ROUTE_BLUETOOTH, Log.Events.AUDIO_ROUTE_BT);
+        put(CallAudioState.ROUTE_EARPIECE, Log.Events.AUDIO_ROUTE_EARPIECE);
+        put(CallAudioState.ROUTE_SPEAKER, Log.Events.AUDIO_ROUTE_SPEAKER);
+        put(CallAudioState.ROUTE_WIRED_HEADSET, Log.Events.AUDIO_ROUTE_HEADSET);
+    }};
 
     private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
         put(CONNECT_WIRED_HEADSET, "CONNECT_WIRED_HEADSET");
@@ -128,6 +140,8 @@
         put(USER_SWITCH_SPEAKER, "USER_SWITCH_SPEAKER");
         put(USER_SWITCH_BASELINE_ROUTE, "USER_SWITCH_BASELINE_ROUTE");
 
+        put(UPDATE_SYSTEM_AUDIO_ROUTE, "UPDATE_SYSTEM_AUDIO_ROUTE");
+
         put(MUTE_ON, "MUTE_ON");
         put(MUTE_OFF, "MUTE_OFF");
         put(TOGGLE_MUTE, "TOGGLE_MUTE");
@@ -137,10 +151,39 @@
         put(RUN_RUNNABLE, "RUN_RUNNABLE");
     }};
 
+    /**
+     * BroadcastReceiver used to track changes in the notification interruption filter.  This
+     * ensures changes to the notification interruption filter made by the user during a call are
+     * respected when restoring the notification interruption filter state.
+     */
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.startSession("CARSM.oR");
+            try {
+                String action = intent.getAction();
+
+                if (action.equals(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)) {
+                    if (mAreNotificationSuppressed) {
+                        // If we've already set the interruption filter, and the user changes it to
+                        // something other than INTERRUPTION_FILTER_ALARMS, assume we will no longer
+                        // try to change it back if the audio route changes.
+                        mAreNotificationSuppressed =
+                                mInterruptionFilterProxy.getCurrentInterruptionFilter()
+                                        == NotificationManager.INTERRUPTION_FILTER_ALARMS;
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+    };
+
     private static final String ACTIVE_EARPIECE_ROUTE_NAME = "ActiveEarpieceRoute";
     private static final String ACTIVE_BLUETOOTH_ROUTE_NAME = "ActiveBluetoothRoute";
     private static final String ACTIVE_SPEAKER_ROUTE_NAME = "ActiveSpeakerRoute";
     private static final String ACTIVE_HEADSET_ROUTE_NAME = "ActiveHeadsetRoute";
+    private static final String RINGING_BLUETOOTH_ROUTE_NAME = "RingingBluetoothRoute";
     private static final String QUIESCENT_EARPIECE_ROUTE_NAME = "QuiescentEarpieceRoute";
     private static final String QUIESCENT_BLUETOOTH_ROUTE_NAME = "QuiescentBluetoothRoute";
     private static final String QUIESCENT_SPEAKER_ROUTE_NAME = "QuiescentSpeakerRoute";
@@ -153,7 +196,7 @@
         if (msg.obj != null && msg.obj instanceof Session) {
             String messageCodeName = MESSAGE_CODE_TO_NAME.get(msg.what, "unknown");
             Log.continueSession((Session) msg.obj, "CARSM.pM_" + messageCodeName);
-            Log.i(this, "Message received: %s=%d", messageCodeName, msg.what);
+            Log.i(this, "Message received: %s=%d, arg1=%d", messageCodeName, msg.what, msg.arg1);
         }
     }
 
@@ -210,6 +253,9 @@
                 case USER_SWITCH_BASELINE_ROUTE:
                     sendInternalMessage(calculateBaselineRouteMessage(true));
                     return HANDLED;
+                case SWITCH_FOCUS:
+                    mAudioFocusType = msg.arg1;
+                    return NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -236,6 +282,9 @@
             super.enter();
             setSpeakerphoneOn(false);
             setBluetoothOn(false);
+            if (mAudioFocusType == ACTIVE_FOCUS) {
+                setNotificationsSuppressed(true);
+            }
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE,
                     mAvailableRoutes);
             setSystemAudioState(newState);
@@ -243,6 +292,12 @@
         }
 
         @Override
+        public void exit() {
+            super.exit();
+            setNotificationsSuppressed(false);
+        }
+
+        @Override
         public void updateSystemAudioState() {
             updateInternalCallAudioState();
             setSystemAudioState(mCurrentCallAudioState);
@@ -261,7 +316,8 @@
                 case SWITCH_BLUETOOTH:
                 case USER_SWITCH_BLUETOOTH:
                     if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
-                        transitionTo(mActiveBluetoothRoute);
+                        transitionTo(mAudioFocusType == ACTIVE_FOCUS ?
+                                mActiveBluetoothRoute : mRingingBluetoothRoute);
                     } else {
                         Log.w(this, "Ignoring switch to bluetooth command. Not available.");
                     }
@@ -279,6 +335,10 @@
                     transitionTo(mActiveSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
+                    if (msg.arg1 == ACTIVE_FOCUS) {
+                        setNotificationsSuppressed(true);
+                    }
+
                     if (msg.arg1 == NO_FOCUS) {
                         reinitialize();
                     }
@@ -343,7 +403,7 @@
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
-                    if (msg.arg1 == HAS_FOCUS) {
+                    if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
                         transitionTo(mActiveEarpieceRoute);
                     }
                     return HANDLED;
@@ -442,7 +502,8 @@
                 case SWITCH_BLUETOOTH:
                 case USER_SWITCH_BLUETOOTH:
                     if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
-                        transitionTo(mActiveBluetoothRoute);
+                        transitionTo(mAudioFocusType == ACTIVE_FOCUS ?
+                                mActiveBluetoothRoute : mRingingBluetoothRoute);
                     } else {
                         Log.w(this, "Ignoring switch to bluetooth command. Not available.");
                     }
@@ -520,7 +581,7 @@
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
-                    if (msg.arg1 == HAS_FOCUS) {
+                    if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
                         transitionTo(mActiveHeadsetRoute);
                     }
                     return HANDLED;
@@ -645,6 +706,8 @@
                 case SWITCH_FOCUS:
                     if (msg.arg1 == NO_FOCUS) {
                         reinitialize();
+                    } else if (msg.arg1 == RINGING_FOCUS) {
+                        transitionTo(mRingingBluetoothRoute);
                     }
                     return HANDLED;
                 case BT_AUDIO_DISCONNECT:
@@ -656,6 +719,87 @@
         }
     }
 
+    class RingingBluetoothRoute extends BluetoothRoute {
+        @Override
+        public String getName() {
+            return RINGING_BLUETOOTH_ROUTE_NAME;
+        }
+
+        @Override
+        public boolean isActive() {
+            return false;
+        }
+
+        @Override
+        public void enter() {
+            super.enter();
+            setSpeakerphoneOn(false);
+            // Do not enable SCO audio here, since RING is being sent to the headset.
+            CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH,
+                    mAvailableRoutes);
+            setSystemAudioState(newState);
+            updateInternalCallAudioState();
+        }
+
+        @Override
+        public void updateSystemAudioState() {
+            updateInternalCallAudioState();
+            setSystemAudioState(mCurrentCallAudioState);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            if (super.processMessage(msg) == HANDLED) {
+                return HANDLED;
+            }
+            switch (msg.what) {
+                case USER_SWITCH_EARPIECE:
+                    mHasUserExplicitlyLeftBluetooth = true;
+                    // fall through
+                case SWITCH_EARPIECE:
+                    if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
+                        transitionTo(mActiveEarpieceRoute);
+                    } else {
+                        Log.w(this, "Ignoring switch to earpiece command. Not available.");
+                    }
+                    return HANDLED;
+                case SWITCH_BLUETOOTH:
+                case USER_SWITCH_BLUETOOTH:
+                    // Nothing to do
+                    return HANDLED;
+                case USER_SWITCH_HEADSET:
+                    mHasUserExplicitlyLeftBluetooth = true;
+                    // fall through
+                case SWITCH_HEADSET:
+                    if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
+                        transitionTo(mActiveHeadsetRoute);
+                    } else {
+                        Log.w(this, "Ignoring switch to headset command. Not available.");
+                    }
+                    return HANDLED;
+                case USER_SWITCH_SPEAKER:
+                    mHasUserExplicitlyLeftBluetooth = true;
+                    // fall through
+                case SWITCH_SPEAKER:
+                    transitionTo(mActiveSpeakerRoute);
+                    return HANDLED;
+                case SWITCH_FOCUS:
+                    if (msg.arg1 == NO_FOCUS) {
+                        reinitialize();
+                    } else if (msg.arg1 == ACTIVE_FOCUS) {
+                        transitionTo(mActiveBluetoothRoute);
+                    }
+                    return HANDLED;
+                case BT_AUDIO_DISCONNECT:
+                    // Ignore BT_AUDIO_DISCONNECT when ringing, since SCO audio should not be
+                    // connected.
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
     class QuiescentBluetoothRoute extends BluetoothRoute {
         @Override
         public String getName() {
@@ -710,8 +854,10 @@
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
-                    if (msg.arg1 == HAS_FOCUS) {
+                    if (msg.arg1 == ACTIVE_FOCUS) {
                         transitionTo(mActiveBluetoothRoute);
+                    } else if (msg.arg1 == RINGING_FOCUS) {
+                        transitionTo(mRingingBluetoothRoute);
                     }
                     return HANDLED;
                 case BT_AUDIO_DISCONNECT:
@@ -809,7 +955,8 @@
                     // fall through
                 case SWITCH_BLUETOOTH:
                     if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
-                        transitionTo(mActiveBluetoothRoute);
+                        transitionTo(mAudioFocusType == ACTIVE_FOCUS ?
+                                mActiveBluetoothRoute : mRingingBluetoothRoute);
                     } else {
                         Log.w(this, "Ignoring switch to bluetooth command. Not available.");
                     }
@@ -899,7 +1046,7 @@
                     // Nothing to do
                     return HANDLED;
                 case SWITCH_FOCUS:
-                    if (msg.arg1 == HAS_FOCUS) {
+                    if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
                         transitionTo(mActiveSpeakerRoute);
                     }
                     return HANDLED;
@@ -955,6 +1102,7 @@
     private final ActiveHeadsetRoute mActiveHeadsetRoute = new ActiveHeadsetRoute();
     private final ActiveBluetoothRoute mActiveBluetoothRoute = new ActiveBluetoothRoute();
     private final ActiveSpeakerRoute mActiveSpeakerRoute = new ActiveSpeakerRoute();
+    private final RingingBluetoothRoute mRingingBluetoothRoute = new RingingBluetoothRoute();
     private final QuiescentEarpieceRoute mQuiescentEarpieceRoute = new QuiescentEarpieceRoute();
     private final QuiescentHeadsetRoute mQuiescentHeadsetRoute = new QuiescentHeadsetRoute();
     private final QuiescentBluetoothRoute mQuiescentBluetoothRoute = new QuiescentBluetoothRoute();
@@ -965,8 +1113,10 @@
      * states
      */
     private int mAvailableRoutes;
+    private int mAudioFocusType;
     private boolean mWasOnSpeaker;
     private boolean mIsMuted;
+    private boolean mAreNotificationSuppressed = false;
 
     private final Context mContext;
     private final CallsManager mCallsManager;
@@ -975,7 +1125,9 @@
     private final WiredHeadsetManager mWiredHeadsetManager;
     private final StatusBarNotifier mStatusBarNotifier;
     private final CallAudioManager.AudioServiceFactory mAudioServiceFactory;
+    private final InterruptionFilterProxy mInterruptionFilterProxy;
     private final boolean mDoesDeviceSupportEarpieceRoute;
+    private final TelecomSystem.SyncRoot mLock;
     private boolean mHasUserExplicitlyLeftBluetooth = false;
 
     private HashMap<String, Integer> mStateNameToRouteCode;
@@ -993,12 +1145,14 @@
             WiredHeadsetManager wiredHeadsetManager,
             StatusBarNotifier statusBarNotifier,
             CallAudioManager.AudioServiceFactory audioServiceFactory,
+            InterruptionFilterProxy interruptionFilterProxy,
             boolean doesDeviceSupportEarpieceRoute) {
         super(NAME);
         addState(mActiveEarpieceRoute);
         addState(mActiveHeadsetRoute);
         addState(mActiveBluetoothRoute);
         addState(mActiveSpeakerRoute);
+        addState(mRingingBluetoothRoute);
         addState(mQuiescentEarpieceRoute);
         addState(mQuiescentHeadsetRoute);
         addState(mQuiescentBluetoothRoute);
@@ -1011,13 +1165,20 @@
         mWiredHeadsetManager = wiredHeadsetManager;
         mStatusBarNotifier = statusBarNotifier;
         mAudioServiceFactory = audioServiceFactory;
+        mInterruptionFilterProxy = interruptionFilterProxy;
+        // Register for misc other intent broadcasts.
+        IntentFilter intentFilter =
+                new IntentFilter(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+        context.registerReceiver(mReceiver, intentFilter);
         mDoesDeviceSupportEarpieceRoute = doesDeviceSupportEarpieceRoute;
+        mLock = callsManager.getLock();
 
         mStateNameToRouteCode = new HashMap<>(8);
         mStateNameToRouteCode.put(mQuiescentEarpieceRoute.getName(), ROUTE_EARPIECE);
         mStateNameToRouteCode.put(mQuiescentBluetoothRoute.getName(), ROUTE_BLUETOOTH);
         mStateNameToRouteCode.put(mQuiescentHeadsetRoute.getName(), ROUTE_WIRED_HEADSET);
         mStateNameToRouteCode.put(mQuiescentSpeakerRoute.getName(), ROUTE_SPEAKER);
+        mStateNameToRouteCode.put(mRingingBluetoothRoute.getName(), ROUTE_BLUETOOTH);
         mStateNameToRouteCode.put(mActiveEarpieceRoute.getName(), ROUTE_EARPIECE);
         mStateNameToRouteCode.put(mActiveBluetoothRoute.getName(), ROUTE_BLUETOOTH);
         mStateNameToRouteCode.put(mActiveHeadsetRoute.getName(), ROUTE_WIRED_HEADSET);
@@ -1116,10 +1277,54 @@
         quitNow();
     }
 
+    /**
+     * Sets whether notifications should be suppressed or not.  Used when in a call to ensure the
+     * device will not vibrate due to notifications.
+     * Alarm-only filtering is activated when
+     *
+     * @param on {@code true} when notification suppression should be activated, {@code false} when
+     *                       it should be deactivated.
+     */
+    private void setNotificationsSuppressed(boolean on) {
+        if (mInterruptionFilterProxy == null) {
+            return;
+        }
+
+        Log.i(this, "setNotificationsSuppressed: on=%s; suppressed=%s", (on ? "yes" : "no"),
+                (mAreNotificationSuppressed ? "yes" : "no"));
+        if (on) {
+            if (!mAreNotificationSuppressed) {
+                // Enabling suppression of notifications.
+                int interruptionFilter = mInterruptionFilterProxy.getCurrentInterruptionFilter();
+                if (interruptionFilter == NotificationManager.INTERRUPTION_FILTER_ALL) {
+                    // No interruption filter is specified, so suppress notifications by setting the
+                    // current filter to alarms-only.
+                    mAreNotificationSuppressed = true;
+                    mInterruptionFilterProxy.setInterruptionFilter(
+                            NotificationManager.INTERRUPTION_FILTER_ALARMS);
+                } else {
+                    // Interruption filter is already chosen by the user, so do not attempt to change
+                    // it.
+                    mAreNotificationSuppressed = false;
+                }
+            }
+        } else {
+            // Disabling suppression of notifications.
+            if (mAreNotificationSuppressed) {
+                // We have implemented the alarms-only policy and the user has not changed it since
+                // we originally set it, so reset the notification filter.
+                mInterruptionFilterProxy.setInterruptionFilter(
+                        NotificationManager.INTERRUPTION_FILTER_ALL);
+            }
+            mAreNotificationSuppressed = false;
+        }
+    }
+
     private void setSpeakerphoneOn(boolean on) {
         if (mAudioManager.isSpeakerphoneOn() != on) {
             Log.i(this, "turning speaker phone %s", on);
             mAudioManager.setSpeakerphoneOn(on);
+            mStatusBarNotifier.notifySpeakerphone(on);
         }
         // StatusBarNotifier has check for previous state before notifying again
         mStatusBarNotifier.notifySpeakerphone(on);
@@ -1141,8 +1346,8 @@
 
     private void setMuteOn(boolean mute) {
         mIsMuted = mute;
-        Log.event(mCallsManager.getForegroundCall(), Log.Events.MUTE,
-                mute ? "on" : "off");
+        Log.event(mCallsManager.getForegroundCall(), mute ? Log.Events.MUTE : Log.Events.UNMUTE);
+
         if (mute != mAudioManager.isMicrophoneMute() && isInActiveState()) {
             IAudioService audio = mAudioServiceFactory.getAudioService();
             Log.i(this, "changing microphone mute state to: %b [serviceIsNull=%b]",
@@ -1193,15 +1398,20 @@
     }
 
     private void setSystemAudioState(CallAudioState newCallAudioState, boolean force) {
-        Log.i(this, "setSystemAudioState: changing from %s to %s", mLastKnownCallAudioState,
-                newCallAudioState);
-        Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
-                CallAudioState.audioRouteToString(newCallAudioState.getRoute()));
+        synchronized (mLock) {
+            Log.i(this, "setSystemAudioState: changing from %s to %s", mLastKnownCallAudioState,
+                    newCallAudioState);
+            if (force || !newCallAudioState.equals(mLastKnownCallAudioState)) {
+                if (newCallAudioState.getRoute() != mLastKnownCallAudioState.getRoute()) {
+                    Log.event(mCallsManager.getForegroundCall(),
+                            AUDIO_ROUTE_TO_LOG_EVENT.get(newCallAudioState.getRoute(),
+                                    Log.Events.AUDIO_ROUTE));
+                }
 
-        if (force || !newCallAudioState.equals(mLastKnownCallAudioState)) {
-            mCallsManager.onCallAudioStateChanged(mLastKnownCallAudioState, newCallAudioState);
-            updateAudioForForegroundCall(newCallAudioState);
-            mLastKnownCallAudioState = newCallAudioState;
+                mCallsManager.onCallAudioStateChanged(mLastKnownCallAudioState, newCallAudioState);
+                updateAudioForForegroundCall(newCallAudioState);
+                mLastKnownCallAudioState = newCallAudioState;
+            }
         }
     }
 
diff --git a/src/com/android/server/telecom/CallIdMapper.java b/src/com/android/server/telecom/CallIdMapper.java
index b097bea..da2c199 100644
--- a/src/com/android/server/telecom/CallIdMapper.java
+++ b/src/com/android/server/telecom/CallIdMapper.java
@@ -77,7 +77,16 @@
         }
     }
 
+    public interface ICallInfo {
+        String getCallId(Call call);
+    }
+
     private final BiMap<String, Call> mCalls = new BiMap<>();
+    private ICallInfo mCallInfo;
+
+    public CallIdMapper(ICallInfo callInfo) {
+        mCallInfo = callInfo;
+    }
 
     void replaceCall(Call newCall, Call callToReplace) {
         // Use the old call's ID for the new call.
@@ -93,7 +102,7 @@
     }
 
     void addCall(Call call) {
-        addCall(call, call.getId());
+        addCall(call, mCallInfo.getCallId(call));
     }
 
     void removeCall(Call call) {
@@ -111,7 +120,7 @@
         if (call == null || mCalls.getKey(call) == null) {
             return null;
         }
-        return call.getId();
+        return mCallInfo.getCallId(call);
     }
 
     Call getCall(Object objId) {
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 2e9ef0b..293d03f 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -190,7 +190,7 @@
             // process will be running throughout the duration of the phone call and should never
             // be killed.
             NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
-                    context, callsManager, call, intent, new PhoneNumberUtilsAdapterImpl(),
+                    context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
                     isPrivilegedDialer);
             final int result = broadcaster.processIntent();
             final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 22bf203..1fd66af 100644
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -145,15 +145,21 @@
         // 1) It was not in the "choose account" phase when disconnected
         // 2) It is a conference call
         // 3) Call was not explicitly canceled
+        // 4) Call is not an external call
         if (isNewlyDisconnected &&
                 (oldState != CallState.SELECT_PHONE_ACCOUNT &&
                  !call.isConference() &&
-                 !isCallCanceled)) {
+                 !isCallCanceled) &&
+                !call.isExternalCall()) {
             int type;
             if (!call.isIncoming()) {
                 type = Calls.OUTGOING_TYPE;
             } else if (disconnectCause == DisconnectCause.MISSED) {
                 type = Calls.MISSED_TYPE;
+            } else if (disconnectCause == DisconnectCause.ANSWERED_ELSEWHERE) {
+                type = Calls.ANSWERED_EXTERNALLY_TYPE;
+            } else if (disconnectCause == DisconnectCause.REJECTED) {
+                type = Calls.REJECTED_TYPE;
             } else {
                 type = Calls.INCOMING_TYPE;
             }
@@ -210,7 +216,8 @@
         Long callDataUsage = call.getCallDataUsage() == Call.DATA_USAGE_NOT_SET ? null :
                 call.getCallDataUsage();
 
-        int callFeatures = getCallFeatures(call.getVideoStateHistory());
+        int callFeatures = getCallFeatures(call.getVideoStateHistory(),
+                call.getDisconnectCause().getCode() == DisconnectCause.CALL_PULLED);
         logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
                 call.getHandlePresentation(), toPreciseLogType(call, callLogType), callFeatures,
                 accountHandle, creationTime, age, callDataUsage, call.isEmergencyCall(),
@@ -283,13 +290,18 @@
      * Based on the video state of the call, determines the call features applicable for the call.
      *
      * @param videoState The video state.
+     * @param isPulledCall {@code true} if this call was pulled to another device.
      * @return The call features.
      */
-    private static int getCallFeatures(int videoState) {
+    private static int getCallFeatures(int videoState, boolean isPulledCall) {
+        int features = 0;
         if (VideoProfile.isVideo(videoState)) {
-            return Calls.FEATURES_VIDEO;
+            features |= Calls.FEATURES_VIDEO;
         }
-        return 0;
+        if (isPulledCall) {
+            features |= Calls.FEATURES_PULLED_EXTERNALLY;
+        }
+        return features;
     }
 
     /**
diff --git a/src/com/android/server/telecom/CallState.java b/src/com/android/server/telecom/CallState.java
index 0d2ca48..0aa928f 100644
--- a/src/com/android/server/telecom/CallState.java
+++ b/src/com/android/server/telecom/CallState.java
@@ -103,6 +103,15 @@
      */
     public static final int DISCONNECTING = 9;
 
+    /**
+     * Indicates that the call is in the process of being pulled to the local device.
+     * <p>
+     * This state should only be set on a call with
+     * {@link android.telecom.Connection#PROPERTY_IS_EXTERNAL_CALL} and
+     * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}.
+     */
+    public static final int PULLING = 10;
+
     public static String toString(int callState) {
         switch (callState) {
             case NEW:
@@ -125,6 +134,8 @@
                 return "ABORTED";
             case DISCONNECTING:
                 return "DISCONNECTING";
+            case PULLING:
+                return "PULLING";
             default:
                 return "UNKNOWN";
         }
diff --git a/src/com/android/server/telecom/CallerInfoLookupHelper.java b/src/com/android/server/telecom/CallerInfoLookupHelper.java
index 3785a6f..244a802 100644
--- a/src/com/android/server/telecom/CallerInfoLookupHelper.java
+++ b/src/com/android/server/telecom/CallerInfoLookupHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
@@ -41,7 +42,7 @@
          * @param info
          * @return true if the value should be cached, false otherwise.
          */
-        void onCallerInfoQueryComplete(Uri handle, CallerInfo info);
+        void onCallerInfoQueryComplete(Uri handle, @Nullable CallerInfo info);
         void onContactPhotoQueryComplete(Uri handle, CallerInfo info);
     }
 
@@ -54,6 +55,7 @@
             listeners = new LinkedList<>();
         }
     }
+
     private final Map<Uri, CallerInfoQueryInfo> mQueryEntries = new HashMap<>();
 
     private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
@@ -95,7 +97,7 @@
                             info.callerInfo.cachedPhotoIcon != null)) {
                         listener.onContactPhotoQueryComplete(handle, info.callerInfo);
                     } else if (info.imageQueryPending) {
-                        Log.i(this, "There is a previously incomplete query for handle %s. " +
+                        Log.i(this, "There is a pending photo query for handle %s. " +
                                 "Adding to listeners for this query.", Log.piiHandle(handle));
                         info.listeners.add(listener);
                     }
@@ -112,7 +114,7 @@
             }
         }
 
-        mHandler.post(new Runnable("CILH.sL") {
+        mHandler.post(new Runnable("CILH.sL", mLock) {
             @Override
             public void loggedRun() {
                 Session continuedSession = Log.createSubsession();
@@ -139,11 +141,15 @@
                 Log.continueSession((Session) cookie, "CILH.oQC");
                 try {
                     if (mQueryEntries.containsKey(handle)) {
+                        Log.i(CallerInfoLookupHelper.this, "CI query for handle %s has completed;" +
+                                " notifying all listeners.", Log.piiHandle(handle));
                         CallerInfoQueryInfo info = mQueryEntries.get(handle);
                         for (OnQueryCompleteListener l : info.listeners) {
                             l.onCallerInfoQueryComplete(handle, ci);
                         }
                         if (ci.contactDisplayPhotoUri == null) {
+                            Log.i(CallerInfoLookupHelper.this, "There is no photo for this " +
+                                    "contact, skipping photo query");
                             mQueryEntries.remove(handle);
                         } else {
                             info.callerInfo = ci;
@@ -152,7 +158,7 @@
                         }
                     } else {
                         Log.i(CallerInfoLookupHelper.this, "CI query for handle %s has completed," +
-                                " but there are no listeners left.", handle);
+                                " but there are no listeners left.", Log.piiHandle(handle));
                     }
                 } finally {
                     Log.endSession();
@@ -162,7 +168,7 @@
     }
 
     private void startPhotoLookup(final Uri handle, final Uri contactPhotoUri) {
-        mHandler.post(new Runnable("CILH.sPL") {
+        mHandler.post(new Runnable("CILH.sPL", mLock) {
             @Override
             public void loggedRun() {
                 Session continuedSession = Log.createSubsession();
@@ -189,6 +195,7 @@
                         if (info.callerInfo == null) {
                             Log.w(CallerInfoLookupHelper.this, "Photo query finished, but the " +
                                     "CallerInfo object previously looked up was not cached.");
+                            mQueryEntries.remove(handle);
                             return;
                         }
                         info.callerInfo.cachedPhoto = photo;
@@ -199,7 +206,8 @@
                         mQueryEntries.remove(handle);
                     } else {
                         Log.i(CallerInfoLookupHelper.this, "Photo query for handle %s has" +
-                                " completed, but there are no listeners left.", handle);
+                                " completed, but there are no listeners left.",
+                                Log.piiHandle(handle));
                     }
                 } finally {
                     Log.endSession();
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 8e6ccce..0c495cb 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom;
 
 import android.app.ActivityManager;
+import android.app.NotificationManager;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.Intent;
@@ -77,9 +78,11 @@
 import java.util.Iterator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -113,7 +116,7 @@
         void onRingbackRequested(Call call, boolean ringback);
         void onIsConferencedChanged(Call call);
         void onIsVoipAudioModeChanged(Call call);
-        void onVideoStateChanged(Call call);
+        void onVideoStateChanged(Call call, int previousVideoState, int newVideoState);
         void onCanAddCallChanged(boolean canAddCall);
         void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
         void onHoldToneRequested(Call call);
@@ -133,11 +136,13 @@
     private static final int MAXIMUM_DSDA_TOP_LEVEL_CALLS = 4;
 
     private static final int[] OUTGOING_CALL_STATES =
-            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING};
+            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
+                    CallState.PULLING};
 
     private static final int[] LIVE_CALL_STATES =
             {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
-                CallState.ACTIVE};
+                    CallState.PULLING, CallState.ACTIVE};
+
     public static final String TELECOM_CALL_ID_PREFIX = "TC@";
 
     // Maps call technologies in PhoneConstants to those in Analytics.
@@ -204,6 +209,8 @@
     private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
     private final Timeouts.Adapter mTimeoutsAdapter;
     private final ViceNotificationImpl mViceNotificationImpl;
+    private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
+    private final NotificationManager mNotificationManager;
     private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
     private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
     /* Handler tied to thread in which CallManager was initialized. */
@@ -261,9 +268,12 @@
             DefaultDialerManagerAdapter defaultDialerAdapter,
             Timeouts.Adapter timeoutsAdapter,
             AsyncRingtonePlayer asyncRingtonePlayer,
-            ViceNotifier viceNotifier) {
+            ViceNotifier viceNotifier,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
+            InterruptionFilterProxy interruptionFilterProxy) {
         mContext = context;
         mLock = lock;
+        mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
         mContactsAsyncHelper = contactsAsyncHelper;
         mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
@@ -278,6 +288,8 @@
                 mContactsAsyncHelper, mLock);
 
         mDtmfLocalTonePlayer = new DtmfLocalTonePlayer();
+        mNotificationManager = (NotificationManager) context.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         CallAudioRouteStateMachine callAudioRouteStateMachine = new CallAudioRouteStateMachine(
                 context,
                 this,
@@ -285,6 +297,7 @@
                 wiredHeadsetManager,
                 statusBarNotifier,
                 audioServiceFactory,
+                interruptionFilterProxy,
                 CallAudioRouteStateMachine.doesDeviceSupportEarpieceRoute()
         );
         callAudioRouteStateMachine.initialize();
@@ -303,7 +316,7 @@
         RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
         SystemVibrator systemVibrator = new SystemVibrator(context);
         mInCallController = new InCallController(
-                context, mLock, this, systemStateProvider, defaultDialerAdapter);
+                context, mLock, this, systemStateProvider, defaultDialerAdapter, mTimeoutsAdapter);
         mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
                 ringtoneFactory, systemVibrator, mInCallController);
 
@@ -391,6 +404,12 @@
     @Override
     public void onSuccessfulIncomingCall(Call incomingCall) {
         Log.d(this, "onSuccessfulIncomingCall");
+        if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
+            Log.i(this, "Skipping call filtering due to ECBM");
+            onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));
+            return;
+        }
+
         List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
         filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
         filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
@@ -412,6 +431,7 @@
                     result.shouldAllowCall ? "successful incoming call" : "blocking call");
         } else {
             Log.i(this, "onCallFilteringCompleted: call already disconnected.");
+            return;
         }
 
         if (result.shouldAllowCall) {
@@ -525,15 +545,12 @@
 
             mDtmfLocalTonePlayer.playTone(call, nextChar);
 
-            // TODO: Create a LockedRunnable class that does the synchronization automatically.
-            mStopTone = new Runnable("CM.oPDC") {
+            mStopTone = new Runnable("CM.oPDC", mLock) {
                 @Override
                 public void loggedRun() {
-                    synchronized (mLock) {
-                        // Set a timeout to stop the tone in case there isn't another tone to
-                        // follow.
-                        mDtmfLocalTonePlayer.stopTone(call);
-                    }
+                    // Set a timeout to stop the tone in case there isn't another tone to
+                    // follow.
+                    mDtmfLocalTonePlayer.stopTone(call);
                 }
             };
             mHandler.postDelayed(mStopTone.prepare(),
@@ -555,7 +572,7 @@
     @Override
     public void onParentChanged(Call call) {
         // parent-child relationship affects which call should be foreground, so do an update.
-        updateCallsManagerState();
+        updateCanAddCall();
         for (CallsManagerListener listener : mListeners) {
             listener.onIsConferencedChanged(call);
         }
@@ -564,7 +581,7 @@
     @Override
     public void onChildrenChanged(Call call) {
         // parent-child relationship affects which call should be foreground, so do an update.
-        updateCallsManagerState();
+        updateCanAddCall();
         for (CallsManagerListener listener : mListeners) {
             listener.onIsConferencedChanged(call);
         }
@@ -578,23 +595,21 @@
     }
 
     @Override
-    public void onVideoStateChanged(Call call) {
+    public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
         for (CallsManagerListener listener : mListeners) {
-            listener.onVideoStateChanged(call);
+            listener.onVideoStateChanged(call, previousVideoState, newVideoState);
         }
     }
 
     @Override
     public boolean onCanceledViaNewOutgoingCallBroadcast(final Call call) {
         mPendingCallsToDisconnect.add(call);
-        mHandler.postDelayed(new Runnable("CM.oCVNOCB") {
+        mHandler.postDelayed(new Runnable("CM.oCVNOCB", mLock) {
             @Override
             public void loggedRun() {
-                synchronized (mLock) {
-                    if (mPendingCallsToDisconnect.remove(call)) {
-                        Log.i(this, "Delayed disconnection of call: %s", call);
-                        call.disconnect();
-                    }
+                if (mPendingCallsToDisconnect.remove(call)) {
+                    Log.i(this, "Delayed disconnection of call: %s", call);
+                    call.disconnect();
                 }
             }
         }.prepare(), Timeouts.getNewOutgoingCallCancelMillis(mContext.getContentResolver()));
@@ -709,7 +724,8 @@
         return false;
     }
 
-    CallAudioState getAudioState() {
+    @VisibleForTesting
+    public CallAudioState getAudioState() {
         return mCallAudioManager.getCallAudioState();
     }
 
@@ -752,6 +768,7 @@
                 mConnectionServiceRepository,
                 mContactsAsyncHelper,
                 mCallerInfoAsyncQueryFactory,
+                mPhoneNumberUtilsAdapter,
                 handle,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -784,6 +801,7 @@
                 mConnectionServiceRepository,
                 mContactsAsyncHelper,
                 mCallerInfoAsyncQueryFactory,
+                mPhoneNumberUtilsAdapter,
                 handle,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -819,9 +837,10 @@
         // Check to see if we can reuse any of the calls that are waiting to disconnect.
         // See {@link Call#abort} and {@link #onCanceledViaNewOutgoingCall} for more information.
         Call reusedCall = null;
-        for (Call pendingCall : mPendingCallsToDisconnect) {
+        for (Iterator<Call> callIter = mPendingCallsToDisconnect.iterator(); callIter.hasNext();) {
+            Call pendingCall = callIter.next();
             if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) {
-                mPendingCallsToDisconnect.remove(pendingCall);
+                callIter.remove();
                 Log.i(this, "Reusing disconnected call %s", pendingCall);
                 reusedCall = pendingCall;
             } else {
@@ -856,6 +875,7 @@
                     mConnectionServiceRepository,
                     mContactsAsyncHelper,
                     mCallerInfoAsyncQueryFactory,
+                    mPhoneNumberUtilsAdapter,
                     handle,
                     null /* gatewayInfo */,
                     null /* connectionManagerPhoneAccount */,
@@ -869,10 +889,11 @@
                 //Reset PostDialDigits with empty string for ConfURI call.
                 call.setPostDialDigits("");
             }
-            call.setInitiatingUser(initiatingUser);
 
             call.initAnalytics();
 
+            call.setInitiatingUser(initiatingUser);
+
             isReusedCall = false;
         }
 
@@ -884,11 +905,13 @@
 
             // If this is an emergency video call, we need to check if the phone account supports
             // emergency video calling.
-            if (call.isEmergencyCall() && VideoProfile.isVideo(videoState)) {
+            // Also, ensure we don't try to place an outgoing call with video if video is not
+            // supported.
+            if (VideoProfile.isVideo(videoState)) {
                 PhoneAccount account =
                         mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
 
-                if (account != null &&
+                if (call.isEmergencyCall() && account != null &&
                         !account.hasCapabilities(PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
                     // Phone account doesn't support emergency video calling, so fallback to
                     // audio-only now to prevent the InCall UI from setting up video surfaces
@@ -896,6 +919,12 @@
                     Log.i(this, "startOutgoingCall - emergency video calls not supported; " +
                             "falling back to audio-only");
                     videoState = VideoProfile.STATE_AUDIO_ONLY;
+                } else if (account != null &&
+                        !account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
+                    // Phone account doesn't support video calling, so fallback to audio-only.
+                    Log.i(this, "startOutgoingCall - video calls not supported; fallback to " +
+                            "audio-only.");
+                    videoState = VideoProfile.STATE_AUDIO_ONLY;
                 }
             }
 
@@ -937,7 +966,7 @@
             }
         }
 
-        if (phoneAccountHandle == null && accounts.size() > 0 && !call.isEmergencyCall()) {
+        if (phoneAccountHandle == null && accounts.size() > 0) {
             // No preset account, check if default exists that supports the URI scheme for the
             // handle and verify it can be used.
             if(accounts.size() > 1) {
@@ -1038,26 +1067,24 @@
 
         final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
                 R.bool.use_speaker_when_docked);
-        final boolean isDocked = mDockManager.isDocked();
-        final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabled(videoState);
+        final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
+        final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);
 
         // Auto-enable speakerphone if the originating intent specified to do so, if the call
         // is a video call, of if using speaker when docked
         call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
-                || (useSpeakerWhenDocked && isDocked));
+                || (useSpeakerWhenDocked && useSpeakerForDock));
         call.setVideoState(videoState);
 
         if (speakerphoneOn) {
             Log.i(this, "%s Starting with speakerphone as requested", call);
-        } else if (useSpeakerWhenDocked && useSpeakerWhenDocked) {
+        } else if (useSpeakerWhenDocked && useSpeakerForDock) {
             Log.i(this, "%s Starting with speakerphone because car is docked.", call);
         } else if (useSpeakerForVideoCall) {
             Log.i(this, "%s Starting with speakerphone because its a video call.", call);
         }
 
         if (call.isEmergencyCall()) {
-            // Emergency -- CreateConnectionProcessor will choose accounts automatically
-            call.setTargetPhoneAccount(null);
             new AsyncEmergencyContactNotifier(mContext).execute();
         }
 
@@ -1132,7 +1159,8 @@
             // STATE_DIALING, put it on hold before answering the call.
             if (activeCall != null && activeCall != call &&
                     (activeCall.isActive() ||
-                     activeCall.getState() == CallState.DIALING)) {
+                     activeCall.getState() == CallState.DIALING) ||
+                     activeCall.getState() == CallState.PULLING) {
                 if (0 == (activeCall.getConnectionCapabilities()
                         & Connection.CAPABILITY_HOLD)) {
                     // This call does not support hold.  If it is from a different connection
@@ -1165,7 +1193,7 @@
             // We do not update the UI until we get confirmation of the answer() through
             // {@link #markCallAsActive}.
             call.answer(videoState);
-            if (isSpeakerphoneAutoEnabled(videoState)) {
+            if (isSpeakerphoneAutoEnabledForVideoCalls(videoState)) {
                 call.setStartWithSpeakerphoneOn(true);
             }
         }
@@ -1179,7 +1207,7 @@
      * @param videoState The video state of the call.
      * @return {@code true} if the speakerphone should be enabled.
      */
-    private boolean isSpeakerphoneAutoEnabled(int videoState) {
+    public boolean isSpeakerphoneAutoEnabledForVideoCalls(int videoState) {
         return VideoProfile.isVideo(videoState) &&
             !mWiredHeadsetManager.isPluggedIn() &&
             !mBluetoothManager.isBluetoothAvailable() &&
@@ -1187,6 +1215,19 @@
     }
 
     /**
+     * Determines if the speakerphone should be enabled for when docked.  Speakerphone
+     * should be enabled if the device is docked and bluetooth or the wired headset are
+     * not in use.
+     *
+     * @return {@code true} if the speakerphone should be enabled for the dock.
+     */
+    private boolean isSpeakerphoneEnabledForDock() {
+        return mDockManager.isDocked() &&
+            !mWiredHeadsetManager.isPluggedIn() &&
+            !mBluetoothManager.isBluetoothAvailable();
+    }
+
+    /**
      * Determines if the speakerphone should be automatically enabled for video calls.
      *
      * @return {@code true} if the speakerphone should automatically be enabled.
@@ -1308,6 +1349,7 @@
         if (!mCalls.contains(call)) {
             Log.w(this, "Unknown call (%s) asked to be removed from hold", call);
         } else {
+            boolean otherCallHeld = false;
             Log.d(this, "unholding call: (%s)", call);
             for (Call c : mCalls) {
                 PhoneAccountHandle ph = call.getTargetPhoneAccount();
@@ -1317,9 +1359,14 @@
                 if (c != null && c.isAlive() && c != call && c.getParentCall() == null
                         && (ph != null && ph1 != null &&
                         isSamePhAccIdOrSipId(ph.getId(), ph1.getId()))) {
+                    otherCallHeld = true;
+                    Log.event(c, Log.Events.SWAP);
                     c.hold();
                 }
             }
+            if (otherCallHeld) {
+                Log.event(call, Log.Events.SWAP);
+            }
             call.unhold();
         }
     }
@@ -1337,6 +1384,7 @@
             boolean isNeedReset = extras.getBoolean("isNeedReset", false);
             handleCdmaConnectionTimeReset(c, isNeedReset);
         }
+        updateCanAddCall();
     }
 
     void handleCdmaConnectionTimeReset(Call call, boolean isNeedReset) {
@@ -1350,6 +1398,7 @@
             call.removeExtras(Call.SOURCE_INCALL_SERVICE,
                     new ArrayList<String>(Arrays.asList("isNeedReset")));
         }
+        updateCanAddCall();
     }
 
     // Construct the list of possible PhoneAccounts that the outgoing call can use based on the
@@ -1522,6 +1571,11 @@
         setActiveSubscription(call.getTargetPhoneAccount().getId());
     }
 
+    void markCallAsPulling(Call call) {
+        setCallState(call, CallState.PULLING, "pulling set explicitly");
+        maybeMoveToSpeakerPhone(call);
+    }
+
     void markCallAsActive(Call call) {
         setCallState(call, CallState.ACTIVE, "active set explicitly");
         maybeMoveToSpeakerPhone(call);
@@ -1589,16 +1643,25 @@
             setActiveSubscription(null);
             manageDsdaInCallTones(false);
         }
+        Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
+        boolean isChildCall = call.isChildCall();
         if (mLocallyDisconnectingCalls.contains(call)) {
-            boolean isChildCall = call.isChildCall();
             Log.v(this, "markCallAsRemoved: isChildCall = "
                 + isChildCall + "call -> %s", call);
             mLocallyDisconnectingCalls.remove(call);
-            Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
             if (!isChildCall && foregroundCall != null
                     && foregroundCall.getState() == CallState.ON_HOLD) {
                 foregroundCall.unhold();
             }
+        } else if (!isChildCall && foregroundCall != null &&
+                !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD)  &&
+                foregroundCall.getState() == CallState.ON_HOLD) {
+
+            // The new foreground call is on hold, however the carrier does not display the hold
+            // button in the UI.  Therefore, we need to auto unhold the held call since the user has
+            // no means of unholding it themselves.
+            Log.i(this, "Auto-unholding held foreground call (call doesn't support hold)");
+            foregroundCall.unhold();
         }
     }
 
@@ -1659,13 +1722,14 @@
                     mCallAudioManager.toggleMute();
                     return true;
                 } else {
-                    ringingCall.answer(ringingCall.getVideoState());
+                    ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
                     return true;
                 }
             } else if (HeadsetMediaButton.LONG_PRESS == type) {
                 Log.d(this, "handleHeadsetHook: longpress -> hangup");
                 Call callToHangup = getFirstCallWithState(
-                        CallState.RINGING, CallState.DIALING, CallState.ACTIVE, CallState.ON_HOLD);
+                        CallState.RINGING, CallState.DIALING, CallState.PULLING, CallState.ACTIVE,
+                        CallState.ON_HOLD);
                 if (callToHangup != null) {
                     callToHangup.disconnect();
                     return true;
@@ -1678,7 +1742,8 @@
     /**
      * Returns true if telecom supports adding another top-level call.
      */
-    boolean canAddCall() {
+    @VisibleForTesting
+    public boolean canAddCall() {
         boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
         if (!isDeviceProvisioned) {
@@ -1695,9 +1760,18 @@
             if (call.isEmergencyCall()) {
                 // We never support add call if one of the calls is an emergency call.
                 return false;
+            } else if (call.isExternalCall()) {
+                // External calls don't count.
+                continue;
             } else if (call.getParentCall() == null) {
                 count++;
             }
+            Bundle extras = call.getExtras();
+            if (extras != null) {
+                if (extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) {
+                    return false;
+                }
+            }
 
             // We do not check states for canAddCall. We treat disconnected calls the same
             // and wait until they are removed instead. If we didn't count disconnected calls,
@@ -1713,6 +1787,7 @@
                 return false;
             }
         }
+
         return true;
     }
 
@@ -1756,6 +1831,11 @@
         return getFirstCallWithState((Call) null, states);
     }
 
+    @VisibleForTesting
+    public PhoneNumberUtilsAdapter getPhoneNumberUtilsAdapter() {
+        return mPhoneNumberUtilsAdapter;
+    }
+
     /**
      * Returns the first call that it finds with the given states. The states are treated as having
      * priority order so that any call with the first state will be returned before any call with
@@ -1781,6 +1861,10 @@
                     continue;
                 }
 
+                if (call.isExternalCall()) {
+                    continue;
+                }
+
                 if (currentState == call.getState()) {
                     return call;
                 }
@@ -1846,6 +1930,7 @@
                 mConnectionServiceRepository,
                 mContactsAsyncHelper,
                 mCallerInfoAsyncQueryFactory,
+                mPhoneNumberUtilsAdapter,
                 null /* handle */,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -1863,6 +1948,12 @@
         call.setVideoProvider(parcelableConference.getVideoProvider());
         call.setStatusHints(parcelableConference.getStatusHints());
         call.putExtras(Call.SOURCE_CONNECTION_SERVICE, parcelableConference.getExtras());
+        // In case this Conference was added via a ConnectionManager, keep track of the original
+        // Connection ID as created by the originating ConnectionService.
+        Bundle extras = parcelableConference.getExtras();
+        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
+        }
 
         // TODO: Move this to be a part of addCall()
         call.addListener(this);
@@ -1899,7 +1990,16 @@
      * @param incomingCall Incoming call that has been rejected
      */
     private void rejectCallAndLog(Call incomingCall) {
-        incomingCall.reject(false, null);
+        if (incomingCall.getConnectionService() != null) {
+            // Only reject the call if it has not already been destroyed.  If a call ends while
+            // incoming call filtering is taking place, it is possible that the call has already
+            // been destroyed, and as such it will be impossible to send the reject to the
+            // associated ConnectionService.
+            incomingCall.reject(false, null);
+        } else {
+            Log.i(this, "rejectCallAndLog - call already destroyed.");
+        }
+
         // Since the call was not added to the list of calls, we have to call the missed
         // call notifier and the call logger manually.
         // Do we need missed call notification for direct to Voicemail calls?
@@ -1924,7 +2024,7 @@
         extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
                 SystemClock.elapsedRealtime());
 
-        updateCallsManagerState();
+        updateCanAddCall();
         // onCallAdded for calls which immediately take the foreground (like the first call).
         for (CallsManagerListener listener : mListeners) {
             if (Log.SYSTRACE_DEBUG) {
@@ -1956,7 +2056,7 @@
 
         // Only broadcast changes for calls that are being tracked.
         if (shouldNotify) {
-            updateCallsManagerState();
+            updateCanAddCall();
             for (CallsManagerListener listener : mListeners) {
                 if (Log.SYSTRACE_DEBUG) {
                     Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
@@ -1997,7 +2097,7 @@
             Trace.beginSection("onCallStateChanged");
             // Only broadcast state change for calls that are being tracked.
             if (mCalls.contains(call)) {
-                updateCallsManagerState();
+                updateCanAddCall();
                 for (CallsManagerListener listener : mListeners) {
                     if (Log.SYSTRACE_DEBUG) {
                         Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
@@ -2029,10 +2129,6 @@
         }
     }
 
-    private void updateCallsManagerState() {
-        updateCanAddCall();
-    }
-
     private boolean isPotentialMMICode(Uri handle) {
         return (handle != null && handle.getSchemeSpecificPart() != null
                 && handle.getSchemeSpecificPart().contains("#"));
@@ -2068,7 +2164,9 @@
         int count = 0;
         for (int state : states) {
             for (Call call : mCalls) {
-                if (call.getParentCall() == null && call.getState() == state) {
+                if (call.getParentCall() == null && call.getState() == state &&
+                        !call.isExternalCall()) {
+
                     count++;
                 }
             }
@@ -2119,7 +2217,7 @@
     }
 
     private boolean hasMaximumDialingCalls() {
-        return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(CallState.DIALING);
+        return MAXIMUM_DIALING_CALLS <= getNumCallsWithState(CallState.DIALING, CallState.PULLING);
     }
 
     /**
@@ -2341,6 +2439,8 @@
      * @return The new call.
      */
     Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
+        boolean isDowngradedConference = (connection.getConnectionProperties()
+                & Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE) != 0;
         Call call = new Call(
                 callId,
                 mContext,
@@ -2349,13 +2449,14 @@
                 mConnectionServiceRepository,
                 mContactsAsyncHelper,
                 mCallerInfoAsyncQueryFactory,
+                mPhoneNumberUtilsAdapter,
                 connection.getHandle() /* handle */,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
                 connection.getPhoneAccount(), /* targetPhoneAccountHandle */
                 Call.CALL_DIRECTION_UNDEFINED /* callDirection */,
                 false /* forceAttachToExistingConnection */,
-                false /* isConference */,
+                isDowngradedConference /* isConference */,
                 connection.getConnectTimeMillis() /* connectTimeMillis */);
 
         call.initAnalytics();
@@ -2367,14 +2468,44 @@
         call.setConnectionProperties(connection.getConnectionProperties());
         call.setCallerDisplayName(connection.getCallerDisplayName(),
                 connection.getCallerDisplayNamePresentation());
-
         call.addListener(this);
+
+        // In case this connection was added via a ConnectionManager, keep track of the original
+        // Connection ID as created by the originating ConnectionService.
+        Bundle extras = connection.getExtras();
+        if (extras != null && extras.containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+            call.setOriginalConnectionId(extras.getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID));
+        }
         addCall(call);
 
         return call;
     }
 
     /**
+     * Determines whether Telecom already knows about a Connection added via the
+     * {@link android.telecom.ConnectionService#addExistingConnection(PhoneAccountHandle,
+     * Connection)} API via a ConnectionManager.
+     *
+     * See {@link Connection#EXTRA_ORIGINAL_CONNECTION_ID}.
+     * @param originalConnectionId The new connection ID to check.
+     * @return {@code true} if this connection is already known by Telecom.
+     */
+    Call getAlreadyAddedConnection(String originalConnectionId) {
+        Optional<Call> existingCall = mCalls.stream()
+                .filter(call -> originalConnectionId.equals(call.getOriginalConnectionId()) ||
+                            originalConnectionId.equals(call.getId()))
+                .findFirst();
+
+        if (existingCall.isPresent()) {
+            Log.i(this, "isExistingConnectionAlreadyAdded - call %s already added with id %s",
+                    originalConnectionId, existingCall.get().getId());
+            return existingCall.get();
+        }
+
+        return null;
+    }
+
+    /**
      * @return A new unique telecom call Id.
      */
     private String getNextCallId() {
@@ -2407,6 +2538,10 @@
         }
     }
 
+    public TelecomSystem.SyncRoot getLock() {
+        return mLock;
+    }
+
     private void reloadMissedCallsOfUser(UserHandle userHandle) {
         mMissedCallNotifier.reloadFromDatabase(
                 mLock, this, mContactsAsyncHelper, mCallerInfoAsyncQueryFactory, userHandle);
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index 9bfa098..a4c76c1 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public void onVideoStateChanged(Call call) {
+    public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
     }
 
     @Override
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 338d1c3..f040134 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.app.AppOpsManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
@@ -67,7 +68,7 @@
         @Override
         public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
                 ParcelableConnection connection) {
-            Log.startSession("CSW.hCCC");
+            Log.startSession(Log.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -83,7 +84,7 @@
 
         @Override
         public void setActive(String callId) {
-            Log.startSession("CSW.sA");
+            Log.startSession(Log.Sessions.CSW_SET_ACTIVE);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -103,7 +104,7 @@
 
         @Override
         public void setRinging(String callId) {
-            Log.startSession("CSW.sR");
+            Log.startSession(Log.Sessions.CSW_SET_RINGING);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -141,7 +142,7 @@
 
         @Override
         public void setDialing(String callId) {
-            Log.startSession("CSW.sD");
+            Log.startSession(Log.Sessions.CSW_SET_DIALING);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -160,8 +161,26 @@
         }
 
         @Override
+        public void setPulling(String callId) {
+            Log.startSession(Log.Sessions.CSW_SET_PULLING);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setPulling %s", callId);
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.markCallAsPulling(call);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void setDisconnected(String callId, DisconnectCause disconnectCause) {
-            Log.startSession("CSW.sD");
+            Log.startSession(Log.Sessions.CSW_SET_DISCONNECTED);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -182,7 +201,7 @@
 
         @Override
         public void setOnHold(String callId) {
-            Log.startSession("CSW.sOH");
+            Log.startSession(Log.Sessions.CSW_SET_ON_HOLD);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -222,7 +241,7 @@
 
         @Override
         public void removeCall(String callId) {
-            Log.startSession("CSW.rC");
+            Log.startSession(Log.Sessions.CSW_REMOVE_CALL);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -284,7 +303,7 @@
 
         @Override
         public void setIsConferenced(String callId, String conferenceCallId) {
-            Log.startSession("CSW.sIC");
+            Log.startSession(Log.Sessions.CSW_SET_IS_CONFERENCED);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -324,20 +343,7 @@
                     // deliver the message anyway that they want. b/20530631.
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
-                        // Update extras so that event reaches to InCallUi and InCallUi
-                        // updates merge button.
-                        Bundle extras = new Bundle();
-                        extras.putBoolean("update", true);
-                        call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras);
-                        // Just refresh the connection capabilities so that the UI
-                        // is forced to reenable the merge button as the capability
-                        // is still on the connection. Note when b/20530631 is fixed, we need
-                        // to revisit this fix to remove this hacky way of unhiding the merge
-                        // button (side effect of reprocessing the capabilities) and plumb
-                        // the failure event all the way to InCallUI instead of stopping
-                        // it here. That way we can also handle the UI of notifying that
-                        // the merged has failed.
-                        call.setConnectionCapabilities(call.getConnectionCapabilities(), true);
+                        call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null);
                     } else {
                         Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId);
                     }
@@ -350,7 +356,7 @@
 
         @Override
         public void addConferenceCall(String callId, ParcelableConference parcelableConference) {
-            Log.startSession("CSW.aCC");
+            Log.startSession(Log.Sessions.CSW_ADD_CONFERENCE_CALL);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -359,6 +365,8 @@
                                 "call id %s", callId);
                         return;
                     }
+                    logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference,
+                            parcelableConference.getConnectionIds());
 
                     // Make sure that there's at least one valid call. For remote connections
                     // we'll get a add conference msg from both the remote connection service
@@ -376,16 +384,46 @@
                         return;
                     }
 
-                    // need to create a new Call
                     PhoneAccountHandle phAcc = null;
                     if (parcelableConference != null &&
                             parcelableConference.getPhoneAccount() != null) {
                         phAcc = parcelableConference.getPhoneAccount();
                     }
-                    Call conferenceCall = mCallsManager.createConferenceCall(callId,
-                            phAcc, parcelableConference);
-                    mCallIdMapper.addCall(conferenceCall, callId);
-                    conferenceCall.setConnectionService(ConnectionServiceWrapper.this);
+
+                    Bundle connectionExtras = parcelableConference.getExtras();
+
+                    String connectIdToCheck = null;
+                    if (connectionExtras != null && connectionExtras
+                            .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+                        // Conference was added via a connection manager, see if its original id is
+                        // known.
+                        connectIdToCheck = connectionExtras
+                                .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+                    } else {
+                        connectIdToCheck = callId;
+                    }
+
+                    Call conferenceCall;
+                    // Check to see if this conference has already been added.
+                    Call alreadyAddedConnection = mCallsManager
+                            .getAlreadyAddedConnection(connectIdToCheck);
+                    if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) {
+                        // We are currently attempting to add the conference via a connection mgr,
+                        // and the originating ConnectionService has already added it.  Instead of
+                        // making a new Telecom call, we will simply add it to the ID mapper here,
+                        // and replace the ConnectionService on the call.
+                        mCallIdMapper.addCall(alreadyAddedConnection, callId);
+                        alreadyAddedConnection.replaceConnectionService(
+                                ConnectionServiceWrapper.this);
+                        conferenceCall = alreadyAddedConnection;
+                    } else {
+                        // need to create a new Call
+                        Call newConferenceCall = mCallsManager.createConferenceCall(callId,
+                                phAcc, parcelableConference);
+                        mCallIdMapper.addCall(newConferenceCall, callId);
+                        newConferenceCall.setConnectionService(ConnectionServiceWrapper.this);
+                        conferenceCall = newConferenceCall;
+                    }
 
                     Log.d(this, "adding children to conference %s phAcc %s",
                             parcelableConference.getConnectionIds(), phAcc);
@@ -602,10 +640,11 @@
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    logIncoming("setConferenceableConnections %s %s", callId,
-                            conferenceableCallIds);
+
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
+                        logIncoming("setConferenceableConnections %s %s", callId,
+                                conferenceableCallIds);
                         List<Call> conferenceableCalls =
                                 new ArrayList<>(conferenceableCallIds.size());
                         for (String otherId : conferenceableCallIds) {
@@ -626,14 +665,68 @@
         @Override
         public void addExistingConnection(String callId, ParcelableConnection connection) {
             Log.startSession("CSW.aEC");
+            UserHandle userHandle = Binder.getCallingUserHandle();
+            // Check that the Calling Package matches PhoneAccountHandle's Component Package
+            PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount();
+            if (callingPhoneAccountHandle != null) {
+                mAppOpsManager.checkPackage(Binder.getCallingUid(),
+                        callingPhoneAccountHandle.getComponentName().getPackageName());
+            }
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    logIncoming("addExistingConnection  %s %s", callId, connection);
-                    Call existingCall = mCallsManager
-                            .createCallForExistingConnection(callId, connection);
-                    mCallIdMapper.addCall(existingCall, callId);
-                    existingCall.setConnectionService(ConnectionServiceWrapper.this);
+                    // Make sure that the PhoneAccount associated with the incoming
+                    // ParcelableConnection is in fact registered to Telecom and is being called
+                    // from the correct user.
+                    List<PhoneAccountHandle> accountHandles =
+                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/,
+                                    false /*includeDisabledAccounts*/, userHandle);
+                    PhoneAccountHandle phoneAccountHandle = null;
+                    for (PhoneAccountHandle accountHandle : accountHandles) {
+                        if(accountHandle.equals(callingPhoneAccountHandle)) {
+                            phoneAccountHandle = accountHandle;
+                        }
+                    }
+                    // Allow the Sim call manager account as well, even if its disabled.
+                    if (phoneAccountHandle == null && callingPhoneAccountHandle != null) {
+                        if (callingPhoneAccountHandle.equals(
+                                mPhoneAccountRegistrar.getSimCallManager(userHandle))) {
+                            phoneAccountHandle = callingPhoneAccountHandle;
+                        }
+                    }
+                    if (phoneAccountHandle != null) {
+                        logIncoming("addExistingConnection %s %s", callId, connection);
+
+                        Bundle connectionExtras = connection.getExtras();
+                        String connectIdToCheck = null;
+                        if (connectionExtras != null && connectionExtras
+                                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+                            connectIdToCheck = connectionExtras
+                                    .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+                        } else {
+                            connectIdToCheck = callId;
+                        }
+                        // Check to see if this Connection has already been added.
+                        Call alreadyAddedConnection = mCallsManager
+                                .getAlreadyAddedConnection(connectIdToCheck);
+
+                        if (alreadyAddedConnection != null
+                                && mCallIdMapper.getCall(callId) == null) {
+                            mCallIdMapper.addCall(alreadyAddedConnection, callId);
+                            alreadyAddedConnection
+                                    .replaceConnectionService(ConnectionServiceWrapper.this);
+                            return;
+                        }
+
+                        Call existingCall = mCallsManager
+                                .createCallForExistingConnection(callId, connection);
+                        mCallIdMapper.addCall(existingCall, callId);
+                        existingCall.setConnectionService(ConnectionServiceWrapper.this);
+                    } else {
+                        Log.e(this, new RemoteException("The PhoneAccount being used is not " +
+                                "currently registered with Telecom."), "Unable to " +
+                                "addExistingConnection.");
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -662,7 +755,7 @@
     }
 
     private final Adapter mAdapter = new Adapter();
-    private final CallIdMapper mCallIdMapper = new CallIdMapper();
+    private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId);
     private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
 
     private Binder2 mBinder = new Binder2();
@@ -670,6 +763,7 @@
     private final ConnectionServiceRepository mConnectionServiceRepository;
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final CallsManager mCallsManager;
+    private final AppOpsManager mAppOpsManager;
 
     /**
      * Creates a connection service.
@@ -697,6 +791,7 @@
         });
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mCallsManager = callsManager;
+        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
     }
 
     /** See {@link IConnectionService#addConnectionServiceAdapter}. */
@@ -710,6 +805,17 @@
         }
     }
 
+    /** See {@link IConnectionService#removeConnectionServiceAdapter}. */
+    private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
+        if (isServiceValid("removeConnectionServiceAdapter")) {
+            try {
+                logOutgoing("removeConnectionServiceAdapter %s", adapter);
+                mServiceInterface.removeConnectionServiceAdapter(adapter);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     /**
      * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
      */
@@ -1040,18 +1146,23 @@
     /** {@inheritDoc} */
     @Override
     protected void setServiceInterface(IBinder binder) {
-        if (binder == null) {
-            // We have lost our service connection. Notify the world that this service is done.
-            // We must notify the adapter before CallsManager. The adapter will force any pending
-            // outgoing calls to try the next service. This needs to happen before CallsManager
-            // tries to clean up any calls still associated with this service.
-            handleConnectionServiceDeath();
-            mCallsManager.handleConnectionServiceDeath(this);
-            mServiceInterface = null;
-        } else {
-            mServiceInterface = IConnectionService.Stub.asInterface(binder);
-            addConnectionServiceAdapter(mAdapter);
-        }
+        mServiceInterface = IConnectionService.Stub.asInterface(binder);
+        Log.v(this, "Adding Connection Service Adapter.");
+        addConnectionServiceAdapter(mAdapter);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void removeServiceInterface() {
+        Log.v(this, "Removing Connection Service Adapter.");
+        removeConnectionServiceAdapter(mAdapter);
+        // We have lost our service connection. Notify the world that this service is done.
+        // We must notify the adapter before CallsManager. The adapter will force any pending
+        // outgoing calls to try the next service. This needs to happen before CallsManager
+        // tries to clean up any calls still associated with this service.
+        handleConnectionServiceDeath();
+        mCallsManager.handleConnectionServiceDeath(this);
+        mServiceInterface = null;
     }
 
     private void handleCreateConnectionComplete(
@@ -1091,11 +1202,13 @@
     }
 
     private void logIncoming(String msg, Object... params) {
-        Log.d(this, "ConnectionService -> Telecom: " + msg, params);
+        Log.d(this, "ConnectionService -> Telecom[" + mComponentName.flattenToShortString() + "]: "
+                + msg, params);
     }
 
     private void logOutgoing(String msg, Object... params) {
-        Log.d(this, "Telecom -> ConnectionService: " + msg, params);
+        Log.d(this, "Telecom -> ConnectionService[" + mComponentName.flattenToShortString() + "]: "
+                + msg, params);
     }
 
     private void queryRemoteConnectionServices(final UserHandle userHandle,
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 7f9bbab..22ec3c6 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -96,6 +96,7 @@
     private final Context mContext;
     private CreateConnectionTimeout mTimeout;
     private ConnectionServiceWrapper mService;
+    private int mConnectionAttempt;
 
     @VisibleForTesting
     public CreateConnectionProcessor(
@@ -107,6 +108,7 @@
         mCallResponse = response;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mContext = context;
+        mConnectionAttempt = 0;
     }
 
     boolean isProcessingComplete() {
@@ -117,6 +119,10 @@
         return mTimeout != null && mTimeout.isCallTimedOut();
     }
 
+    public int getConnectionAttempt() {
+        return mConnectionAttempt;
+    }
+
     @VisibleForTesting
     public void process() {
         Log.v(this, "process");
@@ -127,7 +133,7 @@
                     mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
         }
         adjustAttemptsForConnectionManager();
-        adjustAttemptsForEmergency();
+        adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());
         mAttemptRecordIterator = mAttemptRecords.iterator();
         attemptNextPhoneAccount();
     }
@@ -200,6 +206,7 @@
                 Log.i(this, "Found no connection service for attempt %s", attempt);
                 attemptNextPhoneAccount();
             } else {
+                mConnectionAttempt++;
                 mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
                 mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
                 mCall.setConnectionService(mService);
@@ -288,7 +295,7 @@
 
     // If we are possibly attempting to call a local emergency number, ensure that the
     // plain PSTN connection services are listed, and nothing else.
-    private void adjustAttemptsForEmergency() {
+    private void adjustAttemptsForEmergency(PhoneAccountHandle preferredPAH) {
         if (mCall.isEmergencyCall()) {
             Log.i(this, "Emergency number detected");
             mAttemptRecords.clear();
@@ -307,16 +314,29 @@
                 allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount());
             }
 
-            // First, add SIM phone accounts which can place emergency calls.
+            // First, possibly add the SIM phone account that the user prefers
+            PhoneAccount preferredPA = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
+                    preferredPAH);
+            if (preferredPA != null &&
+                    preferredPA.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
+                    preferredPA.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                Log.i(this, "Will try PSTN account %s for emergency",
+                        preferredPA.getAccountHandle());
+                mAttemptRecords.add(new CallAttemptRecord(preferredPAH, preferredPAH));
+            }
+
+            // Next, add all SIM phone accounts which can place emergency calls.
+            TelephonyUtil.sortSimPhoneAccounts(mContext, allAccounts);
             for (PhoneAccount phoneAccount : allAccounts) {
                 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) &&
                         phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
-                    Log.i(this, "Will try PSTN account %s for emergency",
-                            phoneAccount.getAccountHandle());
-                    mAttemptRecords.add(
-                            new CallAttemptRecord(
-                                    phoneAccount.getAccountHandle(),
-                                    phoneAccount.getAccountHandle()));
+                    PhoneAccountHandle phoneAccountHandle = phoneAccount.getAccountHandle();
+                    // Don't add the preferred account since it has already been added previously.
+                    if (!phoneAccountHandle.equals(preferredPAH)) {
+                        Log.i(this, "Will try PSTN account %s for emergency", phoneAccountHandle);
+                        mAttemptRecords.add(new CallAttemptRecord(phoneAccountHandle,
+                                phoneAccountHandle));
+                    }
                 }
             }
 
@@ -419,7 +439,7 @@
     public void handleCreateConnectionFailure(DisconnectCause errorDisconnectCause) {
         // Failure of some sort; record the reasons for failure and try again if possible
         Log.d(CreateConnectionProcessor.this, "Connection failed: (%s)", errorDisconnectCause);
-        if(shouldFailCallIfConnectionManagerFails(errorDisconnectCause)){
+        if (shouldFailCallIfConnectionManagerFails(errorDisconnectCause)) {
             notifyCallConnectionFailure(errorDisconnectCause);
             return;
         }
diff --git a/src/com/android/server/telecom/CreateConnectionTimeout.java b/src/com/android/server/telecom/CreateConnectionTimeout.java
index 69cc129..8bc3373 100644
--- a/src/com/android/server/telecom/CreateConnectionTimeout.java
+++ b/src/com/android/server/telecom/CreateConnectionTimeout.java
@@ -40,7 +40,7 @@
 
     CreateConnectionTimeout(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
             ConnectionServiceWrapper service, Call call) {
-        super("CCT");
+        super("CCT", null /*lock*/);
         mContext = context;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mConnectionService = service;
@@ -114,7 +114,8 @@
         int state = call.getState();
         return state == CallState.NEW
             || state == CallState.CONNECTING
-            || state == CallState.DIALING;
+            || state == CallState.DIALING
+            || state == CallState.PULLING;
     }
 
     private long getTimeoutLengthMillis() {
diff --git a/src/com/android/server/telecom/HeadsetMediaButton.java b/src/com/android/server/telecom/HeadsetMediaButton.java
index a8bd354..af0ce13 100644
--- a/src/com/android/server/telecom/HeadsetMediaButton.java
+++ b/src/com/android/server/telecom/HeadsetMediaButton.java
@@ -135,6 +135,9 @@
     /** ${inheritDoc} */
     @Override
     public void onCallRemoved(Call call) {
+        if (call.isExternalCall()) {
+            return;
+        }
         if (!mCallsManager.hasAnyCalls()) {
             mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget();
         }
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index e18e3e6..8a6e1a0 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -47,7 +47,7 @@
     @Override
     public void answerCall(String callId, int videoState) {
         try {
-            Log.startSession("ICA.aC", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_ANSWER_CALL, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -70,7 +70,7 @@
     @Override
     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
         try {
-            Log.startSession("ICA.rC", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_REJECT_CALL, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -162,7 +162,7 @@
     @Override
     public void disconnectCall(String callId) {
         try {
-            Log.startSession("ICA.dC", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_DISCONNECT_CALL, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -185,7 +185,7 @@
     @Override
     public void holdCall(String callId) {
         try {
-            Log.startSession("ICA.hC", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_HOLD_CALL, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -207,7 +207,7 @@
     @Override
     public void unholdCall(String callId) {
         try {
-            Log.startSession("ICA.uC", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_UNHOLD_CALL, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -252,7 +252,7 @@
     @Override
     public void mute(boolean shouldMute) {
         try {
-            Log.startSession("ICA.m", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_MUTE, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -269,7 +269,7 @@
     @Override
     public void setAudioRoute(int route) {
         try {
-            Log.startSession("ICA.sAR", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -286,7 +286,7 @@
     @Override
     public void conference(String callId, String otherCallId) {
         try {
-            Log.startSession("ICA.c", mOwnerComponentName);
+            Log.startSession(Log.Sessions.ICA_CONFERENCE, mOwnerComponentName);
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index e14547a..33cf329 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -78,6 +78,60 @@
         public void dump(IndentingPrintWriter pw) {}
     }
 
+    private class InCallServiceInfo {
+        private final ComponentName mComponentName;
+        private boolean mIsExternalCallsSupported;
+        private final int mType;
+
+        public InCallServiceInfo(ComponentName componentName,
+                boolean isExternalCallsSupported,
+                int type) {
+            mComponentName = componentName;
+            mIsExternalCallsSupported = isExternalCallsSupported;
+            mType = type;
+        }
+
+        public ComponentName getComponentName() {
+            return mComponentName;
+        }
+
+        public boolean isExternalCallsSupported() {
+            return mIsExternalCallsSupported;
+        }
+
+        public int getType() {
+            return mType;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            InCallServiceInfo that = (InCallServiceInfo) o;
+
+            if (mIsExternalCallsSupported != that.mIsExternalCallsSupported) {
+                return false;
+            }
+            return mComponentName.equals(that.mComponentName);
+
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mComponentName, mIsExternalCallsSupported);
+        }
+
+        @Override
+        public String toString() {
+            return "[" + mComponentName + " supportsExternal? " + mIsExternalCallsSupported + "]";
+        }
+    }
+
     private class InCallServiceBindingConnection extends InCallServiceConnection {
 
         private final ServiceConnection mServiceConnection = new ServiceConnection() {
@@ -113,12 +167,12 @@
             }
         };
 
-        private final ComponentName mComponentName;
+        private final InCallServiceInfo mInCallServiceInfo;
         private boolean mIsConnected = false;
         private boolean mIsBound = false;
 
-        public InCallServiceBindingConnection(ComponentName componentName) {
-            mComponentName = componentName;
+        public InCallServiceBindingConnection(InCallServiceInfo info) {
+            mInCallServiceInfo = info;
         }
 
         @Override
@@ -129,7 +183,7 @@
             }
 
             Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
-            intent.setComponent(mComponentName);
+            intent.setComponent(mInCallServiceInfo.getComponentName());
             if (call != null && !call.isIncoming() && !call.isExternalCall()){
                 intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
                         call.getIntentExtras());
@@ -137,7 +191,7 @@
                         call.getTargetPhoneAccount());
             }
 
-            Log.i(this, "Attempting to bind to InCall %s, with %s", mComponentName, intent);
+            Log.i(this, "Attempting to bind to InCall %s, with %s", mInCallServiceInfo, intent);
             mIsConnected = true;
             if (!mContext.bindServiceAsUser(intent, mServiceConnection,
                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE |
@@ -147,6 +201,12 @@
                 mIsConnected = false;
             }
 
+            if (call != null && mIsConnected) {
+                call.getAnalytics().addInCallService(
+                        mInCallServiceInfo.getComponentName().flattenToShortString(),
+                        mInCallServiceInfo.getType());
+            }
+
             return mIsConnected;
         }
 
@@ -169,10 +229,10 @@
 
         protected void onConnected(IBinder service) {
             boolean shouldRemainConnected =
-                    InCallController.this.onConnected(mComponentName, service);
+                    InCallController.this.onConnected(mInCallServiceInfo, service);
             if (!shouldRemainConnected) {
                 // Sometimes we can opt to disconnect for certain reasons, like if the
-                // InCallService rejected our intialization step, or the calls went away
+                // InCallService rejected our initialization step, or the calls went away
                 // in the time it took us to bind to the InCallService. In such cases, we go
                 // ahead and disconnect ourselves.
                 disconnect();
@@ -180,7 +240,7 @@
         }
 
         protected void onDisconnected() {
-            InCallController.this.onDisconnected(mComponentName);
+            InCallController.this.onDisconnected(mInCallServiceInfo.getComponentName());
             disconnect();  // Unbind explicitly if we get disconnected.
             if (mListener != null) {
                 mListener.onDisconnect(InCallServiceBindingConnection.this);
@@ -215,8 +275,9 @@
         };
 
         public EmergencyInCallServiceConnection(
-                ComponentName componentName, InCallServiceConnection subConnection) {
-            super(componentName);
+                InCallServiceInfo info, InCallServiceConnection subConnection) {
+
+            super(info);
             mSubConnection = subConnection;
             if (mSubConnection != null) {
                 mSubConnection.setListener(mSubListener);
@@ -500,7 +561,7 @@
         }
 
         @Override
-        public void onVideoStateChanged(Call call) {
+        public void onVideoStateChanged(Call call, int previousVideoState, int newVideoState) {
             updateCall(call);
         }
 
@@ -536,14 +597,14 @@
     private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4;
 
     /** The in-call app implementations, see {@link IInCallService}. */
-    private final Map<ComponentName, IInCallService> mInCallServices = new ArrayMap<>();
+    private final Map<InCallServiceInfo, IInCallService> mInCallServices = new ArrayMap<>();
 
     /**
      * The {@link ComponentName} of the bound In-Call UI Service.
      */
     private ComponentName mInCallUIComponentName;
 
-    private final CallIdMapper mCallIdMapper = new CallIdMapper();
+    private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
 
     /** The {@link ComponentName} of the default InCall UI. */
     private final ComponentName mSystemInCallComponentName;
@@ -553,17 +614,19 @@
     private final CallsManager mCallsManager;
     private final SystemStateProvider mSystemStateProvider;
     private final DefaultDialerManagerAdapter mDefaultDialerAdapter;
+    private final Timeouts.Adapter mTimeoutsAdapter;
     private CarSwappingInCallServiceConnection mInCallServiceConnection;
     private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
 
     public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
             SystemStateProvider systemStateProvider,
-            DefaultDialerManagerAdapter defaultDialerAdapter) {
+            DefaultDialerManagerAdapter defaultDialerAdapter, Timeouts.Adapter timeoutsAdapter) {
         mContext = context;
         mLock = lock;
         mCallsManager = callsManager;
         mSystemStateProvider = systemStateProvider;
         mDefaultDialerAdapter = defaultDialerAdapter;
+        mTimeoutsAdapter = timeoutsAdapter;
 
         Resources resources = mContext.getResources();
         mSystemInCallComponentName = new ComponentName(
@@ -584,16 +647,26 @@
             // Track the call if we don't already know about it.
             addCall(call);
 
-            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
-                ComponentName componentName = entry.getKey();
+            List<ComponentName> componentsUpdated = new ArrayList<>();
+            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
+                InCallServiceInfo info = entry.getKey();
+
+                if (call.isExternalCall() && !info.isExternalCallsSupported()) {
+                    continue;
+                }
+
+                componentsUpdated.add(info.getComponentName());
                 IInCallService inCallService = entry.getValue();
+
                 ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
-                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar());
+                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
+                        info.isExternalCallsSupported());
                 try {
                     inCallService.addCall(parcelableCall);
                 } catch (RemoteException ignored) {
                 }
             }
+            Log.i(this, "Call added to components: %s", componentsUpdated);
         }
     }
 
@@ -605,17 +678,15 @@
              *  give them enough time to process all the pending messages.
              */
             Handler handler = new Handler(Looper.getMainLooper());
-            handler.postDelayed(new Runnable("ICC.oCR") {
+            handler.postDelayed(new Runnable("ICC.oCR", mLock) {
                 @Override
                 public void loggedRun() {
-                    synchronized (mLock) {
-                        // Check again to make sure there are no active calls.
-                        if (mCallsManager.getCalls().isEmpty()) {
-                            unbindFromServices();
-                        }
+                    // Check again to make sure there are no active calls.
+                    if (mCallsManager.getCalls().isEmpty()) {
+                        unbindFromServices();
                     }
                 }
-            }.prepare(), Timeouts.getCallRemoveUnbindInCallServicesDelay(
+            }.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
                             mContext.getContentResolver()));
         }
         call.removeListener(mCallListener);
@@ -625,8 +696,62 @@
     @Override
     public void onExternalCallChanged(Call call, boolean isExternalCall) {
         Log.i(this, "onExternalCallChanged: %s -> %b", call, isExternalCall);
-        // TODO: Need to add logic which ensures changes to a call's external state adds or removes
-        // the call from the InCallServices depending on whether they support external calls.
+
+        List<ComponentName> componentsUpdated = new ArrayList<>();
+        if (!isExternalCall) {
+            // The call was external but it is no longer external.  We must now add it to any
+            // InCallServices which do not support external calls.
+            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
+                InCallServiceInfo info = entry.getKey();
+
+                if (info.isExternalCallsSupported()) {
+                    // For InCallServices which support external calls, the call will have already
+                    // been added to the connection service, so we do not need to add it again.
+                    continue;
+                }
+
+                componentsUpdated.add(info.getComponentName());
+                IInCallService inCallService = entry.getValue();
+
+                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
+                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
+                        info.isExternalCallsSupported());
+                try {
+                    inCallService.addCall(parcelableCall);
+                } catch (RemoteException ignored) {
+                }
+            }
+            Log.i(this, "Previously external call added to components: %s", componentsUpdated);
+        } else {
+            // The call was regular but it is now external.  We must now remove it from any
+            // InCallServices which do not support external calls.
+            // Remove the call by sending a call update indicating the call was disconnected.
+            ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
+                    call,
+                    false /* includeVideoProvider */,
+                    mCallsManager.getPhoneAccountRegistrar(),
+                    false /* supportsExternalCalls */,
+                    android.telecom.Call.STATE_DISCONNECTED /* overrideState */);
+
+            Log.i(this, "Removing external call %s ==> %s", call, parcelableCall);
+            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
+                InCallServiceInfo info = entry.getKey();
+                if (info.isExternalCallsSupported()) {
+                    // For InCallServices which support external calls, we do not need to remove
+                    // the call.
+                    continue;
+                }
+
+                componentsUpdated.add(info.getComponentName());
+                IInCallService inCallService = entry.getValue();
+
+                try {
+                    inCallService.updateCall(parcelableCall);
+                } catch (RemoteException ignored) {
+                }
+            }
+            Log.i(this, "External call removed from components: %s", componentsUpdated);
+        }
     }
 
     @Override
@@ -716,6 +841,10 @@
         if (!mInCallServices.isEmpty()) {
             for (IInCallService inCallService : mInCallServices.values()) {
                 try {
+                    Log.i(this, "notifyConnectionEvent {Call: %s, Event: %s, Extras:[%s]}",
+                            (call != null ? call.toString() :"null"),
+                            (event != null ? event : "null") ,
+                            (extras != null ? extras.toString() : "null"));
                     inCallService.onConnectionEvent(mCallIdMapper.getCallId(call), event, extras);
                 } catch (RemoteException ignored) {
                 }
@@ -728,10 +857,14 @@
      */
     private void unbindFromServices() {
         if (isBoundToServices()) {
-            mInCallServiceConnection.disconnect();
-            mInCallServiceConnection = null;
-            mNonUIInCallServiceConnections.disconnect();
-            mNonUIInCallServiceConnections = null;
+            if (mInCallServiceConnection != null) {
+                mInCallServiceConnection.disconnect();
+                mInCallServiceConnection = null;
+            }
+            if (mNonUIInCallServiceConnections != null) {
+                mNonUIInCallServiceConnections.disconnect();
+                mNonUIInCallServiceConnections = null;
+            }
         }
     }
 
@@ -744,23 +877,25 @@
     @VisibleForTesting
     public void bindToServices(Call call) {
         InCallServiceConnection dialerInCall = null;
-        ComponentName defaultDialerComponent = getDefaultDialerComponent();
-        Log.i(this, "defaultDialer: " + defaultDialerComponent);
-        if (defaultDialerComponent != null &&
-                !defaultDialerComponent.equals(mSystemInCallComponentName)) {
-            dialerInCall = new InCallServiceBindingConnection(defaultDialerComponent);
+        InCallServiceInfo defaultDialerComponentInfo = getDefaultDialerComponent();
+        Log.i(this, "defaultDialer: " + defaultDialerComponentInfo);
+        if (defaultDialerComponentInfo != null &&
+                !defaultDialerComponentInfo.getComponentName().equals(mSystemInCallComponentName)) {
+            dialerInCall = new InCallServiceBindingConnection(defaultDialerComponentInfo);
         }
         Log.i(this, "defaultDialer: " + dialerInCall);
 
+        InCallServiceInfo systemInCallInfo =  getInCallServiceComponent(mSystemInCallComponentName,
+                IN_CALL_SERVICE_TYPE_SYSTEM_UI);
         EmergencyInCallServiceConnection systemInCall =
-                new EmergencyInCallServiceConnection(mSystemInCallComponentName, dialerInCall);
+                new EmergencyInCallServiceConnection(systemInCallInfo, dialerInCall);
         systemInCall.setHasEmergency(mCallsManager.hasEmergencyCall());
 
         InCallServiceConnection carModeInCall = null;
-        ComponentName carModeComponent = getCarModeComponent();
-        if (carModeComponent != null &&
-                !carModeComponent.equals(mSystemInCallComponentName)) {
-            carModeInCall = new InCallServiceBindingConnection(carModeComponent);
+        InCallServiceInfo carModeComponentInfo = getCarModeComponent();
+        if (carModeComponentInfo != null &&
+                !carModeComponentInfo.getComponentName().equals(mSystemInCallComponentName)) {
+            carModeInCall = new InCallServiceBindingConnection(carModeComponentInfo);
         }
 
         mInCallServiceConnection =
@@ -768,18 +903,17 @@
         mInCallServiceConnection.setCarMode(shouldUseCarModeUI());
         mInCallServiceConnection.connect(call);
 
-
-        List<ComponentName> nonUIInCallComponents =
-                getInCallServiceComponents(null, IN_CALL_SERVICE_TYPE_NON_UI);
+        List<InCallServiceInfo> nonUIInCallComponents =
+                getInCallServiceComponents(IN_CALL_SERVICE_TYPE_NON_UI);
         List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>();
-        for (ComponentName componentName : nonUIInCallComponents) {
-            nonUIInCalls.add(new InCallServiceBindingConnection(componentName));
+        for (InCallServiceInfo serviceInfo : nonUIInCallComponents) {
+            nonUIInCalls.add(new InCallServiceBindingConnection(serviceInfo));
         }
         mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
         mNonUIInCallServiceConnections.connect(call);
     }
 
-    private ComponentName getDefaultDialerComponent() {
+    private InCallServiceInfo getDefaultDialerComponent() {
         String packageName = mDefaultDialerAdapter.getDefaultDialerApplication(
                 mContext, mCallsManager.getCurrentUserHandle().getIdentifier());
         Log.d(this, "Default Dialer package: " + packageName);
@@ -787,25 +921,57 @@
         return getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI);
     }
 
-    private ComponentName getCarModeComponent() {
-        return getInCallServiceComponent(null, IN_CALL_SERVICE_TYPE_CAR_MODE_UI);
+    private InCallServiceInfo getCarModeComponent() {
+        // Seems strange to cast a String to null, but the signatures of getInCallServiceComponent
+        // differ in the types of the first parameter, and passing in null is inherently ambiguous.
+        return getInCallServiceComponent((String) null, IN_CALL_SERVICE_TYPE_CAR_MODE_UI);
     }
 
-    private ComponentName getInCallServiceComponent(String packageName, int type) {
-        List<ComponentName> list = getInCallServiceComponents(packageName, type);
+    private InCallServiceInfo getInCallServiceComponent(ComponentName componentName, int type) {
+        List<InCallServiceInfo> list = getInCallServiceComponents(componentName, type);
+        if (list != null && !list.isEmpty()) {
+            return list.get(0);
+        } else {
+            // Last Resort: Try to bind to the ComponentName given directly.
+            Log.e(this, new Exception(), "Package Manager could not find ComponentName: "
+                    + componentName +". Trying to bind anyway.");
+            return new InCallServiceInfo(componentName, false, type);
+        }
+    }
+
+    private InCallServiceInfo getInCallServiceComponent(String packageName, int type) {
+        List<InCallServiceInfo> list = getInCallServiceComponents(packageName, type);
         if (list != null && !list.isEmpty()) {
             return list.get(0);
         }
         return null;
     }
 
-    private List<ComponentName> getInCallServiceComponents(String packageName, int type) {
-        List<ComponentName> retval = new LinkedList<>();
+    private List<InCallServiceInfo> getInCallServiceComponents(int type) {
+        return getInCallServiceComponents(null, null, type);
+    }
+
+    private List<InCallServiceInfo> getInCallServiceComponents(String packageName, int type) {
+        return getInCallServiceComponents(packageName, null, type);
+    }
+
+    private List<InCallServiceInfo> getInCallServiceComponents(ComponentName componentName,
+            int type) {
+        return getInCallServiceComponents(null, componentName, type);
+    }
+
+    private List<InCallServiceInfo> getInCallServiceComponents(String packageName,
+            ComponentName componentName, int requestedType) {
+
+        List<InCallServiceInfo> retval = new LinkedList<>();
 
         Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
         if (packageName != null) {
             serviceIntent.setPackage(packageName);
         }
+        if (componentName != null) {
+            serviceIntent.setComponent(componentName);
+        }
 
         PackageManager packageManager = mContext.getPackageManager();
         for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
@@ -815,8 +981,15 @@
             ServiceInfo serviceInfo = entry.serviceInfo;
 
             if (serviceInfo != null) {
-                if (type == 0 || type == getInCallServiceType(entry.serviceInfo, packageManager)) {
-                    retval.add(new ComponentName(serviceInfo.packageName, serviceInfo.name));
+                boolean isExternalCallsSupported = serviceInfo.metaData != null &&
+                        serviceInfo.metaData.getBoolean(
+                                TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, false);
+                if (requestedType == 0 || requestedType == getInCallServiceType(entry.serviceInfo,
+                        packageManager)) {
+
+                    retval.add(new InCallServiceInfo(
+                            new ComponentName(serviceInfo.packageName, serviceInfo.name),
+                            isExternalCallsSupported, requestedType));
                 }
             }
         }
@@ -862,7 +1035,6 @@
             return IN_CALL_SERVICE_TYPE_CAR_MODE_UI;
         }
 
-
         // Check to see that it is the default dialer package
         boolean isDefaultDialerPackage = Objects.equals(serviceInfo.packageName,
                 mDefaultDialerAdapter.getDefaultDialerApplication(
@@ -900,16 +1072,16 @@
      * this class and in-call app by sending the first update to in-call app. This method is
      * called after a successful binding connection is established.
      *
-     * @param componentName The service {@link ComponentName}.
+     * @param info Info about the service, including its {@link ComponentName}.
      * @param service The {@link IInCallService} implementation.
      * @return True if we successfully connected.
      */
-    private boolean onConnected(ComponentName componentName, IBinder service) {
-        Trace.beginSection("onConnected: " + componentName);
-        Log.i(this, "onConnected to %s", componentName);
+    private boolean onConnected(InCallServiceInfo info, IBinder service) {
+        Trace.beginSection("onConnected: " + info.getComponentName());
+        Log.i(this, "onConnected to %s", info.getComponentName());
 
         IInCallService inCallService = IInCallService.Stub.asInterface(service);
-        mInCallServices.put(componentName, inCallService);
+        mInCallServices.put(info, inCallService);
 
         try {
             inCallService.setInCallAdapter(
@@ -917,7 +1089,7 @@
                             mCallsManager,
                             mCallIdMapper,
                             mLock,
-                            componentName.getPackageName()));
+                            info.getComponentName().getPackageName()));
         } catch (RemoteException e) {
             Log.e(this, e, "Failed to set the in-call adapter.");
             Trace.endSection();
@@ -926,28 +1098,32 @@
 
         // Upon successful connection, send the state of the world to the service.
         List<Call> calls = orderCallsWithChildrenFirst(mCallsManager.getCalls());
-        if (!calls.isEmpty()) {
-            Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
-                    componentName);
-            for (Call call : calls) {
-                try {
-                    // Track the call if we don't already know about it.
-                    addCall(call);
-                    inCallService.addCall(ParcelableCallUtils.toParcelableCall(
-                            call,
-                            true /* includeVideoProvider */,
-                            mCallsManager.getPhoneAccountRegistrar()));
-                } catch (RemoteException ignored) {
-                }
-            }
+        Log.i(this, "Adding %s calls to InCallService after onConnected: %s, including external " +
+                "calls", calls.size(), info.getComponentName());
+        int numCallsSent = 0;
+        for (Call call : calls) {
             try {
-                inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
-                inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
+                if (call.isExternalCall() && !info.isExternalCallsSupported()) {
+                    continue;
+                }
+
+                // Track the call if we don't already know about it.
+                addCall(call);
+                numCallsSent += 1;
+                inCallService.addCall(ParcelableCallUtils.toParcelableCall(
+                        call,
+                        true /* includeVideoProvider */,
+                        mCallsManager.getPhoneAccountRegistrar(),
+                        info.isExternalCallsSupported()));
             } catch (RemoteException ignored) {
             }
-        } else {
-            return false;
         }
+        try {
+            inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
+            inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
+        } catch (RemoteException ignored) {
+        }
+        Log.i(this, "%s calls sent to InCallService.", numCallsSent);
         Trace.endSection();
         mCallsManager.setDsdaAdapter();
         return true;
@@ -982,16 +1158,23 @@
      */
     private void updateCall(Call call, boolean videoProviderChanged) {
         if (!mInCallServices.isEmpty()) {
-            ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
-                    call,
-                    videoProviderChanged /* includeVideoProvider */,
-                    mCallsManager.getPhoneAccountRegistrar());
-            Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall);
+            Log.i(this, "Sending updateCall %s", call);
             List<ComponentName> componentsUpdated = new ArrayList<>();
-            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
-                ComponentName componentName = entry.getKey();
+            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
+                InCallServiceInfo info = entry.getKey();
+                if (call.isExternalCall() && !info.isExternalCallsSupported()) {
+                    continue;
+                }
+
+                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
+                        call,
+                        videoProviderChanged /* includeVideoProvider */,
+                        mCallsManager.getPhoneAccountRegistrar(),
+                        info.isExternalCallsSupported());
+                ComponentName componentName = info.getComponentName();
                 IInCallService inCallService = entry.getValue();
                 componentsUpdated.add(componentName);
+
                 try {
                     inCallService.updateCall(parcelableCall);
                 } catch (RemoteException ignored) {
@@ -1024,8 +1207,8 @@
     public void dump(IndentingPrintWriter pw) {
         pw.println("mInCallServices (InCalls registered):");
         pw.increaseIndent();
-        for (ComponentName componentName : mInCallServices.keySet()) {
-            pw.println(componentName);
+        for (InCallServiceInfo info : mInCallServices.keySet()) {
+            pw.println(info);
         }
         pw.decreaseIndent();
 
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index d6082d0..a916a37 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -280,7 +280,12 @@
             mSession = Log.createSubsession();
         }
 
-        start();
+        super.start();
+    }
+
+    @Override
+    public void start() {
+        Log.w(this, "Do not call the start method directly; use startTone instead.");
     }
 
     /**
@@ -299,15 +304,13 @@
 
     private void cleanUpTonePlayer() {
         // Release focus on the main thread.
-        mMainThreadHandler.post(new Runnable("ICTP.cUTP") {
+        mMainThreadHandler.post(new Runnable("ICTP.cUTP", mLock) {
             @Override
             public void loggedRun() {
-                synchronized (mLock) {
-                    if (sTonesPlaying == 0) {
-                        Log.wtf(this, "Over-releasing focus for tone player.");
-                    } else if (--sTonesPlaying == 0) {
-                        mCallAudioManager.setIsTonePlaying(false);
-                    }
+                if (sTonesPlaying == 0) {
+                    Log.wtf(this, "Over-releasing focus for tone player.");
+                } else if (--sTonesPlaying == 0) {
+                    mCallAudioManager.setIsTonePlaying(false);
                 }
             }
         }.prepare());
diff --git a/src/com/android/server/telecom/InCallWakeLockController.java b/src/com/android/server/telecom/InCallWakeLockController.java
index ffa6a3f..0de8123 100644
--- a/src/com/android/server/telecom/InCallWakeLockController.java
+++ b/src/com/android/server/telecom/InCallWakeLockController.java
@@ -37,16 +37,25 @@
 
     @Override
     public void onCallAdded(Call call) {
+        if (call.isExternalCall()) {
+            return;
+        }
         handleWakeLock();
     }
 
     @Override
     public void onCallRemoved(Call call) {
+        if (call.isExternalCall()) {
+            return;
+        }
         handleWakeLock();
     }
 
     @Override
     public void onCallStateChanged(Call call, int oldState, int newState) {
+        if (call.isExternalCall()) {
+            return;
+        }
         handleWakeLock();
     }
 
diff --git a/src/com/android/server/telecom/InterruptionFilterProxy.java b/src/com/android/server/telecom/InterruptionFilterProxy.java
new file mode 100644
index 0000000..434c341
--- /dev/null
+++ b/src/com/android/server/telecom/InterruptionFilterProxy.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom;
+
+/**
+ * Defines common functionality used by {@link CallAudioRouteStateMachine} to control the current
+ * interruption filter for notifications while in a call.  Used to ensure that this functionality
+ * can be mocked out in unit tests.
+ */
+public interface InterruptionFilterProxy {
+    void setInterruptionFilter(int interruptionFilter);
+    int getCurrentInterruptionFilter();
+}
diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java
index fda21fd..2282ff0 100644
--- a/src/com/android/server/telecom/Log.java
+++ b/src/com/android/server/telecom/Log.java
@@ -22,6 +22,7 @@
 import android.os.Looper;
 import android.os.AsyncTask;
 import android.telecom.PhoneAccount;
+import android.telecom.TimedEvent;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Base64;
@@ -34,7 +35,9 @@
 import java.security.NoSuchAlgorithmException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.IllegalFormatException;
@@ -52,16 +55,61 @@
 @VisibleForTesting
 public class Log {
 
+    public static final class Sessions {
+        public static final String ICA_ANSWER_CALL = "ICA.aC";
+        public static final String ICA_REJECT_CALL = "ICA.rC";
+        public static final String ICA_DISCONNECT_CALL = "ICA.dC";
+        public static final String ICA_HOLD_CALL = "ICA.hC";
+        public static final String ICA_UNHOLD_CALL = "ICA.uC";
+        public static final String ICA_MUTE = "ICA.m";
+        public static final String ICA_SET_AUDIO_ROUTE = "ICA.sAR";
+        public static final String ICA_CONFERENCE = "ICA.c";
+        public static final String CSW_HANDLE_CREATE_CONNECTION_COMPLETE = "CSW.hCCC";
+        public static final String CSW_SET_ACTIVE = "CSW.sA";
+        public static final String CSW_SET_RINGING = "CSW.sR";
+        public static final String CSW_SET_DIALING = "CSW.sD";
+        public static final String CSW_SET_PULLING = "CSW.sP";
+        public static final String CSW_SET_DISCONNECTED = "CSW.sDc";
+        public static final String CSW_SET_ON_HOLD = "CSW.sOH";
+        public static final String CSW_REMOVE_CALL = "CSW.rC";
+        public static final String CSW_SET_IS_CONFERENCED = "CSW.sIC";
+        public static final String CSW_ADD_CONFERENCE_CALL = "CSW.aCC";
+    }
+
     /**
      * Stores the various events associated with {@link Call}s. Also stores all request-response
      * pairs amongst the events.
      */
     public final static class Events {
+        public static class TimedEventPair {
+            private static final long DEFAULT_TIMEOUT = 3000L;
+
+            String mRequest;
+            String mResponse;
+            String mName;
+            long mTimeoutMillis = DEFAULT_TIMEOUT;
+
+            public TimedEventPair(String request, String response,
+                    String name) {
+                this.mRequest = request;
+                this.mResponse = response;
+                this.mName = name;
+            }
+
+            public TimedEventPair(String request, String response,
+                    String name, long timeoutMillis) {
+                this.mRequest = request;
+                this.mResponse = response;
+                this.mName = name;
+                this.mTimeoutMillis = timeoutMillis;
+            }
+        }
+
         public static final String CREATED = "CREATED";
         public static final String DESTROYED = "DESTROYED";
-        public static final String SET_NEW = "SET_NEW";
         public static final String SET_CONNECTING = "SET_CONNECTING";
         public static final String SET_DIALING = "SET_DIALING";
+        public static final String SET_PULLING = "SET_PULLING";
         public static final String SET_ACTIVE = "SET_ACTIVE";
         public static final String SET_HOLD = "SET_HOLD";
         public static final String SET_RINGING = "SET_RINGING";
@@ -84,13 +132,18 @@
         public static final String BIND_CS = "BIND_CS";
         public static final String CS_BOUND = "CS_BOUND";
         public static final String CONFERENCE_WITH = "CONF_WITH";
-        public static final String SPLIT_CONFERENCE = "CONF_SPLIT";
+        public static final String SPLIT_FROM_CONFERENCE = "CONF_SPLIT";
         public static final String SWAP = "SWAP";
         public static final String ADD_CHILD = "ADD_CHILD";
         public static final String REMOVE_CHILD = "REMOVE_CHILD";
         public static final String SET_PARENT = "SET_PARENT";
         public static final String MUTE = "MUTE";
+        public static final String UNMUTE = "UNMUTE";
         public static final String AUDIO_ROUTE = "AUDIO_ROUTE";
+        public static final String AUDIO_ROUTE_EARPIECE = "AUDIO_ROUTE_EARPIECE";
+        public static final String AUDIO_ROUTE_HEADSET = "AUDIO_ROUTE_HEADSET";
+        public static final String AUDIO_ROUTE_BT = "AUDIO_ROUTE_BT";
+        public static final String AUDIO_ROUTE_SPEAKER = "AUDIO_ROUTE_SPEAKER";
         public static final String ERROR_LOG = "ERROR";
         public static final String USER_LOG_MARK = "USER_LOG_MARK";
         public static final String SILENCE = "SILENCE";
@@ -107,29 +160,71 @@
         public static final String FILTERING_TIMED_OUT = "FILTERING_TIMED_OUT";
         public static final String REMOTELY_HELD = "REMOTELY_HELD";
         public static final String REMOTELY_UNHELD = "REMOTELY_UNHELD";
-        public static final String PULL = "PULL";
+        public static final String REQUEST_PULL = "PULL";
         public static final String INFO = "INFO";
+        public static final String VIDEO_STATE_CHANGED = "VIDEO_STATE_CHANGED";
+        public static final String RECEIVE_VIDEO_REQUEST = "RECEIVE_VIDEO_REQUEST";
+        public static final String RECEIVE_VIDEO_RESPONSE = "RECEIVE_VIDEO_RESPONSE";
+        public static final String SEND_VIDEO_REQUEST = "SEND_VIDEO_REQUEST";
+        public static final String SEND_VIDEO_RESPONSE = "SEND_VIDEO_RESPONSE";
+        public static final String IS_EXTERNAL = "IS_EXTERNAL";
+        public static final String PROPERTY_CHANGE = "PROPERTY_CHANGE";
+        public static final String CAPABILITY_CHANGE = "CAPABILITY_CHANGE";
+        public static final String CONNECTION_EVENT = "CONNECTION_EVENT";
+
+        public static class Timings {
+            public static final String ACCEPT_TIMING = "accept";
+            public static final String REJECT_TIMING = "reject";
+            public static final String DISCONNECT_TIMING = "disconnect";
+            public static final String HOLD_TIMING = "hold";
+            public static final String UNHOLD_TIMING = "unhold";
+            public static final String OUTGOING_TIME_TO_DIALING_TIMING = "outgoing_time_to_dialing";
+            public static final String BIND_CS_TIMING = "bind_cs";
+            public static final String SCREENING_COMPLETED_TIMING = "screening_completed";
+            public static final String DIRECT_TO_VM_FINISHED_TIMING = "direct_to_vm_finished";
+            public static final String BLOCK_CHECK_FINISHED_TIMING = "block_check_finished";
+            public static final String FILTERING_COMPLETED_TIMING = "filtering_completed";
+            public static final String FILTERING_TIMED_OUT_TIMING = "filtering_timed_out";
+
+            private static final TimedEventPair[] sTimedEvents = {
+                    new TimedEventPair(REQUEST_ACCEPT, SET_ACTIVE, ACCEPT_TIMING),
+                    new TimedEventPair(REQUEST_REJECT, SET_DISCONNECTED, REJECT_TIMING),
+                    new TimedEventPair(REQUEST_DISCONNECT, SET_DISCONNECTED, DISCONNECT_TIMING),
+                    new TimedEventPair(REQUEST_HOLD, SET_HOLD, HOLD_TIMING),
+                    new TimedEventPair(REQUEST_UNHOLD, SET_ACTIVE, UNHOLD_TIMING),
+                    new TimedEventPair(START_CONNECTION, SET_DIALING,
+                            OUTGOING_TIME_TO_DIALING_TIMING),
+                    new TimedEventPair(BIND_CS, CS_BOUND, BIND_CS_TIMING),
+                    new TimedEventPair(SCREENING_SENT, SCREENING_COMPLETED,
+                            SCREENING_COMPLETED_TIMING),
+                    new TimedEventPair(DIRECT_TO_VM_INITIATED, DIRECT_TO_VM_FINISHED,
+                            DIRECT_TO_VM_FINISHED_TIMING),
+                    new TimedEventPair(BLOCK_CHECK_INITIATED, BLOCK_CHECK_FINISHED,
+                            BLOCK_CHECK_FINISHED_TIMING),
+                    new TimedEventPair(FILTERING_INITIATED, FILTERING_COMPLETED,
+                            FILTERING_COMPLETED_TIMING),
+                    new TimedEventPair(FILTERING_INITIATED, FILTERING_TIMED_OUT,
+                            FILTERING_TIMED_OUT_TIMING, 6000L),
+            };
+        }
 
         /**
-         * Maps from a request to a response.  The same event could be listed as the
-         * response for multiple requests (e.g. REQUEST_ACCEPT and REQUEST_UNHOLD both map to the
-         * SET_ACTIVE response). This map is used to print out the amount of time it takes between
-         * a request and a response.
+         * Maps from request events to a list of possible response events. Used to track
+         * end-to-end timing for critical user-facing operations in Telecom.
          */
-        public static final Map<String, String> requestResponsePairs =
-                new HashMap<String, String>() {{
-                    put(REQUEST_ACCEPT, SET_ACTIVE);
-                    put(REQUEST_REJECT, SET_DISCONNECTED);
-                    put(REQUEST_DISCONNECT, SET_DISCONNECTED);
-                    put(REQUEST_HOLD, SET_HOLD);
-                    put(REQUEST_UNHOLD, SET_ACTIVE);
-                    put(START_CONNECTION, SET_DIALING);
-                    put(BIND_CS, CS_BOUND);
-                    put(SCREENING_SENT, SCREENING_COMPLETED);
-                    put(BLOCK_CHECK_INITIATED, BLOCK_CHECK_FINISHED);
-                    put(DIRECT_TO_VM_INITIATED, DIRECT_TO_VM_FINISHED);
-                    put(FILTERING_INITIATED, FILTERING_COMPLETED);
-                }};
+        public static final Map<String, List<TimedEventPair>> requestResponsePairs;
+        static {
+            requestResponsePairs = new HashMap<>();
+            for (TimedEventPair p : Timings.sTimedEvents) {
+                if (requestResponsePairs.containsKey(p.mRequest)) {
+                    requestResponsePairs.get(p.mRequest).add(p);
+                } else {
+                    ArrayList<TimedEventPair> responses = new ArrayList<>();
+                    responses.add(p);
+                    requestResponsePairs.put(p.mRequest, responses);
+                }
+            }
+        }
     }
 
     public static class CallEvent {
@@ -147,10 +242,42 @@
     }
 
     public static class CallEventRecord {
+        public static class EventTiming extends TimedEvent<String> {
+            public String name;
+            public long time;
+
+            public EventTiming(String name, long time) {
+                this.name = name;
+                this.time = time;
+            }
+
+            public String getKey() {
+                return name;
+            }
+
+            public long getTime() {
+                return time;
+            }
+        }
+
+        private static class PendingResponse {
+            String requestEventId;
+            long requestEventTimeMillis;
+            long timeoutMillis;
+            String name;
+
+            public PendingResponse(String requestEventId, long requestEventTimeMillis,
+                    long timeoutMillis, String name) {
+                this.requestEventId = requestEventId;
+                this.requestEventTimeMillis = requestEventTimeMillis;
+                this.timeoutMillis = timeoutMillis;
+                this.name = name;
+            }
+        }
+
         private static final DateFormat sLongDateFormat = new SimpleDateFormat(
                 "yyyy-MM-dd HH:mm:ss.SSS");
         private static final DateFormat sDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
-        private static int sNextId = 1;
         private final List<CallEvent> mEvents = new LinkedList<>();
         private final Call mCall;
 
@@ -167,9 +294,40 @@
             Log.i("Event", "Call %s: %s, %s", mCall.getId(), event, data);
         }
 
-        public void dump(IndentingPrintWriter pw) {
-            Map<String, CallEvent> pendingResponses = new HashMap<>();
+        public List<CallEvent> getEvents() {
+            return mEvents;
+        }
 
+        public List<EventTiming> extractEventTimings() {
+            if (mEvents == null) {
+                return Collections.emptyList();
+            }
+
+            LinkedList<EventTiming> result = new LinkedList<>();
+            Map<String, PendingResponse> pendingResponses = new HashMap<>();
+            for (CallEvent event : mEvents) {
+                if (Events.requestResponsePairs.containsKey(event.eventId)) {
+                    // This event expects a response, so add that expected response to the maps
+                    // of pending events.
+                    for (Events.TimedEventPair p : Events.requestResponsePairs.get(event.eventId)) {
+                        pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
+                                event.time, p.mTimeoutMillis, p.mName));
+                    }
+                }
+
+                PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
+                if (pendingResponse != null) {
+                    long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
+                    if (elapsedTime < pendingResponse.timeoutMillis) {
+                        result.add(new EventTiming(pendingResponse.name, elapsedTime));
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        public void dump(IndentingPrintWriter pw) {
             pw.print("Call ");
             pw.print(mCall.getId());
             pw.print(" [");
@@ -181,20 +339,6 @@
             pw.println("To address: " + piiHandle(mCall.getHandle()));
 
             for (CallEvent event : mEvents) {
-
-                // We print out events in chronological order. During that process we look at each
-                // event and see if it maps to a request on the Request-Response pairs map. If it
-                // does, then we effectively start 'listening' for the response. We do that by
-                // storing the response event ID in {@code pendingResponses}. When we find the
-                // response in a later iteration of the loop, we grab the original request and
-                // calculate the time it took to get a response.
-                if (Events.requestResponsePairs.containsKey(event.eventId)) {
-                    // This event expects a response, so add that response to the maps
-                    // of pending events.
-                    String pendingResponse = Events.requestResponsePairs.get(event.eventId);
-                    pendingResponses.put(pendingResponse, event);
-                }
-
                 pw.print(sDateFormat.format(new Date(event.time)));
                 pw.print(" - ");
                 pw.print(event.eventId);
@@ -214,26 +358,25 @@
                     pw.print(data);
                     pw.print(")");
                 }
-
-                // If this event is a response event that we've been waiting for, calculate the time
-                // it took for the response to complete and print that out as well.
-                CallEvent requestEvent = pendingResponses.remove(event.eventId);
-                if (requestEvent != null) {
-                    pw.print(", time since ");
-                    pw.print(requestEvent.eventId);
-                    pw.print(": ");
-                    pw.print(event.time - requestEvent.time);
-                    pw.print(" ms");
-                }
                 pw.print(":");
                 pw.print(event.sessionId);
                 pw.println();
             }
+
+            pw.println("Timings (average for this call, milliseconds):");
+            pw.increaseIndent();
+            Map<String, Double> avgEventTimings = EventTiming.averageTimings(extractEventTimings());
+            List<String> eventNames = new ArrayList<>(avgEventTimings.keySet());
+            Collections.sort(eventNames);
+            for (String eventName : eventNames) {
+                pw.printf("%s: %.2f\n", eventName, avgEventTimings.get(eventName));
+            }
+            pw.decreaseIndent();
             pw.decreaseIndent();
         }
     }
 
-    public static final int MAX_CALLS_TO_CACHE = 5;  // Arbitrarily chosen.
+    public static final int MAX_CALLS_TO_CACHE = 10;  // Arbitrarily chosen.
     public static final int MAX_CALLS_TO_CACHE_DEBUG = 20;  // Arbitrarily chosen.
     private static final long EXTENDED_LOGGING_DURATION_MILLIS = 60000 * 30; // 30 minutes
 
@@ -548,6 +691,7 @@
             // running time of the session.
             long fullSessionTimeMs =
                     System.currentTimeMillis() - subsession.getExecutionStartTimeMilliseconds();
+            Analytics.addSessionTiming(subsession.getShortMethodName(), fullSessionTimeMs);
             Log.v(LOGGING_TAG, Session.END_SESSION + " (dur: " + fullSessionTimeMs + " ms): " +
                     subsession.toString());
         }
@@ -601,6 +745,20 @@
         }
     }
 
+    public static void event(Call call, String event, String format, Object... args) {
+        String msg;
+        try {
+            msg = (args == null || args.length == 0) ? format
+                    : String.format(Locale.US, format, args);
+        } catch (IllegalFormatException ife) {
+            e("Log", ife, "IllegalFormatException: formatString='%s' numArgs=%d", format,
+                    args.length);
+            msg = format + " (An error occurred while formatting the message.)";
+        }
+
+        event(call, event, msg);
+    }
+
     @VisibleForTesting
     public static synchronized void cleanupStaleSessions(long timeoutMs) {
         String logMessage = "Stale Sessions Cleaned:\n";
@@ -641,6 +799,13 @@
         // Now add a new entry
         mCallEventRecords.add(newRecord);
         mCallEventRecordMap.put(call, newRecord);
+
+        // Register the events with Analytics
+        if (call.getAnalytics() != null) {
+            call.getAnalytics().setCallEvents(newRecord);
+        } else {
+            Log.w(LOGGING_TAG, "Call analytics is null");
+        }
     }
 
     /**
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index 86b393b..6f22596 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -57,9 +57,6 @@
  */
 @VisibleForTesting
 public class NewOutgoingCallIntentBroadcaster {
-    private static final String EXTRA_ACTUAL_NUMBER_TO_DIAL =
-            "android.telecom.extra.ACTUAL_NUMBER_TO_DIAL";
-
     /**
      * Legacy string constants used to retrieve gateway provider extras from intents. These still
      * need to be copied from the source call intent to the destination intent in order to
@@ -69,14 +66,13 @@
     public static final String EXTRA_GATEWAY_PROVIDER_PACKAGE =
             "com.android.phone.extra.GATEWAY_PROVIDER_PACKAGE";
     public static final String EXTRA_GATEWAY_URI = "com.android.phone.extra.GATEWAY_URI";
-    public static final String EXTRA_GATEWAY_ORIGINAL_URI =
-            "com.android.phone.extra.GATEWAY_ORIGINAL_URI";
 
     private final CallsManager mCallsManager;
     private final Call mCall;
     private final Intent mIntent;
     private final Context mContext;
     private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
+    private final TelecomSystem.SyncRoot mLock;
 
     /*
      * Whether or not the outgoing call intent originated from the default phone application. If
@@ -94,6 +90,7 @@
         mIntent = intent;
         mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
         mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
+        mLock = mCallsManager.getLock();
     }
 
     /**
@@ -107,70 +104,73 @@
             try {
                 Log.startSession("NOCBIR.oR");
                 Trace.beginSection("onReceiveNewOutgoingCallBroadcast");
-                Log.v(this, "onReceive: %s", intent);
+                synchronized (mLock) {
+                    Log.v(this, "onReceive: %s", intent);
 
-                // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData is used as the
-                // actual number to call. (If null, no call will be placed.)
-                String resultNumber = getResultData();
-                Log.i(this, "Received new-outgoing-call-broadcast for %s with data %s", mCall,
-                        Log.pii(resultNumber));
+                    // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData is
+                    // used as the actual number to call. (If null, no call will be placed.)
+                    String resultNumber = getResultData();
+                    Log.i(this, "Received new-outgoing-call-broadcast for %s with data %s", mCall,
+                            Log.pii(resultNumber));
 
-                boolean endEarly = false;
-                if (resultNumber == null) {
-                    Log.v(this, "Call cancelled (null number), returning...");
-                    endEarly = true;
-                } else if (TelephonyUtil.isPotentialLocalEmergencyNumber(resultNumber)) {
-                    Log.w(this, "Cannot modify outgoing call to emergency number %s.",
-                            resultNumber);
-                    endEarly = true;
-                }
-
-                if (endEarly) {
-                    if (mCall != null) {
-                        mCall.disconnect(true /* wasViaNewOutgoingCall */);
+                    boolean endEarly = false;
+                    if (resultNumber == null) {
+                        Log.v(this, "Call cancelled (null number), returning...");
+                        endEarly = true;
+                    } else if (TelephonyUtil.isPotentialLocalEmergencyNumber(
+                            resultNumber)) {
+                        Log.w(this, "Cannot modify outgoing call to emergency number %s.",
+                                resultNumber);
+                        endEarly = true;
                     }
-                    return;
+
+                    if (endEarly) {
+                        if (mCall != null) {
+                            mCall.disconnect(true /* wasViaNewOutgoingCall */);
+                        }
+                        return;
+                    }
+
+                    // If this call is already disconnected then we have nothing more to do.
+                    if (mCall.isDisconnected()) {
+                        Log.w(this, "Call has already been disconnected," +
+                                        " ignore the broadcast Call %s", mCall);
+                        return;
+                    }
+
+                    boolean isSkipSchemaParsing = mIntent.getBooleanExtra(
+                            TelephonyProperties.EXTRA_SKIP_SCHEMA_PARSING, false);
+                    Uri resultHandleUri = null;
+                    Uri originalUri = mIntent.getData();
+                    if (isSkipSchemaParsing) {
+                        // resultNumber does not have the schema present
+                        // hence use originalUri which is same as handle
+                        resultHandleUri = Uri.fromParts(PhoneAccount.SCHEME_TEL,
+                                originalUri.toString(), null);
+                    } else {
+                        resultHandleUri = Uri.fromParts(mPhoneNumberUtilsAdapter
+                                .isUriNumber(resultNumber) ? PhoneAccount.SCHEME_SIP
+                                : PhoneAccount.SCHEME_TEL, resultNumber, null);
+                    }
+
+                    if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
+                        Log.v(this, "Call number unmodified after" +
+                                " new outgoing call intent broadcast.");
+                    } else {
+                        Log.v(this, "Retrieved modified handle after outgoing call intent" +
+                                " broadcast: Original: %s, Modified: %s",
+                                Log.pii(originalUri),
+                                Log.pii(resultHandleUri));
+                    }
+
+                    GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
+                    mCall.setNewOutgoingCallIntentBroadcastIsDone();
+                    mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
+                            mIntent.getBooleanExtra(
+                                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false),
+                            mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                                    VideoProfile.STATE_AUDIO_ONLY));
                 }
-
-                // If this call is already disconnected then we have nothing more to do.
-                if (mCall.isDisconnected()) {
-                    Log.w(this,
-                        "Call has already been disconnected, ignore the broadcast Call %s", mCall);
-                    return;
-                }
-
-                boolean isSkipSchemaParsing = mIntent.getBooleanExtra(
-                        TelephonyProperties.EXTRA_SKIP_SCHEMA_PARSING, false);
-                Uri resultHandleUri = null;
-                Uri originalUri = mIntent.getData();
-
-                if (isSkipSchemaParsing) {
-                    // resultNumber does not have the schema present
-                    // hence use originalUri which is same as handle
-                    resultHandleUri = Uri.fromParts(PhoneAccount.SCHEME_TEL,
-                            originalUri.toString(), null);
-                } else {
-                    resultHandleUri = Uri.fromParts(mPhoneNumberUtilsAdapter.isUriNumber(resultNumber) ?
-                            PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, resultNumber, null);
-                }
-
-                if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
-                    Log.v(this, "Call number unmodified after new outgoing call intent broadcast.");
-                } else {
-                    Log.v(this, "Retrieved modified handle after outgoing call intent broadcast: "
-                            + "Original: %s, Modified: %s",
-                            Log.pii(originalUri),
-                            Log.pii(resultHandleUri));
-                }
-
-                GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
-                mCall.setNewOutgoingCallIntentBroadcastIsDone();
-                mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
-                        mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,
-                                false),
-                        mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
-                                VideoProfile.STATE_AUDIO_ONLY));
-
             } finally {
                 Trace.endSection();
                 Log.endSession();
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index a83a134..f066c9b 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -28,11 +28,13 @@
  * Utilities dealing with {@link ParcelableCall}.
  */
 public class ParcelableCallUtils {
+    private static final int CALL_STATE_OVERRIDE_NONE = -1;
+
     public static class Converter {
         public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
                 PhoneAccountRegistrar phoneAccountRegistrar) {
             return ParcelableCallUtils.toParcelableCall(
-                    call, includeVideoProvider, phoneAccountRegistrar);
+                    call, includeVideoProvider, phoneAccountRegistrar, false);
         }
     }
 
@@ -45,13 +47,45 @@
      *      method creates a {@link VideoCallImpl} instance on access it is important for the
      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
+     * @param supportsExternalCalls Indicates whether the call should be parcelled for an
+     *      {@link InCallService} which supports external calls or not.
+     */
+    public static ParcelableCall toParcelableCall(
+            Call call,
+            boolean includeVideoProvider,
+            PhoneAccountRegistrar phoneAccountRegistrar,
+            boolean supportsExternalCalls) {
+        return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
+                supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */);
+    }
+
+    /**
+     * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
+     *
+     * @param call The {@link Call} to parcel.
+     * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
+     *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
+     *      method creates a {@link VideoCallImpl} instance on access it is important for the
+     *      recipient of the {@link ParcelableCall} to know if the video provider changed.
+     * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
+     * @param supportsExternalCalls Indicates whether the call should be parcelled for an
+     *      {@link InCallService} which supports external calls or not.
+     * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
+     *      override to whatever is defined in the call.
      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
      */
     public static ParcelableCall toParcelableCall(
             Call call,
             boolean includeVideoProvider,
-            PhoneAccountRegistrar phoneAccountRegistrar) {
-        int state = getParcelableState(call);
+            PhoneAccountRegistrar phoneAccountRegistrar,
+            boolean supportsExternalCalls,
+            int overrideState) {
+        int state;
+        if (overrideState == CALL_STATE_OVERRIDE_NONE) {
+            state = getParcelableState(call, supportsExternalCalls);
+        } else {
+            state = overrideState;
+        }
         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
         int properties = convertConnectionToCallProperties(call.getConnectionProperties());
         if (call.isConference()) {
@@ -138,7 +172,7 @@
                 call.getExtras());
     }
 
-    private static int getParcelableState(Call call) {
+    private static int getParcelableState(Call call, boolean supportsExternalCalls) {
         int state = CallState.NEW;
         switch (call.getState()) {
             case CallState.ABORTED:
@@ -154,6 +188,19 @@
             case CallState.DIALING:
                 state = android.telecom.Call.STATE_DIALING;
                 break;
+            case CallState.PULLING:
+                if (supportsExternalCalls) {
+                    // The InCallService supports external calls, so it must handle
+                    // STATE_PULLING_CALL.
+                    state = android.telecom.Call.STATE_PULLING_CALL;
+                } else {
+                    // The InCallService does NOT support external calls, so remap
+                    // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
+                    // as a form of dialing, so it is appropriate for InCallServices which do not
+                    // handle external calls.
+                    state = android.telecom.Call.STATE_DIALING;
+                }
+                break;
             case CallState.DISCONNECTING:
                 state = android.telecom.Call.STATE_DISCONNECTING;
                 break;
@@ -270,11 +317,14 @@
         Connection.PROPERTY_GENERIC_CONFERENCE,
         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
 
-        Connection.PROPERTY_SHOW_CALLBACK_NUMBER,
+        Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
 
         Connection.PROPERTY_IS_EXTERNAL_CALL,
-        android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL
+        android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
+
+        Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
+        android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY
     };
 
     private static int convertConnectionToCallProperties(int connectionProperties) {
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index a4eba5d..da802e9 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -59,7 +59,6 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -77,8 +76,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
@@ -245,6 +248,46 @@
     }
 
     /**
+     * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling
+     * account and group Id for the {@link UserHandle} specified.
+     */
+    private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) {
+        if (userHandle == null) {
+            return null;
+        }
+        DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
+                .get(userHandle);
+        if (defaultPhoneAccountHandle == null) {
+            return null;
+        }
+
+        return defaultPhoneAccountHandle;
+    }
+
+    /**
+     * @return The currently registered PhoneAccount in Telecom that has the same group Id.
+     */
+    private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName,
+            UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) {
+        if (groupId == null || groupId.isEmpty() || userHandle == null) {
+            return null;
+        }
+        // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the
+        // newAccount that was just added
+        List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle).stream()
+                .filter(account -> groupId.equals(account.getGroupId()) &&
+                        !account.getAccountHandle().equals(excludePhoneAccountHandle) &&
+                        Objects.equals(account.getAccountHandle().getComponentName(),
+                                groupComponentName))
+                .collect(Collectors.toList());
+        // There should be one or no PhoneAccounts with the same group Id
+        if (accounts.size() > 1) {
+            Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!");
+        }
+        return accounts.isEmpty() ? null : accounts.get(0);
+    }
+
+    /**
      * Sets the phone account with which to place all calls by default. Set by the user
      * within phone settings.
      */
@@ -278,7 +321,8 @@
             }
 
             mState.defaultOutgoingAccountHandles
-                    .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle));
+                    .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
+                            account.getGroupId()));
         }
 
         write();
@@ -592,6 +636,8 @@
         }
 
         mState.accounts.add(account);
+        // Set defaults and replace based on the group Id.
+        maybeReplaceOldAccount(account);
         // Reset enabled state to whatever the value was if the account was already registered,
         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled.
         account.setIsEnabled(
@@ -701,6 +747,40 @@
         }
     }
 
+    private void maybeReplaceOldAccount(PhoneAccount newAccount) {
+        UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle();
+        DefaultPhoneAccountHandle defaultHandle =
+                getUserSelectedDefaultPhoneAccount(newAccountUserHandle);
+        if (defaultHandle == null || defaultHandle.groupId.isEmpty()) {
+            Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " +
+                    "default.");
+            return;
+        }
+        if (!defaultHandle.groupId.equals(newAccount.getGroupId())) {
+            Log.v(this, "maybeReplaceOldAccount: group Ids are not equal.");
+            return;
+        }
+        if (Objects.equals(newAccount.getAccountHandle().getComponentName(),
+                defaultHandle.phoneAccountHandle.getComponentName())) {
+            // Move default calling account over to new user, since the ComponentNames and Group Ids
+            // are the same.
+            setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(),
+                    newAccountUserHandle);
+        } else {
+            Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" +
+                    " the same as the default. Not replacing default PhoneAccount.");
+        }
+        PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(),
+                newAccount.getAccountHandle().getComponentName(), newAccountUserHandle,
+                newAccount.getAccountHandle());
+        if (replacementAccount != null) {
+            // Unregister the old PhoneAccount.
+            Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " +
+                    replacementAccount.getAccountHandle());
+            unregisterPhoneAccount(replacementAccount.getAccountHandle());
+        }
+    }
+
     /**
      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
@@ -933,10 +1013,13 @@
 
         public final PhoneAccountHandle phoneAccountHandle;
 
+        public final String groupId;
+
         public DefaultPhoneAccountHandle(UserHandle userHandle,
-                PhoneAccountHandle phoneAccountHandle) {
+                PhoneAccountHandle phoneAccountHandle, String groupId) {
             this.userHandle = userHandle;
             this.phoneAccountHandle = phoneAccountHandle;
+            this.groupId = groupId;
         }
     }
 
@@ -1183,6 +1266,13 @@
             serializer.endTag(null, tagName);
         }
 
+        protected void writeNonNullString(String tagName, String value, XmlSerializer serializer)
+                throws IOException {
+            serializer.startTag(null, tagName);
+            serializer.text(value != null ? value : "");
+            serializer.endTag(null, tagName);
+        }
+
         /**
          * Reads a string array from the XML parser.
          *
@@ -1321,8 +1411,9 @@
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
                         if (s.versionNumber < 9) {
-                            // Migration old default phone account handle here by assuming the
-                            // default phone account handle is belong to primary user.
+                            // Migrate old default phone account handle here by assuming the
+                            // default phone account handle belongs to the primary user. Also,
+                            // assume there are no groups.
                             parser.nextTag();
                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
                                     .readFromXml(parser, s.versionNumber, context);
@@ -1332,7 +1423,7 @@
                                 UserHandle userHandle = primaryUser.getUserHandle();
                                 DefaultPhoneAccountHandle defaultPhoneAccountHandle
                                         = new DefaultPhoneAccountHandle(userHandle,
-                                        phoneAccountHandle);
+                                        phoneAccountHandle, "" /* groupId */);
                                 s.defaultOutgoingAccountHandles
                                         .put(userHandle, defaultPhoneAccountHandle);
                             }
@@ -1372,6 +1463,7 @@
                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
                         = "default_outgoing_phone_account_handle";
                 private static final String USER_SERIAL_NUMBER = "user_serial_number";
+                private static final String GROUP_ID = "group_id";
                 private static final String ACCOUNT_HANDLE = "account_handle";
 
                 @Override
@@ -1383,6 +1475,7 @@
                         if (serialNumber != -1) {
                             serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
                             writeLong(USER_SERIAL_NUMBER, serialNumber, serializer);
+                            writeNonNullString(GROUP_ID, o.groupId, serializer);
                             serializer.startTag(null, ACCOUNT_HANDLE);
                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
                                     context);
@@ -1400,6 +1493,7 @@
                         int outerDepth = parser.getDepth();
                         PhoneAccountHandle accountHandle = null;
                         String userSerialNumberString = null;
+                        String groupId = "";
                         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
                                 parser.nextTag();
@@ -1408,6 +1502,9 @@
                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
                                 parser.next();
                                 userSerialNumberString = parser.getText();
+                            } else if (parser.getName().equals(GROUP_ID)) {
+                                parser.next();
+                                groupId = parser.getText();
                             }
                         }
                         UserHandle userHandle = null;
@@ -1421,8 +1518,9 @@
                                         "Could not parse UserHandle " + userSerialNumberString);
                             }
                         }
-                        if (accountHandle != null && userHandle != null) {
-                            return new DefaultPhoneAccountHandle(userHandle, accountHandle);
+                        if (accountHandle != null && userHandle != null && groupId != null) {
+                            return new DefaultPhoneAccountHandle(userHandle, accountHandle,
+                                    groupId);
                         }
                     }
                     return null;
diff --git a/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java b/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
index 41284cb..8e59a64 100644
--- a/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
+++ b/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
@@ -24,6 +24,7 @@
  * refactoring.
  */
 public interface PhoneNumberUtilsAdapter {
+    boolean isLocalEmergencyNumber(Context context, String number);
     boolean isPotentialLocalEmergencyNumber(Context context, String number);
     boolean isUriNumber(String number);
     String getNumberFromIntent(Intent intent, Context context);
diff --git a/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java b/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
index 640d814..fa316a5 100644
--- a/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
+++ b/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
@@ -22,6 +22,11 @@
 
 public class PhoneNumberUtilsAdapterImpl implements PhoneNumberUtilsAdapter {
     @Override
+    public boolean isLocalEmergencyNumber(Context context, String number) {
+            return PhoneNumberUtils.isLocalEmergencyNumber(context, number);
+    }
+
+    @Override
     public boolean isPotentialLocalEmergencyNumber(Context context, String number) {
         return PhoneNumberUtils.isPotentialLocalEmergencyNumber(context, number);
     }
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index 413f06c..0781ca2 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -43,6 +43,9 @@
 
     @Override
     public void onCallStateChanged(Call call, int oldState, int newState) {
+        if (call.isExternalCall()) {
+            return;
+        }
         updateStates(call);
     }
 
@@ -83,8 +86,8 @@
         int callState = TelephonyManager.CALL_STATE_IDLE;
         if (mCallsManager.hasRingingCall()) {
             callState = TelephonyManager.CALL_STATE_RINGING;
-        } else if (mCallsManager.getFirstCallWithState(CallState.DIALING, CallState.ACTIVE,
-                    CallState.ON_HOLD) != null) {
+        } else if (mCallsManager.getFirstCallWithState(CallState.DIALING, CallState.PULLING,
+                CallState.ACTIVE, CallState.ON_HOLD) != null) {
             callState = TelephonyManager.CALL_STATE_OFFHOOK;
         }
         sendPhoneStateChangedBroadcast(call, callState);
diff --git a/src/com/android/server/telecom/ProximitySensorManager.java b/src/com/android/server/telecom/ProximitySensorManager.java
index dd336c4..e53b1d5 100644
--- a/src/com/android/server/telecom/ProximitySensorManager.java
+++ b/src/com/android/server/telecom/ProximitySensorManager.java
@@ -38,6 +38,9 @@
 
     @Override
     public void onCallRemoved(Call call) {
+        if (call.isExternalCall()) {
+            return;
+        }
         if (mCallsManager.getCalls().isEmpty()) {
             Log.i(this, "All calls removed, resetting proximity sensor to default state");
             turnOff(true);
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index 1029308..3f60dbb 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.telecom.Connection;
 import android.telecom.Response;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionManager;
@@ -132,8 +133,7 @@
     public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
         if (rejectWithMessage
                 && call.getHandle() != null
-                && !call.can(
-                        android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+                && !call.can(Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
             int subId = mCallsManager.getPhoneAccountRegistrar().getSubscriptionIdForPhoneAccount(
                     call.getTargetPhoneAccount());
             rejectCallWithMessage(call.getContext(), call.getHandle().getSchemeSpecificPart(),
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 77b1590..262f437 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -94,30 +94,32 @@
         mInCallController = inCallController;
     }
 
-    public void startRinging(Call foregroundCall) {
+    public boolean startRinging(Call foregroundCall) {
+        AudioManager audioManager =
+                (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        boolean isRingerAudible = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
+
         if (mSystemSettingsUtil.isTheaterModeOn(mContext)) {
-            return;
+            return false;
         }
 
         if (foregroundCall == null) {
             Log.wtf(this, "startRinging called with null foreground call.");
-            return;
+            return false;
         }
 
         if (mInCallController.doesConnectedDialerSupportRinging()) {
             Log.event(foregroundCall, Log.Events.SKIP_RINGING);
-            return;
+            return isRingerAudible;
         }
 
         stopCallWaiting();
 
         if (!shouldRingForContact(foregroundCall.getContactUri())) {
-            return;
+            return false;
         }
 
-        AudioManager audioManager =
-                (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
+        if (isRingerAudible) {
             mRingingCall = foregroundCall;
             Log.event(foregroundCall, Log.Events.START_RINGER);
             // Because we wait until a contact info query to complete before processing a
@@ -126,7 +128,7 @@
             // request the custom ringtone from the call and expect it to be current.
             mRingtonePlayer.play(mRingtoneFactory, foregroundCall);
         } else {
-            Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0");
+            Log.i(this, "startRingingOrCallWaiting, skipping because volume is 0");
         }
 
         if (shouldVibrate(mContext) && !mIsVibrating) {
@@ -134,6 +136,8 @@
                     VIBRATION_ATTRIBUTES);
             mIsVibrating = true;
         }
+
+        return isRingerAudible;
     }
 
     public void startCallWaiting(Call call) {
diff --git a/src/com/android/server/telecom/Runnable.java b/src/com/android/server/telecom/Runnable.java
index 41415fd..c7ace72 100644
--- a/src/com/android/server/telecom/Runnable.java
+++ b/src/com/android/server/telecom/Runnable.java
@@ -24,7 +24,7 @@
 
     private Session mSubsession;
     private final String mSubsessionName;
-    private final Object mLock = new Object();
+    private final Object mLock;
     private final java.lang.Runnable mRunnable = new java.lang.Runnable() {
             @Override
             public void run() {
@@ -42,7 +42,18 @@
             }
         };
 
-    public Runnable(String subsessionName) {
+    /**
+     * Creates a new Telecom Runnable that incorporates Session Logging into it. Useful for carrying
+     * Logging Sessions through different threads as well as through handlers.
+     * @param subsessionName The name that will be used in the Logs to mark this Session
+     * @param lock The synchronization lock that will be used to lock loggedRun().
+     */
+    public Runnable(String subsessionName, Object lock) {
+        if (lock == null) {
+            mLock = new Object();
+        } else {
+            mLock = lock;
+        }
         mSubsessionName = subsessionName;
     }
 
@@ -78,7 +89,8 @@
     }
 
     /**
-     * The method that will be run in the handler/thread.
+     * The method that will be run in the handler/thread. This method will be called with mLock
+     * held.
      */
     abstract public void loggedRun();
 
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index 18d6581..05f0bcb 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -169,7 +169,7 @@
     private final String mServiceAction;
 
     /** The component name of the service to bind to. */
-    private final ComponentName mComponentName;
+    protected final ComponentName mComponentName;
 
     /** The set of callbacks waiting for notification of the binding's success or failure. */
     private final Set<BindCallback> mCallbacks = new ArraySet<>();
@@ -227,12 +227,16 @@
     }
 
     final void decrementAssociatedCallCount() {
+        decrementAssociatedCallCount(false /*isSuppressingUnbind*/);
+    }
+
+    final void decrementAssociatedCallCount(boolean isSuppressingUnbind) {
         if (mAssociatedCallCount > 0) {
             mAssociatedCallCount--;
             Log.v(this, "Call count decrement %d, %s", mAssociatedCallCount,
                     mComponentName.flattenToShortString());
 
-            if (mAssociatedCallCount == 0) {
+            if (!isSuppressingUnbind && mAssociatedCallCount == 0) {
                 unbind();
             }
         } else {
@@ -336,22 +340,28 @@
      */
     private void setBinder(IBinder binder) {
         if (mBinder != binder) {
-            mBinder = binder;
-
-            setServiceInterface(binder);
-
             if (binder == null) {
+                removeServiceInterface();
+                mBinder = null;
                 for (Listener l : mListeners) {
                     l.onUnbind(this);
                 }
+            } else {
+                mBinder = binder;
+                setServiceInterface(binder);
             }
         }
     }
 
     /**
-     * Sets the service interface after the service is bound or unbound.
+     * Sets the service interface after the service is bound.
      *
-     * @param binder The actual bound service implementation.
+     * @param binder The new binder interface that is being set.
      */
     protected abstract void setServiceInterface(IBinder binder);
+
+    /**
+     * Removes the service interface before the service is unbound.
+     */
+    protected abstract void removeServiceInterface();
 }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 577d93a..c93a752 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -39,9 +39,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.DefaultDialerManager;
-import android.telecom.ParcelableCallAnalytics;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomAnalytics;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.SubscriptionManager;
@@ -56,8 +56,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -1145,11 +1143,11 @@
         }
 
         @Override
-        public List<ParcelableCallAnalytics> dumpCallAnalytics() {
+        public TelecomAnalytics dumpCallAnalytics() {
             try {
                 Log.startSession("TSI.dCA");
                 enforcePermission(DUMP);
-                return Arrays.asList(Analytics.dumpToParcelableAnalytics());
+                return Analytics.dumpToParcelableAnalytics();
             } finally {
                 Log.endSession();
             }
@@ -1173,6 +1171,11 @@
                 return;
             }
 
+            if (args.length > 0 && Analytics.ANALYTICS_DUMPSYS_ARG.equals(args[0])) {
+                Analytics.dumpToEncodedProto(writer, args);
+                return;
+            }
+
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
             if (mCallsManager != null) {
                 pw.println("CallsManager: ");
@@ -1293,6 +1296,7 @@
             call = mCallsManager.getFirstCallWithState(
                     CallState.ACTIVE,
                     CallState.DIALING,
+                    CallState.PULLING,
                     CallState.RINGING,
                     CallState.ON_HOLD);
         }
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index ae5a64a..99895e5 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -157,7 +157,9 @@
                     bluetoothPhoneServiceImplFactory,
             Timeouts.Adapter timeoutsAdapter,
             AsyncRingtonePlayer asyncRingtonePlayer,
-            ViceNotifier vicenotifier) {
+            ViceNotifier vicenotifier,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
+            InterruptionFilterProxy interruptionFilterProxy) {
         mContext = context.getApplicationContext();
         Log.setContext(mContext);
         Log.initMd5Sum();
@@ -179,7 +181,8 @@
         SystemStateProvider systemStateProvider = new SystemStateProvider(mContext);
 
         mMissedCallNotifier = missedCallNotifierImplFactory
-                .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar);
+                .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar,
+                        phoneNumberUtilsAdapter);
 
         DefaultDialerManagerAdapter defaultDialerAdapter =
                 new TelecomServiceImpl.DefaultDialerManagerAdapterImpl();
@@ -201,7 +204,9 @@
                 defaultDialerAdapter,
                 timeoutsAdapter,
                 asyncRingtonePlayer,
-                mViceNotifier);
+                mViceNotifier,
+                phoneNumberUtilsAdapter,
+                interruptionFilterProxy);
 
         mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
         mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index a5fba7b..2a6e6cf 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -24,10 +24,16 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import org.codeaurora.internal.IExtTelephony;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
 /**
  * Utilities to deal with the system telephony services. The system telephony services are treated
  * differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
@@ -103,4 +109,55 @@
         }
         return result;
     }
+
+    public static void sortSimPhoneAccounts(Context context, List<PhoneAccount> accounts) {
+        final TelephonyManager telephonyManager = TelephonyManager.from(context);
+
+        // Sort the accounts according to how we want to display them.
+        Collections.sort(accounts, new Comparator<PhoneAccount>() {
+            @Override
+            public int compare(PhoneAccount account1, PhoneAccount account2) {
+                int retval = 0;
+
+                // SIM accounts go first
+                boolean isSim1 = account1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
+                boolean isSim2 = account2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
+                if (isSim1 != isSim2) {
+                    retval = isSim1 ? -1 : 1;
+                }
+
+                int subId1 = telephonyManager.getSubIdForPhoneAccount(account1);
+                int subId2 = telephonyManager.getSubIdForPhoneAccount(account2);
+                if (subId1 != SubscriptionManager.INVALID_SUBSCRIPTION_ID &&
+                        subId2 != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                    retval = (SubscriptionManager.getSlotId(subId1) <
+                            SubscriptionManager.getSlotId(subId2)) ? -1 : 1;
+                }
+
+                // Then order by package
+                if (retval == 0) {
+                    String pkg1 = account1.getAccountHandle().getComponentName().getPackageName();
+                    String pkg2 = account2.getAccountHandle().getComponentName().getPackageName();
+                    retval = pkg1.compareTo(pkg2);
+                }
+
+                // Finally, order by label
+                if (retval == 0) {
+                    String label1 = nullToEmpty(account1.getLabel().toString());
+                    String label2 = nullToEmpty(account2.getLabel().toString());
+                    retval = label1.compareTo(label2);
+                }
+
+                // Then by hashcode
+                if (retval == 0) {
+                    retval = account1.hashCode() - account2.hashCode();
+                }
+                return retval;
+            }
+        });
+    }
+
+    private static String nullToEmpty(String str) {
+        return str == null ? "" : str;
+    }
 }
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index 08d7410..7be59c3 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -32,6 +32,10 @@
         public long getCallScreeningTimeoutMillis(ContentResolver cr) {
             return Timeouts.getCallScreeningTimeoutMillis(cr);
         }
+
+        public long getCallRemoveUnbindInCallServicesDelay(ContentResolver cr) {
+            return Timeouts.getCallRemoveUnbindInCallServicesDelay(cr);
+        }
     }
 
     /** A prefix to use for all keys so to not clobber the global namespace. */
@@ -53,22 +57,13 @@
     }
 
     /**
-     * Returns the longest period, in milliseconds, to wait for the query for direct-to-voicemail
-     * to complete. If the query goes beyond this timeout, the incoming call screen is shown to the
-     * user.
-     */
-    public static long getDirectToVoicemailMillis(ContentResolver contentResolver) {
-        return get(contentResolver, "direct_to_voicemail_ms", 500L);
-    }
-
-    /**
      * Returns the amount of time to wait before disconnecting a call that was canceled via
      * NEW_OUTGOING_CALL broadcast. This timeout allows apps which repost the call using a gateway
      * to reuse the existing call, preventing the call from causing a start->end->start jank in the
      * in-call UI.
      */
     public static long getNewOutgoingCallCancelMillis(ContentResolver contentResolver) {
-        return get(contentResolver, "new_outgoing_call_cancel_ms", 400L);
+        return get(contentResolver, "new_outgoing_call_cancel_ms", 100000L);
     }
 
     /**
@@ -141,11 +136,4 @@
     public static long getCallScreeningTimeoutMillis(ContentResolver contentResolver) {
         return get(contentResolver, "call_screening_timeout", 5000L /* 5 seconds */);
     }
-
-    /**
-     * Returns the amount of time to wait for the block checker to allow or disallow a call.
-     */
-    public static long getBlockCheckTimeoutMillis(ContentResolver contentResolver) {
-        return get(contentResolver, "block_check_timeout_millis", 500L);
-    }
 }
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
index 9d17139..3722b59 100644
--- a/src/com/android/server/telecom/VideoProviderProxy.java
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -29,7 +29,6 @@
 import com.android.internal.telecom.IVideoProvider;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -130,6 +129,31 @@
                 Log.startSession("VPP.rSMR");
                 synchronized (mLock) {
                     logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile);
+                    Log.event(mCall, Log.Events.RECEIVE_VIDEO_REQUEST,
+                            VideoProfile.videoStateToString(videoProfile.getVideoState()));
+
+                    mCall.getAnalytics().addVideoEvent(
+                            Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST,
+                            videoProfile.getVideoState());
+
+                    if (!mCall.isVideoCallingSupported() &&
+                            VideoProfile.isVideo(videoProfile.getVideoState())) {
+                        // If video calling is not supported by the phone account, and we receive
+                        // a request to upgrade to video, automatically reject it without informing
+                        // the InCallService.
+
+                        Log.event(mCall, Log.Events.SEND_VIDEO_RESPONSE, "video not supported");
+                        VideoProfile responseProfile = new VideoProfile(
+                                VideoProfile.STATE_AUDIO_ONLY);
+                        try {
+                            mConectionServiceVideoProvider.sendSessionModifyResponse(
+                                    responseProfile);
+                        } catch (RemoteException e) {
+                        }
+
+                        // Don't want to inform listeners of the request as we've just rejected it.
+                        return;
+                    }
 
                     // Inform other Telecom components of the session modification request.
                     for (Listener listener : mListeners) {
@@ -154,10 +178,19 @@
         @Override
         public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
                 VideoProfile responseProfile) {
+            logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
+                    " requestProfile=" + requestProfile + " responseProfile=" + responseProfile);
+            String eventMessage = "Status Code : " + status + " Video State: " +
+                    (responseProfile != null ? responseProfile.getVideoState() : "null");
+            Log.event(mCall, Log.Events.RECEIVE_VIDEO_RESPONSE, eventMessage);
             synchronized (mLock) {
-                logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
-                        " requestProfile=" + requestProfile + " responseProfile=" +
-                        responseProfile);
+                if (status == Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS) {
+                    mCall.getAnalytics().addVideoEvent(
+                            Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
+                            responseProfile == null ?
+                                    VideoProfile.STATE_AUDIO_ONLY :
+                                    responseProfile.getVideoState());
+                }
                 VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile,
                         responseProfile);
             }
@@ -172,7 +205,8 @@
         @Override
         public void handleCallSessionEvent(int event) {
             synchronized (mLock) {
-                logFromVideoProvider("handleCallSessionEvent: " + event);
+                logFromVideoProvider("handleCallSessionEvent: " +
+                        Connection.VideoProvider.sessionEventToString(event));
                 VideoProviderProxy.this.handleCallSessionEvent(event);
             }
         }
@@ -337,6 +371,11 @@
     public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
         synchronized (mLock) {
             logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
+            Log.event(mCall, Log.Events.SEND_VIDEO_REQUEST,
+                    VideoProfile.videoStateToString(toProfile.getVideoState()));
+            mCall.getAnalytics().addVideoEvent(
+                    Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
+                    toProfile.getVideoState());
             try {
                 mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
             } catch (RemoteException e) {
@@ -354,6 +393,11 @@
     public void onSendSessionModifyResponse(VideoProfile responseProfile) {
         synchronized (mLock) {
             logFromInCall("sendSessionModifyResponse: " + responseProfile);
+            Log.event(mCall, Log.Events.SEND_VIDEO_RESPONSE,
+                    VideoProfile.videoStateToString(responseProfile.getVideoState()));
+            mCall.getAnalytics().addVideoEvent(
+                    Analytics.SEND_LOCAL_SESSION_MODIFY_RESPONSE,
+                    responseProfile.getVideoState());
             try {
                 mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
             } catch (RemoteException e) {
@@ -434,7 +478,7 @@
      * @param toLog The message to log.
      */
     private void logFromInCall(String toLog) {
-        Log.v(this, "IC->VP: " + toLog);
+        Log.i(this, "IC->VP (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
     }
 
     /**
@@ -444,6 +488,6 @@
      * @param toLog The message to log.
      */
     private void logFromVideoProvider(String toLog) {
-        Log.v(this, "VP->IC: " + toLog);
+        Log.i(this, "VP->IC (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
     }
 }
diff --git a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java b/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
index 8872297..51fc390 100644
--- a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
+++ b/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
@@ -33,7 +33,8 @@
     private final Context mContext;
     private final BlockCheckerAdapter mBlockCheckerAdapter;
     private Call mIncomingCall;
-    private Session mLogSubsession;
+    private Session mBackgroundTaskSubsession;
+    private Session mPostExecuteSubsession;
     private CallFilterResultCallback mCallback;
 
     public AsyncBlockCheckFilter(Context context, BlockCheckerAdapter blockCheckerAdapter) {
@@ -52,13 +53,14 @@
 
     @Override
     protected void onPreExecute() {
-        mLogSubsession = Log.createSubsession();
+        mBackgroundTaskSubsession = Log.createSubsession();
+        mPostExecuteSubsession = Log.createSubsession();
     }
 
     @Override
     protected Boolean doInBackground(String... params) {
         try {
-            Log.continueSession(mLogSubsession, "ABCF.dIB");
+            Log.continueSession(mBackgroundTaskSubsession, "ABCF.dIB");
             Log.event(mIncomingCall, Log.Events.BLOCK_CHECK_INITIATED);
             return mBlockCheckerAdapter.isBlocked(mContext, params[0]);
         } finally {
@@ -68,23 +70,28 @@
 
     @Override
     protected void onPostExecute(Boolean isBlocked) {
-        CallFilteringResult result;
-        if (isBlocked) {
-            result = new CallFilteringResult(
-                    false, // shouldAllowCall
-                    true, //shouldReject
-                    false, //shouldAddToCallLog
-                    false // shouldShowNotification
-            );
-        } else {
-            result = new CallFilteringResult(
-                    true, // shouldAllowCall
-                    false, // shouldReject
-                    true, // shouldAddToCallLog
-                    true // shouldShowNotification
-            );
+        Log.continueSession(mPostExecuteSubsession, "ABCF.oPE");
+        try {
+            CallFilteringResult result;
+            if (isBlocked) {
+                result = new CallFilteringResult(
+                        false, // shouldAllowCall
+                        true, //shouldReject
+                        false, //shouldAddToCallLog
+                        false // shouldShowNotification
+                );
+            } else {
+                result = new CallFilteringResult(
+                        true, // shouldAllowCall
+                        false, // shouldReject
+                        true, // shouldAddToCallLog
+                        true // shouldShowNotification
+                );
+            }
+            Log.event(mIncomingCall, Log.Events.BLOCK_CHECK_FINISHED, result);
+            mCallback.onCallFilteringComplete(mIncomingCall, result);
+        } finally {
+            Log.endSession();
         }
-        Log.event(mIncomingCall, Log.Events.BLOCK_CHECK_FINISHED, result);
-        mCallback.onCallFilteringComplete(mIncomingCall, result);
     }
 }
diff --git a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java b/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
index 4de6777..ea64eb3 100644
--- a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
+++ b/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
@@ -23,6 +23,8 @@
 import com.android.server.telecom.CallerInfoLookupHelper;
 import com.android.server.telecom.Log;
 
+import java.util.Objects;
+
 public class DirectToVoicemailCallFilter implements IncomingCallFilter.CallFilter {
     private final CallerInfoLookupHelper mCallerInfoLookupHelper;
 
@@ -34,13 +36,14 @@
     public void startFilterLookup(final Call call, CallFilterResultCallback callback) {
         Log.event(call, Log.Events.DIRECT_TO_VM_INITIATED);
         final Uri callHandle = call.getHandle();
+
         mCallerInfoLookupHelper.startLookup(callHandle,
                 new CallerInfoLookupHelper.OnQueryCompleteListener() {
                     @Override
                     public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) {
                         CallFilteringResult result;
-                        if ((handle != null) && callHandle.equals(handle)) {
-                            if ((info != null) && info.shouldSendToVoicemail) {
+                        if (Objects.equals(callHandle, handle)) {
+                            if (info != null && info.shouldSendToVoicemail) {
                                 result = new CallFilteringResult(
                                         false, // shouldAllowCall
                                         true, // shouldReject
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
index 4685ec0..6e0c684 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
@@ -70,17 +70,15 @@
         for (CallFilter filter : mFilters) {
             filter.startFilterLookup(mCall, this);
         }
-        mHandler.postDelayed(new Runnable("ICF.pFTO") { // performFiltering time-out
+        // synchronized to prevent a race on mResult and to enter into Telecom.
+        mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { // performFiltering time-out
             @Override
             public void loggedRun() {
-                // synchronized to prevent a race on mResult and to enter into Telecom.
-                synchronized (mTelecomLock) {
-                    if (mIsPending) {
-                        Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
-                        Log.event(mCall, Log.Events.FILTERING_TIMED_OUT);
-                        mListener.onCallFilteringComplete(mCall, mResult);
-                        mIsPending = false;
-                    }
+                if (mIsPending) {
+                    Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
+                    Log.event(mCall, Log.Events.FILTERING_TIMED_OUT);
+                    mListener.onCallFilteringComplete(mCall, mResult);
+                    mIsPending = false;
                 }
             }
         }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
@@ -91,16 +89,14 @@
             mNumPendingFilters--;
             mResult = result.combine(mResult);
             if (mNumPendingFilters == 0) {
-                mHandler.post(new Runnable("ICF.oCFC") {
+                // synchronized on mTelecomLock to enter into Telecom.
+                mHandler.post(new Runnable("ICF.oCFC", mTelecomLock) {
                     @Override
                     public void loggedRun() {
-                        // synchronized to enter into Telecom.
-                        synchronized (mTelecomLock) {
-                            if (mIsPending) {
-                                Log.event(mCall, Log.Events.FILTERING_COMPLETED, mResult);
-                                mListener.onCallFilteringComplete(mCall, mResult);
-                                mIsPending = false;
-                            }
+                        if (mIsPending) {
+                            Log.event(mCall, Log.Events.FILTERING_COMPLETED, mResult);
+                            mListener.onCallFilteringComplete(mCall, mResult);
+                            mIsPending = false;
                         }
                     }
                 }.prepare());
diff --git a/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java b/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java
index 5fd7904..107389b 100644
--- a/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java
+++ b/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java
@@ -21,11 +21,18 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Color;
+import android.graphics.Typeface;
 import android.os.Bundle;
 import android.telecom.DefaultDialerManager;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
 import android.util.Log;
 
 import com.android.internal.app.AlertActivity;
@@ -57,7 +64,7 @@
         }
 
         // Show dialog to require user confirmation.
-         buildDialog(oldPackage, mNewPackage);
+         buildDialog(mNewPackage);
     }
 
     @Override
@@ -81,36 +88,26 @@
         }
 
         if (!DefaultDialerManager.getInstalledDialerApplications(this).contains(newPackage)) {
-            Log.w(TAG, "Provided package name does not correspond to an installed Dialer "
+            Log.w(TAG, "Provided package name does not correspond to an installed Phone "
                     + "application.");
             return false;
         }
 
         if (!TextUtils.isEmpty(oldPackage) && TextUtils.equals(oldPackage, newPackage)) {
-            Log.w(TAG, "Provided package name is already the current default Dialer application.");
+            Log.w(TAG, "Provided package name is already the current default Phone application.");
             return false;
         }
         return true;
     }
 
-    private boolean buildDialog(String oldPackage, String newPackage) {
+    private boolean buildDialog(String newPackage) {
         final PackageManager pm = getPackageManager();
-        final String newPackageLabel =
-                getApplicationLabelForPackageName(pm, newPackage);
+        final String newPackageLabel = getApplicationLabelForPackageName(pm, newPackage);
         final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.change_default_dialer_dialog_title);
-        if (!TextUtils.isEmpty(oldPackage)) {
-            String oldPackageLabel =
-                    getApplicationLabelForPackageName(pm, oldPackage);
-            p.mMessage = getString(R.string.change_default_dialer_with_previous_app_set_text,
-                    newPackageLabel,
-                    oldPackageLabel);
-        } else {
-            p.mMessage = getString(R.string.change_default_dialer_no_previous_app_set_text,
-                    newPackageLabel);
-        }
-        p.mPositiveButtonText = getString(android.R.string.yes);
-        p.mNegativeButtonText = getString(android.R.string.no);
+        p.mTitle = getString(R.string.change_default_dialer_dialog_title, newPackageLabel);
+        p.mMessage = getString(R.string.change_default_dialer_warning_message, newPackageLabel);
+        p.mPositiveButtonText = getString(R.string.change_default_dialer_dialog_affirmative);
+        p.mNegativeButtonText = getString(R.string.change_default_dialer_dialog_negative);
         p.mPositiveButtonListener = this;
         p.mNegativeButtonListener = this;
         setupAlert();
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 9e17b04..ef5bf96 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.components;
 
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
@@ -35,7 +37,10 @@
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockControllerFactory;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.PhoneAccountRegistrar;
+import com.android.server.telecom.PhoneNumberUtilsAdapter;
+import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
 import com.android.server.telecom.ProximitySensorManagerFactory;
 import com.android.server.telecom.InCallWakeLockController;
 import com.android.server.telecom.Log;
@@ -73,6 +78,9 @@
      */
     static void initializeTelecomSystem(Context context) {
         if (TelecomSystem.getInstance() == null) {
+            final NotificationManager notificationManager =
+                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
             TelecomSystem.setInstance(
                     new TelecomSystem(
                             context,
@@ -80,9 +88,10 @@
                                 @Override
                                 public MissedCallNotifierImpl makeMissedCallNotifierImpl(
                                         Context context,
-                                        PhoneAccountRegistrar phoneAccountRegistrar) {
+                                        PhoneAccountRegistrar phoneAccountRegistrar,
+                                        PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
                                     return new MissedCallNotifierImpl(context,
-                                            phoneAccountRegistrar);
+                                            phoneAccountRegistrar, phoneNumberUtilsAdapter);
                                 }
                             },
                             new CallerInfoAsyncQueryFactory() {
@@ -158,7 +167,20 @@
                                     return new ViceNotificationImpl(
                                             context.getApplicationContext(), callsManager);
                                 }
-                            }));
+                            },
+                            new PhoneNumberUtilsAdapterImpl(),
+                            new InterruptionFilterProxy() {
+                                @Override
+                                public void setInterruptionFilter(int interruptionFilter) {
+                                    notificationManager.setInterruptionFilter(interruptionFilter);
+                                }
+
+                                @Override
+                                public int getCurrentInterruptionFilter() {
+                                    return notificationManager.getCurrentInterruptionFilter();
+                                }
+                            }
+                    ));
         }
         if (BluetoothAdapter.getDefaultAdapter() != null) {
             context.startService(new Intent(context, BluetoothPhoneService.class));
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 0bed981..e29373d 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -34,6 +34,7 @@
 import com.android.server.telecom.Log;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
+import com.android.server.telecom.PhoneNumberUtilsAdapter;
 import com.android.server.telecom.R;
 import com.android.server.telecom.Runnable;
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
@@ -94,7 +95,8 @@
 
     public interface MissedCallNotifierImplFactory {
         MissedCallNotifier makeMissedCallNotifierImpl(Context context,
-                PhoneAccountRegistrar phoneAccountRegistrar);
+                PhoneAccountRegistrar phoneAccountRegistrar,
+                PhoneNumberUtilsAdapter phoneNumberUtilsAdapter);
     }
 
     public interface NotificationBuilderFactory {
@@ -133,20 +135,25 @@
     private final NotificationManager mNotificationManager;
     private final NotificationBuilderFactory mNotificationBuilderFactory;
     private final ComponentName mNotificationComponent;
+    private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
     private UserHandle mCurrentUserHandle;
 
     // Used to track the number of missed calls.
     private ConcurrentMap<UserHandle, AtomicInteger> mMissedCallCounts;
 
-    public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar) {
-        this(context, phoneAccountRegistrar, new DefaultNotificationBuilderFactory());
+    public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
+        this(context, phoneAccountRegistrar, phoneNumberUtilsAdapter,
+                new DefaultNotificationBuilderFactory());
     }
 
     public MissedCallNotifierImpl(Context context,
             PhoneAccountRegistrar phoneAccountRegistrar,
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
             NotificationBuilderFactory notificationBuilderFactory) {
         mContext = context;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
+        mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
         mNotificationManager =
                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         final String notificationComponent = context.getString(R.string.notification_component);
@@ -169,7 +176,7 @@
     }
 
     private void markMissedCallsAsRead(final UserHandle userHandle) {
-        AsyncTask.execute(new Runnable("MCNI.mMCAR") {
+        AsyncTask.execute(new Runnable("MCNI.mMCAR", null /*lock*/) {
             @Override
             public void loggedRun() {
                 // Clear the list of new missed calls from the call log.
@@ -601,8 +608,9 @@
                                 // Convert the data to a call object
                                 Call call = new Call(Call.CALL_ID_UNKNOWN, mContext, callsManager,
                                         lock, null, contactsAsyncHelper,
-                                        callerInfoAsyncQueryFactory, null, null, null, null,
-                                        Call.CALL_DIRECTION_INCOMING, false, false);
+                                        callerInfoAsyncQueryFactory, mPhoneNumberUtilsAdapter, null,
+                                        null, null, null, Call.CALL_DIRECTION_INCOMING, false,
+                                        false);
                                 call.setDisconnectCause(
                                         new DisconnectCause(DisconnectCause.MISSED));
                                 call.setState(CallState.DISCONNECTED, "throw away call");
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index b30e372..0150dbe 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -165,6 +165,9 @@
             capabilities |= CAPABILITY_RESPOND_VIA_TEXT;
             setConnectionCapabilities(capabilities);
 
+            if (isIncoming) {
+                putExtra(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true);
+            }
             LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
                     mHangupReceiver, new IntentFilter(TestCallActivity.ACTION_HANGUP_CALLS));
             final IntentFilter filter =
diff --git a/tests/Android.mk b/tests/Android.mk
index 7604a57..56bc04f 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -22,11 +22,17 @@
         android-support-v4 \
         guava \
         mockito-target \
-        ims-ext-common
+        ims-ext-common \
+        platform-test-annotations
 
 LOCAL_SRC_FILES := \
         $(call all-java-files-under, src) \
-        $(call all-java-files-under, ../src)
+        $(call all-java-files-under, ../src) \
+        $(call all-proto-files-under, ../proto)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../proto/
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 
 LOCAL_SRC_FILES += \
         src/org/codeaurora/btmultisim/IBluetoothDsdaService.aidl
@@ -53,6 +59,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.server.telecom.*
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.server.telecom.tests.*
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
new file mode 100644
index 0000000..81d4aa5
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.tests;
+
+import android.content.Context;
+import android.telecom.Connection;
+import android.telecom.DisconnectCause;
+import android.telecom.InCallService;
+import android.telecom.ParcelableCallAnalytics;
+import android.telecom.TelecomAnalytics;
+import android.telecom.TelecomManager;
+import android.telecom.VideoCallImpl;
+import android.telecom.VideoProfile;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.telecom.Analytics;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.TelecomLogClass;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+public class AnalyticsTests extends TelecomSystemTest {
+    @MediumTest
+    public void testAnalyticsSingleCall() throws Exception {
+        IdPair testCall = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+
+        assertTrue(analyticsMap.containsKey(testCall.mCallId));
+
+        Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
+        assertTrue(callAnalytics.startTime > 0);
+        assertEquals(0, callAnalytics.endTime);
+        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection);
+        assertFalse(callAnalytics.isInterrupted);
+        assertNull(callAnalytics.callTerminationReason);
+        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
+                callAnalytics.connectionService);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
+
+        analyticsMap = Analytics.cloneData();
+        callAnalytics = analyticsMap.get(testCall.mCallId);
+        assertTrue(callAnalytics.endTime > 0);
+        assertNotNull(callAnalytics.callTerminationReason);
+        assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode());
+
+        StringWriter sr = new StringWriter();
+        IndentingPrintWriter ip = new IndentingPrintWriter(sr, "    ");
+        Analytics.dump(ip);
+        String dumpResult = sr.toString();
+        String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
+                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
+        for (String field : expectedFields) {
+            assertTrue(dumpResult.contains(field));
+        }
+    }
+
+    @MediumTest
+    public void testAnalyticsDumping() throws Exception {
+        Analytics.reset();
+        IdPair testCall = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
+        Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId);
+
+        TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE);
+        List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics().getCallAnalytics();
+
+        assertEquals(1, analyticsList.size());
+        ParcelableCallAnalytics pCA = analyticsList.get(0);
+
+        assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) <
+                ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
+        assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
+        assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) -
+                pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
+        assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
+
+        assertEquals(expectedAnalytics.callDirection, pCA.getCallType());
+        assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall());
+        assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted());
+        assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies());
+        assertEquals(expectedAnalytics.callTerminationReason.getCode(),
+                pCA.getCallTerminationCode());
+        assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService());
+        List<ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents = pCA.analyticsEvents();
+        Set<Integer> capturedEvents = new HashSet<>();
+        for (ParcelableCallAnalytics.AnalyticsEvent e : analyticsEvents) {
+            capturedEvents.add(e.getEventName());
+            assertIsRoundedToOneSigFig(e.getTimeSinceLastEvent());
+        }
+        assertTrue(capturedEvents.contains(ParcelableCallAnalytics.AnalyticsEvent.SET_ACTIVE));
+        assertTrue(capturedEvents.contains(
+                ParcelableCallAnalytics.AnalyticsEvent.FILTERING_INITIATED));
+    }
+
+    @MediumTest
+    public void testAnalyticsTwoCalls() throws Exception {
+        IdPair testCall1 = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        IdPair testCall2 = startAndMakeActiveOutgoingCall(
+                "650-555-1213",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        assertTrue(analyticsMap.containsKey(testCall1.mCallId));
+        assertTrue(analyticsMap.containsKey(testCall2.mCallId));
+
+        Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId);
+        Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId);
+        assertTrue(callAnalytics1.startTime > 0);
+        assertTrue(callAnalytics2.startTime > 0);
+        assertEquals(0, callAnalytics1.endTime);
+        assertEquals(0, callAnalytics2.endTime);
+
+        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
+        assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
+
+        assertTrue(callAnalytics1.isInterrupted);
+        assertTrue(callAnalytics2.isAdditionalCall);
+
+        assertNull(callAnalytics1.callTerminationReason);
+        assertNull(callAnalytics2.callTerminationReason);
+
+        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
+                callAnalytics1.connectionService);
+        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
+                callAnalytics1.connectionService);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE);
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR);
+
+        analyticsMap = Analytics.cloneData();
+        callAnalytics1 = analyticsMap.get(testCall1.mCallId);
+        callAnalytics2 = analyticsMap.get(testCall2.mCallId);
+        assertTrue(callAnalytics1.endTime > 0);
+        assertTrue(callAnalytics2.endTime > 0);
+        assertNotNull(callAnalytics1.callTerminationReason);
+        assertNotNull(callAnalytics2.callTerminationReason);
+        assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode());
+        assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode());
+    }
+
+    @MediumTest
+    public void testAnalyticsVideo() throws Exception {
+        Analytics.reset();
+        IdPair callIds = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        CountDownLatch counter = new CountDownLatch(1);
+        InCallService.VideoCall.Callback callback = mock(InCallService.VideoCall.Callback.class);
+
+        doAnswer(invocation -> {
+            counter.countDown();
+            return null;
+        }).when(callback)
+                .onSessionModifyResponseReceived(anyInt(), any(VideoProfile.class),
+                        any(VideoProfile.class));
+
+        mConnectionServiceFixtureA.sendSetVideoProvider(
+                mConnectionServiceFixtureA.mLatestConnectionId);
+        InCallService.VideoCall videoCall =
+                mInCallServiceFixtureX.getCall(callIds.mCallId).getVideoCallImpl();
+        videoCall.registerCallback(callback);
+        ((VideoCallImpl) videoCall).setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
+
+        videoCall.sendSessionModifyRequest(new VideoProfile(VideoProfile.STATE_RX_ENABLED));
+        counter.await(10000, TimeUnit.MILLISECONDS);
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        Analytics.dumpToEncodedProto(pw, new String[]{});
+        TelecomLogClass.TelecomLog analyticsProto =
+                TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
+
+        assertEquals(1, analyticsProto.callLogs.length);
+        TelecomLogClass.VideoEvent[] videoEvents = analyticsProto.callLogs[0].videoEvents;
+        assertEquals(2, videoEvents.length);
+
+        assertEquals(Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST, videoEvents[0].getEventName());
+        assertEquals(VideoProfile.STATE_RX_ENABLED, videoEvents[0].getVideoState());
+        assertEquals(-1, videoEvents[0].getTimeSinceLastEventMillis());
+
+        assertEquals(Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
+                videoEvents[1].getEventName());
+        assertEquals(VideoProfile.STATE_RX_ENABLED, videoEvents[1].getVideoState());
+        assertIsRoundedToOneSigFig(videoEvents[1].getTimeSinceLastEventMillis());
+    }
+
+    @SmallTest
+    public void testAnalyticsRounding() {
+        long[] testVals = {0, -1, -10, -100, -57836, 1, 10, 100, 1000, 458457};
+        long[] expected = {0, -1, -10, -100, -60000, 1, 10, 100, 1000, 500000};
+        for (int i = 0; i < testVals.length; i++) {
+            assertEquals(expected[i], Analytics.roundToOneSigFig(testVals[i]));
+        }
+    }
+
+    @SmallTest
+    public void testAnalyticsLogSessionTiming() throws Exception {
+        long minTime = 50;
+        Log.startSession(Log.Sessions.CSW_ADD_CONFERENCE_CALL);
+        Thread.sleep(minTime);
+        Log.endSession();
+        TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE);
+        List<TelecomAnalytics.SessionTiming> sessions = tm.dumpAnalytics().getSessionTimings();
+        sessions.stream()
+                .filter(s -> Log.Sessions.CSW_ADD_CONFERENCE_CALL.equals(
+                        Analytics.sSessionIdToLogSession.get(s.getKey())))
+                .forEach(s -> assertTrue(s.getTime() >= minTime));
+    }
+
+    @MediumTest
+    public void testAnalyticsDumpToProto() throws Exception {
+        Analytics.reset();
+        IdPair testCall = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
+        Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId);
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        Analytics.dumpToEncodedProto(pw, new String[]{});
+        TelecomLogClass.TelecomLog analyticsProto =
+                TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
+
+        assertEquals(1, analyticsProto.callLogs.length);
+        TelecomLogClass.CallLog callLog = analyticsProto.callLogs[0];
+
+        assertTrue(Math.abs(expectedAnalytics.startTime - callLog.getStartTime5Min()) <
+                ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
+        assertEquals(0, callLog.getStartTime5Min() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
+        assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) -
+                callLog.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
+        assertEquals(0,
+                callLog.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
+
+        assertEquals(expectedAnalytics.callDirection, callLog.getType());
+        assertEquals(expectedAnalytics.isAdditionalCall, callLog.getIsAdditionalCall());
+        assertEquals(expectedAnalytics.isInterrupted, callLog.getIsInterrupted());
+        assertEquals(expectedAnalytics.callTechnologies, callLog.getCallTechnologies());
+        assertEquals(expectedAnalytics.callTerminationReason.getCode(),
+                callLog.getCallTerminationCode());
+        assertEquals(expectedAnalytics.connectionService, callLog.connectionService[0]);
+        TelecomLogClass.Event[] analyticsEvents = callLog.callEvents;
+        Set<Integer> capturedEvents = new HashSet<>();
+        for (TelecomLogClass.Event e : analyticsEvents) {
+            capturedEvents.add(e.getEventName());
+            assertIsRoundedToOneSigFig(e.getTimeSinceLastEventMillis());
+        }
+        assertTrue(capturedEvents.contains(ParcelableCallAnalytics.AnalyticsEvent.SET_ACTIVE));
+        assertTrue(capturedEvents.contains(
+                ParcelableCallAnalytics.AnalyticsEvent.FILTERING_INITIATED));
+    }
+
+    @MediumTest
+    public void testAnalyticsConnectionProperties() throws Exception {
+        Analytics.reset();
+        IdPair testCall = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        int properties1 = Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE
+                | Connection.PROPERTY_WIFI
+                | Connection.PROPERTY_EMERGENCY_CALLBACK_MODE;
+        int properties2 = Connection.PROPERTY_HIGH_DEF_AUDIO
+                | Connection.PROPERTY_WIFI;
+        int expectedProperties = properties1 | properties2;
+
+        mConnectionServiceFixtureA.mConnectionById.get(testCall.mConnectionId).properties =
+                properties1;
+        mConnectionServiceFixtureA.sendSetConnectionProperties(testCall.mConnectionId);
+        mConnectionServiceFixtureA.mConnectionById.get(testCall.mConnectionId).properties =
+                properties2;
+        mConnectionServiceFixtureA.sendSetConnectionProperties(testCall.mConnectionId);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        Analytics.dumpToEncodedProto(pw, new String[]{});
+        TelecomLogClass.TelecomLog analyticsProto =
+                TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
+
+        assertEquals(expectedProperties,
+                analyticsProto.callLogs[0].getConnectionProperties() & expectedProperties);
+    }
+
+    private void assertIsRoundedToOneSigFig(long x) {
+        assertEquals(x, Analytics.roundToOneSigFig(x));
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 11a5624..6688ca0 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -27,7 +27,6 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IContentProvider;
 import android.media.AudioManager;
@@ -43,19 +42,15 @@
 import android.telecom.ConnectionRequest;
 import android.telecom.DisconnectCause;
 import android.telecom.ParcelableCall;
-import android.telecom.ParcelableCallAnalytics;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telecom.IInCallAdapter;
 import com.android.internal.telephony.CallerInfo;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.telecom.Analytics;
 import com.android.server.telecom.Log;
 
 import com.google.common.base.Predicate;
@@ -63,9 +58,6 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import java.io.StringWriter;
-import java.util.List;
-import java.util.Map;
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
@@ -73,13 +65,6 @@
 
 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.
  */
@@ -137,7 +122,7 @@
         telecomManager.acceptRingingCall();
 
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .answer(ids.mCallId);
+                .answer(ids.mConnectionId);
         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
 
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
@@ -165,7 +150,7 @@
 
         // Answer video API should be called
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
+                .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL));
         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
 
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
@@ -192,7 +177,7 @@
 
         // The generic answer method on the ConnectionService is used to answer audio-only calls.
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .answer(eq(ids.mCallId));
+                .answer(eq(ids.mConnectionId));
         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
 
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
@@ -220,7 +205,7 @@
 
         // Answer video API should be called
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
+                .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL));
         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
     }
@@ -293,6 +278,7 @@
                 .createConnection(any(PhoneAccountHandle.class), anyString(),
                         any(ConnectionRequest.class), eq(true), eq(false));
 
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
         for (CallerInfoAsyncQueryFactoryFixture.Request request :
                 mCallerInfoAsyncQueryFactoryFixture.mRequests) {
@@ -329,10 +315,12 @@
         mTelecomSystem.getTelecomServiceImpl().getBinder()
                 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
 
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         verify(mConnectionServiceFixtureA.getTestDouble())
                 .createConnection(any(PhoneAccountHandle.class), anyString(),
                         any(ConnectionRequest.class), eq(true), eq(false));
 
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         // Never reply to the caller info lookup.
         assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
 
@@ -372,10 +360,12 @@
         mTelecomSystem.getTelecomServiceImpl().getBinder()
                 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
 
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         verify(mConnectionServiceFixtureA.getTestDouble())
                 .createConnection(any(PhoneAccountHandle.class), anyString(),
                         any(ConnectionRequest.class), eq(true), eq(false));
 
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
         for (CallerInfoAsyncQueryFactoryFixture.Request request :
                 mCallerInfoAsyncQueryFactoryFixture.mRequests) {
@@ -658,7 +648,7 @@
 
         mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null);
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .sendCallEvent(ids.mCallId, TEST_EVENT, null);
+                .sendCallEvent(ids.mConnectionId, TEST_EVENT, null);
     }
 
     /**
@@ -679,136 +669,11 @@
         mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT,
                 testBundle);
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
-                .sendCallEvent(eq(ids.mCallId), eq(TEST_EVENT),
+                .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT),
                         bundleArgumentCaptor.capture());
         assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
     }
 
-    @MediumTest
-    public void testAnalyticsSingleCall() throws Exception {
-        IdPair testCall = startAndMakeActiveIncomingCall(
-                "650-555-1212",
-                mPhoneAccountA0.getAccountHandle(),
-                mConnectionServiceFixtureA);
-        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
-
-        assertTrue(analyticsMap.containsKey(testCall.mCallId));
-
-        Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
-        assertTrue(callAnalytics.startTime > 0);
-        assertEquals(0, callAnalytics.endTime);
-        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection);
-        assertFalse(callAnalytics.isInterrupted);
-        assertNull(callAnalytics.callTerminationReason);
-        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
-                callAnalytics.connectionService);
-
-        mConnectionServiceFixtureA.
-                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
-
-        analyticsMap = Analytics.cloneData();
-        callAnalytics = analyticsMap.get(testCall.mCallId);
-        assertTrue(callAnalytics.endTime > 0);
-        assertNotNull(callAnalytics.callTerminationReason);
-        assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode());
-
-        StringWriter sr = new StringWriter();
-        IndentingPrintWriter ip = new IndentingPrintWriter(sr, "    ");
-        Analytics.dump(ip);
-        String dumpResult = sr.toString();
-        String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
-                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
-        for (String field : expectedFields) {
-            assertTrue(dumpResult.contains(field));
-        }
-    }
-
-    @SmallTest
-    public void testAnalyticsDumping() throws Exception {
-        Analytics.reset();
-        IdPair testCall = startAndMakeActiveIncomingCall(
-                "650-555-1212",
-                mPhoneAccountA0.getAccountHandle(),
-                mConnectionServiceFixtureA);
-
-        mConnectionServiceFixtureA.
-                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
-        Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId);
-
-        TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE);
-        List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics();
-
-        assertEquals(1, analyticsList.size());
-        ParcelableCallAnalytics pCA = analyticsList.get(0);
-
-        assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) <
-                ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
-        assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
-        assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) -
-                pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
-        assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
-
-        assertEquals(expectedAnalytics.callDirection, pCA.getCallType());
-        assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall());
-        assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted());
-        assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies());
-        assertEquals(expectedAnalytics.callTerminationReason.getCode(),
-                pCA.getCallTerminationCode());
-        assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService());
-    }
-
-    @MediumTest
-    public void testAnalyticsTwoCalls() throws Exception {
-        IdPair testCall1 = startAndMakeActiveIncomingCall(
-                "650-555-1212",
-                mPhoneAccountA0.getAccountHandle(),
-                mConnectionServiceFixtureA);
-        IdPair testCall2 = startAndMakeActiveOutgoingCall(
-                "650-555-1213",
-                mPhoneAccountA0.getAccountHandle(),
-                mConnectionServiceFixtureA);
-
-        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
-        assertTrue(analyticsMap.containsKey(testCall1.mCallId));
-        assertTrue(analyticsMap.containsKey(testCall2.mCallId));
-
-        Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId);
-        Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId);
-        assertTrue(callAnalytics1.startTime > 0);
-        assertTrue(callAnalytics2.startTime > 0);
-        assertEquals(0, callAnalytics1.endTime);
-        assertEquals(0, callAnalytics2.endTime);
-
-        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
-        assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
-
-        assertTrue(callAnalytics1.isInterrupted);
-        assertTrue(callAnalytics2.isAdditionalCall);
-
-        assertNull(callAnalytics1.callTerminationReason);
-        assertNull(callAnalytics2.callTerminationReason);
-
-        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
-                callAnalytics1.connectionService);
-        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
-                callAnalytics1.connectionService);
-
-        mConnectionServiceFixtureA.
-                sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE);
-        mConnectionServiceFixtureA.
-                sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR);
-
-        analyticsMap = Analytics.cloneData();
-        callAnalytics1 = analyticsMap.get(testCall1.mCallId);
-        callAnalytics2 = analyticsMap.get(testCall2.mCallId);
-        assertTrue(callAnalytics1.endTime > 0);
-        assertTrue(callAnalytics2.endTime > 0);
-        assertNotNull(callAnalytics1.callTerminationReason);
-        assertNotNull(callAnalytics2.callTerminationReason);
-        assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode());
-        assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode());
-    }
-
     private void blockNumber(String phoneNumber) throws Exception {
         blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() {
             @Override
@@ -843,6 +708,44 @@
     }
 
     /**
+     * Tests to make sure that the Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is set on a
+     * Call that is based on a Connection with the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY
+     * property set.
+     */
+    @MediumTest
+    public void testCdmaEnhancedPrivacyVoiceCall() throws Exception {
+        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
+                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
+
+        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        assertTrue(Call.Details.hasProperty(
+                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
+                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
+    }
+
+    /**
+     * Tests to make sure that Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY is dropped
+     * when the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is removed from the Connection.
+     */
+    @MediumTest
+    public void testDropCdmaEnhancedPrivacyVoiceCall() throws Exception {
+        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
+                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
+
+        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        mConnectionServiceFixtureA.mLatestConnection.setConnectionProperties(0);
+
+        assertFalse(Call.Details.hasProperty(
+                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
+                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
+    }
+
+    /**
      * Tests the {@link Call#pullExternalCall()} API.  Ensures that an external call which is
      * pullable can be pulled.
      *
@@ -864,7 +767,7 @@
         // 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);
+                .pullExternalCall(ids.mConnectionId);
     }
 
     /**
@@ -888,6 +791,56 @@
         // 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);
+                .pullExternalCall(ids.mConnectionId);
+    }
+
+    public void testMergeFailedAndNotifyInCallUi() throws Exception {
+        IdPair testCall1 = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        IdPair testCall2 = startAndMakeActiveOutgoingCall(
+                "650-555-1213",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        assertEquals(Call.STATE_ACTIVE,
+                mInCallServiceFixtureX.getCall(testCall1.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE,
+                mInCallServiceFixtureX.getCall(testCall2.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE,
+                mInCallServiceFixtureY.getCall(testCall1.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE,
+                mInCallServiceFixtureY.getCall(testCall2.mCallId).getState());
+
+        // Conference will not occur and instead will send setConferenceMergeFailed
+        ((ConnectionServiceFixture.FakeConnection)
+                mConnectionServiceFixtureA.mLatestConnection).setIsConferenceCreated(false);
+        mInCallServiceFixtureX.getInCallAdapter().conference(testCall2.mCallId, testCall1.mCallId);
+
+        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
+                eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
+        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
+                eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
+    }
+
+    @LargeTest
+    public void testEmergencyCallFailMoveToSecondSim() throws Exception {
+        IdPair ids = startAndMakeDialingEmergencyCall("650-555-1212",
+                mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        // The Emergency Call has failed on the default SIM with an ERROR Disconnect Cause. Retry
+        // with the other SIM PhoneAccount
+        IdPair newIds = triggerEmergencyRedial(mPhoneAccountE1.getAccountHandle(),
+                mConnectionServiceFixtureA, ids);
+
+        // Call should be active on the E1 PhoneAccount
+        mConnectionServiceFixtureA.sendSetActive(newIds.mConnectionId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(newIds.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(newIds.mCallId).getState());
+        assertEquals(mInCallServiceFixtureX.getCall(ids.mCallId).getAccountHandle(),
+                mPhoneAccountE1.getAccountHandle());
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
index f9502dd..38ea10e 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
@@ -18,6 +18,7 @@
 
 import android.media.AudioManager;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.CallAudioModeStateMachine;
@@ -32,6 +33,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 public class CallAudioModeStateMachineTest extends StateMachineTestBase<CallAudioModeStateMachine> {
     private static class ModeTestParameters extends TestParameters {
@@ -100,6 +102,37 @@
         parametrizedTestStateMachine(testCases);
     }
 
+    @SmallTest
+    public void testNoFocusWhenRingerSilenced() throws Throwable {
+        CallAudioModeStateMachine sm = new CallAudioModeStateMachine(mAudioManager);
+        sm.setCallAudioManager(mCallAudioManager);
+        sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
+        waitForStateMachineActionCompletion(sm, CallAudioModeStateMachine.RUN_RUNNABLE);
+
+        resetMocks();
+        when(mCallAudioManager.startRinging()).thenReturn(false);
+
+        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL,
+                new CallAudioModeStateMachine.MessageArgs(
+                        false, // hasActiveOrDialingCalls
+                        true, // hasRingingCalls
+                        false, // hasHoldingCalls
+                        false, // isTonePlaying
+                        false, // foregroundCallIsVoip
+                        null // session
+                ));
+        waitForStateMachineActionCompletion(sm, CallAudioModeStateMachine.RUN_RUNNABLE);
+
+        assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
+
+        verify(mAudioManager, never()).requestAudioFocusForCall(anyInt(), anyInt());
+        verify(mAudioManager, never()).setMode(anyInt());
+
+        verify(mCallAudioManager, never()).stopRinging();
+
+        verify(mCallAudioManager).stopCallWaiting();
+    }
+
     private List<ModeTestParameters> generateTestCases() {
         List<ModeTestParameters> result = new ArrayList<>();
         result.add(new ModeTestParameters(
@@ -516,6 +549,7 @@
         waitForStateMachineActionCompletion(sm, CallAudioModeStateMachine.RUN_RUNNABLE);
 
         resetMocks();
+        when(mCallAudioManager.startRinging()).thenReturn(true);
 
         sm.sendMessage(params.messageType, params.externalState);
         waitForStateMachineActionCompletion(sm, CallAudioModeStateMachine.RUN_RUNNABLE);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index c4526e4..dddf9e6 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.tests;
 
+import android.app.NotificationManager;
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -31,7 +32,9 @@
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.ConnectionServiceWrapper;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.StatusBarNotifier;
+import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.WiredHeadsetManager;
 
 import org.mockito.ArgumentCaptor;
@@ -42,14 +45,20 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -63,27 +72,37 @@
     static class RoutingTestParameters extends TestParameters {
         public String name;
         public int initialRoute;
+        public int initialNotificationFilter;
         public int availableRoutes; // may excl. speakerphone, because that's always available
         public int speakerInteraction; // one of NONE, ON, or OFF
         public int bluetoothInteraction; // one of NONE, ON, or OFF
         public int action;
         public int expectedRoute;
         public int expectedAvailableRoutes; // also may exclude the speakerphone.
+        public int expectedNotificationFilter; // expected end notification filter.
+        public boolean isNotificationChangeExpected; // indicates whether we expect the notification
+                                                     // filter to change during the process of the
+                                                     // test.
         public boolean doesDeviceSupportEarpiece; // set to false in the case of Wear devices
         public boolean shouldRunWithFocus;
 
-        public RoutingTestParameters(String name, int initialRoute, int availableRoutes, int
-                speakerInteraction, int bluetoothInteraction, int action, int expectedRoute, int
-                expectedAvailableRoutes, boolean doesDeviceSupportEarpiece,
+        public RoutingTestParameters(String name, int initialRoute,
+                int initialNotificationFilter, int availableRoutes, int speakerInteraction,
+                int bluetoothInteraction, int action, int expectedRoute,
+                int expectedAvailableRoutes, int expectedNotificationFilter,
+                boolean isNotificationChangeExpected, boolean doesDeviceSupportEarpiece,
                 boolean shouldRunWithFocus) {
             this.name = name;
             this.initialRoute = initialRoute;
+            this.initialNotificationFilter = initialNotificationFilter;
             this.availableRoutes = availableRoutes;
             this.speakerInteraction = speakerInteraction;
             this.bluetoothInteraction = bluetoothInteraction;
             this.action = action;
             this.expectedRoute = expectedRoute;
             this.expectedAvailableRoutes = expectedAvailableRoutes;
+            this.expectedNotificationFilter = expectedNotificationFilter;
+            this.isNotificationChangeExpected = isNotificationChangeExpected;
             this.doesDeviceSupportEarpiece = doesDeviceSupportEarpiece;
             this.shouldRunWithFocus = shouldRunWithFocus;
         }
@@ -93,12 +112,15 @@
             return "RoutingTestParameters{" +
                     "name='" + name + '\'' +
                     ", initialRoute=" + initialRoute +
+                    ", initialNotificationFilter=" + initialNotificationFilter +
                     ", availableRoutes=" + availableRoutes +
                     ", speakerInteraction=" + speakerInteraction +
                     ", bluetoothInteraction=" + bluetoothInteraction +
                     ", action=" + action +
                     ", expectedRoute=" + expectedRoute +
                     ", expectedAvailableRoutes=" + expectedAvailableRoutes +
+                    ", expectedNotificationFilter= " + expectedNotificationFilter +
+                    ", isNotificationChangeExpected=" + isNotificationChangeExpected +
                     ", doesDeviceSupportEarpiece=" + doesDeviceSupportEarpiece +
                     ", shouldRunWithFocus=" + shouldRunWithFocus +
                     '}';
@@ -112,10 +134,12 @@
     @Mock WiredHeadsetManager mockWiredHeadsetManager;
     @Mock StatusBarNotifier mockStatusBarNotifier;
     @Mock Call fakeCall;
+    @Mock InterruptionFilterProxy mMockInterruptionFilterProxy;
 
     private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
     private static final int TEST_TIMEOUT = 500;
     private AudioManager mockAudioManager;
+    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
 
     @Override
     public void setUp() throws Exception {
@@ -132,12 +156,32 @@
         };
 
         when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
+        when(mockCallsManager.getLock()).thenReturn(mLock);
         when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper);
         when(fakeCall.isAlive()).thenReturn(true);
+        setupInterruptionFilterMocks();
+
         doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
                 any(CallAudioState.class));
     }
 
+    private void setupInterruptionFilterMocks() {
+        // These mock implementations keep track of when the caller sets the current notification
+        // filter, and ensures the same value is returned via getCurrentInterruptionFilter.
+        final int objId = Objects.hashCode(mMockInterruptionFilterProxy);
+        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                NotificationManager.INTERRUPTION_FILTER_ALL);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock i) {
+                int requestedFilter = (int) i.getArguments()[0];
+                when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                        requestedFilter);
+                return null;
+            }
+        }).when(mMockInterruptionFilterProxy).setInterruptionFilter(anyInt());
+    }
+
     @LargeTest
     public void testStateMachineTransitionsWithFocus() throws Throwable {
         List<RoutingTestParameters> paramList = generateTransitionTests(true);
@@ -159,6 +203,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
@@ -177,7 +222,7 @@
         stateMachine.initialize(initState);
 
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
-                CallAudioRouteStateMachine.HAS_FOCUS);
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET);
         CallAudioState expectedMiddleState = new CallAudioState(false,
                 CallAudioState.ROUTE_WIRED_HEADSET,
@@ -199,17 +244,19 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
         when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true);
+
         CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
         stateMachine.initialize(initState);
 
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
-                CallAudioRouteStateMachine.HAS_FOCUS);
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
         stateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE);
         CallAudioState expectedEndState = new CallAudioState(false,
@@ -218,18 +265,90 @@
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
         verifyNewSystemCallAudioState(initState, expectedEndState);
+        // Expecting to end up in earpiece, so we expect notifications to be filtered.
+        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALARMS,
+                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
         resetMocks();
-
         stateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH);
         stateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
-
         assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState());
     }
 
+    @MediumTest
+    public void testBluetoothRinging() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
+                true);
+
+        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
+        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
+        stateMachine.initialize(initState);
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.RINGING_FOCUS);
+        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
+
+        verify(mockBluetoothManager, never()).connectBluetoothAudio();
+        // Shouldn't change interruption filter when in bluetooth route.
+        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALL,
+                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
+        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
+        verify(mockBluetoothManager, times(1)).connectBluetoothAudio();
+    }
+
+    @MediumTest
+    public void testConnectBluetoothDuringRinging() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
+                true);
+
+        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
+        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(false);
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
+                CallAudioState.ROUTE_EARPIECE);
+        stateMachine.initialize(initState);
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.RINGING_FOCUS);
+        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
+        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
+        verify(mockBluetoothManager, never()).connectBluetoothAudio();
+        CallAudioState expectedEndState = new CallAudioState(false,
+                CallAudioState.ROUTE_BLUETOOTH,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
+        verifyNewSystemCallAudioState(initState, expectedEndState);
+
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
+        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
+        verify(mockBluetoothManager, times(1)).connectBluetoothAudio();
+    }
+
     @SmallTest
     public void testInitializationWithEarpieceNoHeadsetNoBluetooth() {
         CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
@@ -303,6 +422,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 doesDeviceSupportEarpiece);
         stateMachine.initialize();
         assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
@@ -313,12 +433,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -326,12 +449,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -339,12 +465,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -352,12 +481,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -365,12 +497,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during headset with bluetooth available", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -378,12 +513,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -391,12 +529,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -404,12 +545,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during speakerphone with bluetooth available", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -417,12 +561,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -430,12 +577,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during wired headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -443,12 +593,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -456,12 +609,31 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during bluetooth without headset in", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Disconnect bluetooth during bluetooth without headset in, priority mode ", // name
+                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
+                NONE, // speakerInteraction
+                OFF, // bluetoothInteraction
+                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -469,12 +641,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during bluetooth with headset in", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -482,12 +657,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -495,12 +673,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -508,12 +689,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -521,12 +705,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -534,12 +721,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 ON, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -547,12 +737,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to earpiece from bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -560,12 +753,47 @@
         params.add(new RoutingTestParameters(
                 "Switch to earpiece from speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Switch to earpiece from speakerphone, priority notifications", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Switch to earpiece from speakerphone, silent mode", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_NONE, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_NONE, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -573,12 +801,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 OFF, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -586,12 +817,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -599,12 +833,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from wired headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -612,12 +849,15 @@
         params.add(new RoutingTestParameters(
                 "Switch from bluetooth to wired/earpiece when neither are available", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 ON, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 false, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -625,12 +865,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect wired headset when device does not support earpiece", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 false, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -651,6 +894,8 @@
     private void runParametrizedTestCaseWithFocus(final RoutingTestParameters params)
             throws Throwable {
         resetMocks();
+        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                params.initialNotificationFilter);
 
         // Construct a fresh state machine on every case
         final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
@@ -660,6 +905,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 params.doesDeviceSupportEarpiece);
 
         // Set up bluetooth and speakerphone state
@@ -668,20 +914,37 @@
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(
                 (params.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0
                         || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0);
-        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(
-                params.initialRoute == CallAudioState.ROUTE_SPEAKER);
+        doReturn(params.initialRoute == CallAudioState.ROUTE_SPEAKER).when(mockAudioManager).
+                isSpeakerphoneOn();
 
         // Set the initial CallAudioState object
         final CallAudioState initState = new CallAudioState(false,
                 params.initialRoute, (params.availableRoutes | CallAudioState.ROUTE_SPEAKER));
         stateMachine.initialize(initState);
+
         // Make the state machine have focus so that we actually do something
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
-                CallAudioRouteStateMachine.HAS_FOCUS);
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
         stateMachine.sendMessageWithSessionInfo(params.action);
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
 
+        // Capture the changes made to the interruption filter and verify that the last change
+        // made to it matches the expected interruption filter.
+        if (params.isNotificationChangeExpected) {
+            ArgumentCaptor<Integer> interruptionCaptor = ArgumentCaptor.forClass(Integer.class);
+            verify(mMockInterruptionFilterProxy, timeout(TEST_TIMEOUT).atLeastOnce())
+                    .setInterruptionFilter(interruptionCaptor.capture());
+            List<Integer> interruptionFilterValues = interruptionCaptor.getAllValues();
+
+            int lastChange = interruptionFilterValues.get(interruptionFilterValues.size() - 1)
+                    .intValue();
+            assertEquals(params.expectedNotificationFilter, lastChange);
+        } else {
+            Thread.sleep(TEST_TIMEOUT);
+            verify(mMockInterruptionFilterProxy, never()).setInterruptionFilter(anyInt());
+        }
+
         stateMachine.quitStateMachine();
 
         // Verify interactions with the speakerphone and bluetooth systems
@@ -727,6 +990,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 params.doesDeviceSupportEarpiece);
 
         // Set up bluetooth and speakerphone state
@@ -787,8 +1051,11 @@
 
     private void resetMocks() {
         reset(mockAudioManager, mockBluetoothManager, mockCallsManager,
-                mockConnectionServiceWrapper);
+                mockConnectionServiceWrapper, mMockInterruptionFilterProxy);
+        mMockInterruptionFilterProxy = mock(InterruptionFilterProxy.class);
+        setupInterruptionFilterMocks();
         when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
+        when(mockCallsManager.getLock()).thenReturn(mLock);
         doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
                 any(CallAudioState.class));
     }
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index bd399ae..e9db543 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -28,14 +28,17 @@
 import android.location.CountryListener;
 import android.net.Uri;
 import android.os.Looper;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.Postsubmit;
 import android.provider.CallLog;
 import android.provider.CallLog.Calls;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.VideoProfile;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -53,6 +56,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -195,8 +199,13 @@
     public void testDontLogCallsFromEmergencyAccount() {
         when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
                 .thenReturn(makeFakePhoneAccount(EMERGENCY_ACCT_HANDLE, 0));
-        mComponentContextFixture.putBooleanResource(R.bool.allow_emergency_numbers_in_call_log,
-                false);
+        CarrierConfigManager mockCarrierConfigManager =
+                (CarrierConfigManager) mComponentContextFixture.getTestDouble()
+                        .getApplicationContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
+        when(mockCarrierConfigManager.getConfig()).thenReturn(bundle);
+
         Call fakeCall = makeFakeCall(
                 DisconnectCause.OTHER, // disconnectCauseCode
                 false, // isConference
@@ -285,7 +294,34 @@
         ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
         assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
                 Integer.valueOf(CallLog.Calls.MISSED_TYPE));
-        verify(mMissedCallNotifier).showMissedCallNotification(fakeMissedCall);
+        // Timeout needed because showMissedCallNotification is called from onPostExecute.
+        verify(mMissedCallNotifier, timeout(TEST_TIMEOUT_MILLIS))
+                .showMissedCallNotification(fakeMissedCall);
+    }
+
+    @MediumTest
+    public void testLogCallDirectionRejected() {
+        when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
+                .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID));
+        Call fakeMissedCall = makeFakeCall(
+                DisconnectCause.REJECTED, // disconnectCauseCode
+                false, // isConference
+                true, // isIncoming
+                1L, // creationTimeMillis
+                1000L, // ageMillis
+                TEL_PHONEHANDLE, // callHandle
+                mDefaultAccountHandle, // phoneAccountHandle
+                NO_VIDEO_STATE, // callVideoState
+                POST_DIAL_STRING, // postDialDigits
+                VIA_NUMBER_STRING, // viaNumber
+                null
+        );
+
+        mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE,
+                CallState.DISCONNECTED);
+        ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID);
+        assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE),
+                Integer.valueOf(Calls.REJECTED_TYPE));
     }
 
     @MediumTest
@@ -388,6 +424,7 @@
     }
 
     @MediumTest
+    @Postsubmit
     public void testLogCallDirectionOutgoingWithMultiUserCapability() {
         when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
                 .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle,
@@ -481,6 +518,7 @@
     }
 
     @MediumTest
+    @Postsubmit
     public void testLogCallDirectionOutgoingFromManagedProfile() {
         when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
                 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0));
@@ -631,10 +669,13 @@
 
     private void verifyNoInsertion() {
         try {
-            verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).never()).insert(any(String.class),
+            Thread.sleep(TEST_TIMEOUT_MILLIS);
+            verify(mContentProvider, never()).insert(any(String.class),
                     any(Uri.class), any(ContentValues.class));
         } catch (android.os.RemoteException e) {
             fail("Remote exception occurred during test execution");
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
     }
 
@@ -642,10 +683,13 @@
     private void verifyNoInsertionInUser(int userId) {
         try {
             Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId);
-            verify(getContentProviderForUser(userId), timeout(TEST_TIMEOUT_MILLIS).never())
+            Thread.sleep(TEST_TIMEOUT_MILLIS);
+            verify(getContentProviderForUser(userId), never())
                     .insert(any(String.class), eq(uri), any(ContentValues.class));
         } catch (android.os.RemoteException e) {
             fail("Remote exception occurred during test execution");
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
     }
 
@@ -694,6 +738,8 @@
         when(fakeCall.getViaNumber()).thenReturn(viaNumber);
         when(fakeCall.getInitiatingUser()).thenReturn(initiatingUser);
         when(fakeCall.getCallDataUsage()).thenReturn(callDataUsage);
+        when(fakeCall.isEmergencyCall()).thenReturn(
+                phoneAccountHandle.equals(EMERGENCY_ACCT_HANDLE));
         return fakeCall;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallerInfoLookupHelperTest.java b/tests/src/com/android/server/telecom/tests/CallerInfoLookupHelperTest.java
index 8ece571..f261d3e 100644
--- a/tests/src/com/android/server/telecom/tests/CallerInfoLookupHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallerInfoLookupHelperTest.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.CallerInfo;
 import com.android.internal.telephony.CallerInfoAsyncQuery;
@@ -43,6 +44,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.atMost;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -93,6 +95,16 @@
         }
     }
 
+    @SmallTest
+    public void testLookupWithEmptyHandle() {
+        CallerInfoLookupHelper.OnQueryCompleteListener listener = mock(
+                CallerInfoLookupHelper.OnQueryCompleteListener.class);
+        mCallerInfoLookupHelper.startLookup(Uri.EMPTY, listener);
+
+        verify(listener).onCallerInfoQueryComplete(eq(Uri.EMPTY), isNull(CallerInfo.class));
+        verifyProperCleanup();
+    }
+
     public void testSimpleLookup() {
         CallerInfoLookupHelper.OnQueryCompleteListener listener = mock(
                 CallerInfoLookupHelper.OnQueryCompleteListener.class);
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index fba4fb0..5ed941e 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -519,6 +519,9 @@
         for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
             ResolveInfo resolveInfo = new ResolveInfo();
             resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName);
+            resolveInfo.serviceInfo.metaData = new Bundle();
+            resolveInfo.serviceInfo.metaData.putBoolean(
+                    TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
             result.add(resolveInfo);
         }
         return result;
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 1831f0e..65e0d7f 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -102,24 +102,43 @@
         @Override
         public Connection onCreateOutgoingConnection(
                 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
-            mLatestConnection = new FakeConnection(request.getVideoState(), request.getAddress());
-            return mLatestConnection;
+            FakeConnection fakeConnection = new FakeConnection(request.getVideoState(),
+                    request.getAddress());
+            mLatestConnection = fakeConnection;
+            if (mCapabilities != NOT_SPECIFIED) {
+                fakeConnection.setConnectionCapabilities(mCapabilities);
+            }
+            if (mProperties != NOT_SPECIFIED) {
+                fakeConnection.setConnectionProperties(mProperties);
+            }
+            return fakeConnection;
         }
 
         @Override
         public void onConference(Connection cxn1, Connection cxn2) {
-            // Usually, this is implemented by something in Telephony, which does a bunch of radio
-            // work to conference the two connections together. Here we just short-cut that and
-            // declare them conferenced.
-            Conference fakeConference = new FakeConference();
-            fakeConference.addConnection(cxn1);
-            fakeConference.addConnection(cxn2);
-            mLatestConference = fakeConference;
-            addConference(fakeConference);
+            if (((FakeConnection) cxn1).getIsConferenceCreated()) {
+                // Usually, this is implemented by something in Telephony, which does a bunch of
+                // radio work to conference the two connections together. Here we just short-cut
+                // that and declare them conferenced.
+                Conference fakeConference = new FakeConference();
+                fakeConference.addConnection(cxn1);
+                fakeConference.addConnection(cxn2);
+                mLatestConference = fakeConference;
+                addConference(fakeConference);
+            } else {
+                try {
+                    sendSetConferenceMergeFailed(cxn1.getTelecomCallId());
+                } catch (Exception e) {
+                    Log.w(this, "Exception on sendSetConferenceMergeFailed: " + e.getMessage());
+                }
+            }
         }
     }
 
     public class FakeConnection extends Connection {
+        // Set to false if you wish the Conference merge to fail.
+        boolean mIsConferenceCreated = true;
+
         public FakeConnection(int videoState, Uri address) {
             super();
             int capabilities = getConnectionCapabilities();
@@ -128,7 +147,7 @@
             capabilities |= CAPABILITY_HOLD;
             setVideoState(videoState);
             setConnectionCapabilities(capabilities);
-            setActive();
+            setDialing();
             setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
         }
 
@@ -136,6 +155,14 @@
         public void onExtrasChanged(Bundle extras) {
             mExtrasLock.countDown();
         }
+
+        public boolean getIsConferenceCreated() {
+            return mIsConferenceCreated;
+        }
+
+        public void setIsConferenceCreated(boolean isConferenceCreated) {
+            mIsConferenceCreated = isConferenceCreated;
+        }
     }
 
     public class FakeConference extends Conference {
@@ -203,6 +230,7 @@
             c.videoState = request.getVideoState();
             c.mockVideoProvider = new MockVideoProvider();
             c.videoProvider = c.mockVideoProvider.getInterface();
+            c.isConferenceCreated = true;
             mConnectionById.put(id, c);
             mConnectionServiceDelegateAdapter.createConnection(connectionManagerPhoneAccount,
                     id, request, isIncoming, isUnknown);
@@ -320,6 +348,7 @@
         int videoState;
         boolean isVoipAudioMode;
         Bundle extras;
+        boolean isConferenceCreated;
     }
 
     public class ConferenceInfo {
@@ -408,6 +437,11 @@
         }
     }
 
+    public void sendSetConnectionProperties(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setConnectionProperties(id, mConnectionById.get(id).properties);
+        }
+    }
     public void sendSetIsConferenced(String id) throws Exception {
         for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
             a.setIsConferenced(id, mConnectionById.get(id).conferenceId);
@@ -525,6 +559,12 @@
         }
     }
 
+    public void sendSetConferenceMergeFailed(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setConferenceMergeFailed(id);
+        }
+    }
+
     /**
      * Waits until the {@link Connection#onExtrasChanged(Bundle)} API has been called on a
      * {@link Connection} or {@link Conference}.
diff --git a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java b/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
index ac74604..2ebb6fc 100644
--- a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
@@ -42,7 +42,6 @@
 
     public void setUp() throws Exception {
         super.setUp();
-        when(mCall.getHandle()).thenReturn(TEST_HANDLE);
     }
 
     @SmallTest
@@ -79,13 +78,32 @@
                 ));
     }
 
+    @SmallTest
+    public void testNullResponseFromLookupHelper() {
+        CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart(null);
+
+        queryListener.onCallerInfoQueryComplete(null, null);
+        verify(mCallback).onCallFilteringComplete(mCall,
+                new CallFilteringResult(
+                        true, // shouldAllowCall
+                        false, // shouldReject
+                        true, // shouldAddToCallLog
+                        true // shouldShowNotification
+                ));
+    }
+
     private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
+        return verifyLookupStart(TEST_HANDLE);
+    }
+
+    private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart(Uri handle) {
+        when(mCall.getHandle()).thenReturn(handle);
         DirectToVoicemailCallFilter filter =
                 new DirectToVoicemailCallFilter(mCallerInfoLookupHelper);
         filter.startFilterLookup(mCall, mCallback);
         ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> captor =
                 ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
-        verify(mCallerInfoLookupHelper).startLookup(eq(TEST_HANDLE), captor.capture());
+        verify(mCallerInfoLookupHelper).startLookup(eq(handle), captor.capture());
         return captor.getValue();
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 2468774..f5c0439 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
@@ -28,15 +29,17 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
-import android.telecom.ConnectionService;
 import android.telecom.InCallService;
+import android.telecom.ParcelableCall;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.text.TextUtils;
 
 import com.android.internal.telecom.IInCallAdapter;
 import com.android.internal.telecom.IInCallService;
+import com.android.server.telecom.Analytics;
 import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallsManager;
@@ -46,22 +49,24 @@
 import com.android.server.telecom.SystemStateProvider;
 import com.android.server.telecom.TelecomServiceImpl.DefaultDialerManagerAdapter;
 import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.Timeouts;
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
+import java.util.Collections;
 import java.util.LinkedList;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyChar;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -79,6 +84,7 @@
     @Mock Resources mMockResources;
     @Mock MockContext mMockContext;
     @Mock DefaultDialerManagerAdapter mMockDefaultDialerAdapter;
+    @Mock Timeouts.Adapter mTimeoutsAdapter;
 
     private static final int CURRENT_USER_ID = 900973;
     private static final String DEF_PKG = "defpkg";
@@ -90,17 +96,18 @@
 
     private UserHandle mUserHandle = UserHandle.of(CURRENT_USER_ID);
     private InCallController mInCallController;
-    private TelecomSystem.SyncRoot mLock;
+    private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {};
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
+        when(mMockCall.getAnalytics()).thenReturn(new Analytics.CallInfo());
         doReturn(mMockResources).when(mMockContext).getResources();
         doReturn(SYS_PKG).when(mMockResources).getString(R.string.ui_default_package);
         doReturn(SYS_CLASS).when(mMockResources).getString(R.string.incall_default_class);
         mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
-                mMockSystemStateProvider, mMockDefaultDialerAdapter);
+                mMockSystemStateProvider, mMockDefaultDialerAdapter, mTimeoutsAdapter);
     }
 
     @Override
@@ -114,11 +121,9 @@
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
         when(mMockCall.isIncoming()).thenReturn(true);
+        when(mMockCall.isExternalCall()).thenReturn(false);
 
-        Intent queryIntent = new Intent(InCallService.SERVICE_INTERFACE);
-        when(mMockPackageManager.queryIntentServicesAsUser(
-                queryIntent, PackageManager.GET_META_DATA, CURRENT_USER_ID))
-            .thenReturn(new LinkedList<ResolveInfo>());
+        setupMockPackageManager(false /* default */, true /* system */, false /* external calls */);
         mInCallController.bindToServices(mMockCall);
 
         ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -146,11 +151,10 @@
         when(mMockCall.isIncoming()).thenReturn(false);
         when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockCall.getIntentExtras()).thenReturn(callExtras);
+        when(mMockCall.isExternalCall()).thenReturn(false);
 
         Intent queryIntent = new Intent(InCallService.SERVICE_INTERFACE);
-        when(mMockPackageManager.queryIntentServicesAsUser(
-                queryIntent, PackageManager.GET_META_DATA, CURRENT_USER_ID))
-            .thenReturn(new LinkedList<ResolveInfo>());
+        setupMockPackageManager(false /* default */, true /* system */, false /* external calls */);
         mInCallController.bindToServices(mMockCall);
 
         ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -181,36 +185,18 @@
         when(mMockCall.isIncoming()).thenReturn(false);
         when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockCall.getIntentExtras()).thenReturn(callExtras);
+        when(mMockCall.isExternalCall()).thenReturn(false);
         when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
                 .thenReturn(DEF_PKG);
         when(mMockContext.bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
                 anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
 
-        Intent queryIntent = new Intent(InCallService.SERVICE_INTERFACE);
-        when(mMockPackageManager.queryIntentServicesAsUser(
-                any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID)))
-            .thenReturn(new LinkedList<ResolveInfo>() {{
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = DEF_PKG;
-                    serviceInfo.name = DEF_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                    serviceInfo.metaData = new Bundle();
-                    serviceInfo.metaData.putBoolean(
-                            TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
-                }});
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = SYS_PKG;
-                    serviceInfo.name = SYS_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                }});
-            }});
+        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
         mInCallController.bindToServices(mMockCall);
 
         // Query for the different InCallServices
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockPackageManager, times(3)).queryIntentServicesAsUser(
+        verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
                 eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
 
@@ -249,37 +235,20 @@
         when(mMockCall.isIncoming()).thenReturn(false);
         when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockCall.getIntentExtras()).thenReturn(callExtras);
+        when(mMockCall.isExternalCall()).thenReturn(false);
         when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
                 .thenReturn(DEF_PKG);
         when(mMockContext.bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.CURRENT))).thenReturn(true);
 
-        Intent queryIntent = new Intent(InCallService.SERVICE_INTERFACE);
-        when(mMockPackageManager.queryIntentServicesAsUser(
-                any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID)))
-            .thenReturn(new LinkedList<ResolveInfo>() {{
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = DEF_PKG;
-                    serviceInfo.name = DEF_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                    serviceInfo.metaData = new Bundle();
-                    serviceInfo.metaData.putBoolean(
-                            TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
-                }});
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = SYS_PKG;
-                    serviceInfo.name = SYS_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                }});
-            }});
+        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+
         mInCallController.bindToServices(mMockCall);
 
         // Query for the different InCallServices
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockPackageManager, times(3)).queryIntentServicesAsUser(
+        verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
                 eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
 
@@ -315,40 +284,26 @@
         when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
+        when(mMockCallsManager.getAudioState()).thenReturn(null);
+        when(mMockCallsManager.canAddCall()).thenReturn(false);
         when(mMockCall.isIncoming()).thenReturn(false);
         when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
         when(mMockCall.getIntentExtras()).thenReturn(callExtras);
+        when(mMockCall.isExternalCall()).thenReturn(false);
+        when(mMockCall.getConferenceableCalls()).thenReturn(Collections.emptyList());
         when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
                 .thenReturn(DEF_PKG);
         when(mMockContext.bindServiceAsUser(
                 any(Intent.class), any(ServiceConnection.class), anyInt(), any(UserHandle.class)))
                 .thenReturn(true);
 
-        Intent queryIntent = new Intent(InCallService.SERVICE_INTERFACE);
-        when(mMockPackageManager.queryIntentServicesAsUser(
-                any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID)))
-            .thenReturn(new LinkedList<ResolveInfo>() {{
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = DEF_PKG;
-                    serviceInfo.name = DEF_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                    serviceInfo.metaData = new Bundle();
-                    serviceInfo.metaData.putBoolean(
-                            TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
-                }});
-                add(new ResolveInfo() {{
-                    serviceInfo = new ServiceInfo();
-                    serviceInfo.packageName = SYS_PKG;
-                    serviceInfo.name = SYS_CLASS;
-                    serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
-                }});
-            }});
+        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
         mInCallController.bindToServices(mMockCall);
 
         // Query for the different InCallServices
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockPackageManager, times(3)).queryIntentServicesAsUser(
+        verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
                 eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
 
@@ -404,4 +359,164 @@
         assertEquals(SYS_PKG, bindIntent.getComponent().getPackageName());
         assertEquals(SYS_CLASS, bindIntent.getComponent().getClassName());
     }
+
+    /**
+     * Ensures that the {@link InCallController} will bind to an {@link InCallService} which
+     * supports external calls.
+     */
+    @MediumTest
+    public void testBindToService_IncludeExternal() throws Exception {
+        setupMocks(true /* isExternalCall */);
+        setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+        mInCallController.bindToServices(mMockCall);
+
+        // Query for the different InCallServices
+        ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
+                queryIntentCaptor.capture(),
+                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+
+        // Verify call for default dialer InCallService
+        assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
+        // Verify call for car-mode InCallService
+        assertEquals(null, queryIntentCaptor.getAllValues().get(1).getPackage());
+        // Verify call for non-UI InCallServices
+        assertEquals(null, queryIntentCaptor.getAllValues().get(2).getPackage());
+
+        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockContext, times(1)).bindServiceAsUser(
+                bindIntentCaptor.capture(),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.CURRENT));
+
+        Intent bindIntent = bindIntentCaptor.getValue();
+        assertEquals(InCallService.SERVICE_INTERFACE, bindIntent.getAction());
+        assertEquals(DEF_PKG, bindIntent.getComponent().getPackageName());
+        assertEquals(DEF_CLASS, bindIntent.getComponent().getClassName());
+    }
+
+    /**
+     * Make sure that if a call goes away before the in-call service finishes binding and another
+     * call gets connected soon after, the new call will still be sent to the in-call service.
+     */
+    @MediumTest
+    public void testUnbindDueToCallDisconnect() throws Exception {
+        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
+        when(mMockCall.isIncoming()).thenReturn(true);
+        when(mMockCall.isExternalCall()).thenReturn(false);
+        when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
+                .thenReturn(DEF_PKG);
+        when(mMockContext.bindServiceAsUser(
+                any(Intent.class), any(ServiceConnection.class), anyInt(), any(UserHandle.class)))
+                .thenReturn(true);
+        when(mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(any(ContentResolver.class)))
+                .thenReturn(500L);
+
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
+        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+        mInCallController.bindToServices(mMockCall);
+
+        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
+                ArgumentCaptor.forClass(ServiceConnection.class);
+        verify(mMockContext, times(1)).bindServiceAsUser(
+                bindIntentCaptor.capture(),
+                serviceConnectionCaptor.capture(),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.CURRENT));
+
+        // Pretend that the call has gone away.
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList());
+        mInCallController.onCallRemoved(mMockCall);
+
+        // Start the connection, make sure we don't unbind, and make sure that we don't send
+        // anything to the in-call service yet.
+        ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
+        ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
+        IBinder mockBinder = mock(IBinder.class);
+        IInCallService mockInCallService = mock(IInCallService.class);
+        when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+
+        serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
+        verify(mockInCallService).setInCallAdapter(any(IInCallAdapter.class));
+        verify(mMockContext, never()).unbindService(serviceConnection);
+        verify(mockInCallService, never()).addCall(any(ParcelableCall.class));
+
+        // Now, we add in the call again and make sure that it's sent to the InCallService.
+        when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
+        mInCallController.onCallAdded(mMockCall);
+        verify(mockInCallService).addCall(any(ParcelableCall.class));
+    }
+
+    private void setupMocks(boolean isExternalCall) {
+        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockCallsManager.hasEmergencyCall()).thenReturn(false);
+        when(mMockCall.isIncoming()).thenReturn(false);
+        when(mMockCall.getTargetPhoneAccount()).thenReturn(PA_HANDLE);
+        when(mMockDefaultDialerAdapter.getDefaultDialerApplication(mMockContext, CURRENT_USER_ID))
+                .thenReturn(DEF_PKG);
+        when(mMockContext.bindServiceAsUser(any(Intent.class), any(ServiceConnection.class),
+                anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
+        when(mMockCall.isExternalCall()).thenReturn(isExternalCall);
+    }
+
+    private ResolveInfo getDefResolveInfo(final boolean includeExternalCalls) {
+        return new ResolveInfo() {{
+            serviceInfo = new ServiceInfo();
+            serviceInfo.packageName = DEF_PKG;
+            serviceInfo.name = DEF_CLASS;
+            serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+            serviceInfo.metaData = new Bundle();
+            serviceInfo.metaData.putBoolean(
+                    TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
+            if (includeExternalCalls) {
+                serviceInfo.metaData.putBoolean(
+                        TelecomManager.METADATA_INCLUDE_EXTERNAL_CALLS, true);
+            }
+        }};
+    }
+
+    private ResolveInfo getSysResolveinfo() {
+        return new ResolveInfo() {{
+            serviceInfo = new ServiceInfo();
+            serviceInfo.packageName = SYS_PKG;
+            serviceInfo.name = SYS_CLASS;
+            serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+        }};
+    }
+
+    private void setupMockPackageManager(final boolean useDefaultDialer,
+            final boolean useSystemDialer, final boolean includeExternalCalls) {
+
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                Intent intent = (Intent) args[0];
+                String packageName = intent.getPackage();
+                ComponentName componentName = intent.getComponent();
+                if (componentName != null) {
+                    packageName = componentName.getPackageName();
+                }
+                LinkedList<ResolveInfo> resolveInfo = new LinkedList<ResolveInfo>();
+                if (!TextUtils.isEmpty(packageName)) {
+                    if ((TextUtils.isEmpty(packageName) || packageName.equals(DEF_PKG)) &&
+                            useDefaultDialer) {
+                        resolveInfo.add(getDefResolveInfo(includeExternalCalls));
+                    }
+
+                    if ((TextUtils.isEmpty(packageName) || packageName.equals(SYS_PKG)) &&
+                           useSystemDialer) {
+                        resolveInfo.add(getSysResolveinfo());
+                    }
+                }
+                return resolveInfo;
+            }
+        }).when(mMockPackageManager).queryIntentServicesAsUser(
+                any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/LogTest.java b/tests/src/com/android/server/telecom/tests/LogTest.java
index 586105f..20c4d63 100644
--- a/tests/src/com/android/server/telecom/tests/LogTest.java
+++ b/tests/src/com/android/server/telecom/tests/LogTest.java
@@ -16,29 +16,33 @@
 
 package com.android.server.telecom.tests;
 
-import android.content.ContentResolver;
-import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.os.SomeArgs;
-import com.android.server.telecom.Runnable;
+import com.android.server.telecom.Analytics;
+import com.android.server.telecom.Call;
 import com.android.server.telecom.Session;
 import com.android.server.telecom.SystemLoggingContainer;
 import com.android.server.telecom.Log;
 
 import org.junit.Assert;
+import org.mockito.ArgumentCaptor;
 import org.mockito.MockitoAnnotations;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * Unit tests for Telecom's Logging system.
@@ -456,6 +460,26 @@
         assertEquals(null, sessionRef.get());
     }
 
+    @SmallTest
+    public void testEventRecordTiming() throws Exception {
+        Call call = mock(Call.class);
+        Analytics.CallInfo mockCallInfo = mock(Analytics.CallInfo.class);
+        when(call.getAnalytics()).thenReturn(mockCallInfo);
+        int minWaitTime = 40;
+        Log.event(call, Log.Events.REQUEST_ACCEPT);
+        Thread.sleep(minWaitTime);
+        Log.event(call, Log.Events.SET_ACTIVE);
+
+        ArgumentCaptor<Log.CallEventRecord> captor =
+                ArgumentCaptor.forClass(Log.CallEventRecord.class);
+        verify(mockCallInfo).setCallEvents(captor.capture());
+        List<Log.CallEventRecord.EventTiming> eventTimings =
+                captor.getValue().extractEventTimings();
+        eventTimings.stream()
+                .filter(timing -> timing.name.equals("accept"))
+                .forEach(timing -> assertTrue(timing.time > minWaitTime));
+    }
+
     private void verifyMethodCall(String parentSessionName, String methodName, int sessionId,
             String subsession, String shortMethodName, int timeoutMs) {
         if (!parentSessionName.isEmpty()){
diff --git a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
index 2ac9c50..24c59ff 100644
--- a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
@@ -36,6 +36,7 @@
 import com.android.server.telecom.Constants;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
+import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
 import com.android.server.telecom.components.TelecomBroadcastReceiver;
 import com.android.server.telecom.ui.MissedCallNotifierImpl;
@@ -166,7 +167,7 @@
                 makeNotificationBuilderFactory(builders);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, fakeBuilderFactory);
+                mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
 
         missedCallNotifier.showMissedCallNotification(fakeCall);
         missedCallNotifier.showMissedCallNotification(fakeCall);
@@ -315,7 +316,7 @@
                 makeNotificationBuilderFactory(builder1);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, fakeBuilderFactory);
+                mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
 
         Call fakeCall =
@@ -374,7 +375,7 @@
     private MissedCallNotifier makeMissedCallNotifier(
             NotificationBuilderFactory fakeBuilderFactory, UserHandle currentUser) {
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, fakeBuilderFactory);
+                mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
         missedCallNotifier.setCurrentUserHandle(currentUser);
         return missedCallNotifier;
     }
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index a7d98db..54613d4 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -38,6 +38,7 @@
 import com.android.server.telecom.NewOutgoingCallIntentBroadcaster;
 import com.android.server.telecom.PhoneNumberUtilsAdapter;
 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
+import com.android.server.telecom.TelecomSystem;
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -77,6 +78,7 @@
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
         mPhoneNumberUtilsAdapterSpy = spy(new PhoneNumberUtilsAdapterImpl());
         when(mCall.getInitiatingUser()).thenReturn(UserHandle.CURRENT);
+        when(mCallsManager.getLock()).thenReturn(new TelecomSystem.SyncRoot() { });
     }
 
     @SmallTest
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index ceabc58..12d24c4 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -171,8 +171,7 @@
     public void testAccounts() throws Exception {
         int i = 0;
 
-        mComponentContextFixture.addConnectionService(
-                makeQuickConnectionServiceComponentName(),
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
                 Mockito.mock(IConnectionService.class));
 
         registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
@@ -205,8 +204,7 @@
 
     @MediumTest
     public void testDefaultOutgoing() throws Exception {
-        mComponentContextFixture.addConnectionService(
-                makeQuickConnectionServiceComponentName(),
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
                 Mockito.mock(IConnectionService.class));
 
         // By default, there is no default outgoing account (nothing has been registered)
@@ -253,6 +251,229 @@
     }
 
     @MediumTest
+    public void testReplacePhoneAccountByGroup() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Add call capable SIP account, make sure tel: doesn't change
+        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Replace tel: account with another in the same Group
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount2, defaultAccount);
+        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+    }
+
+    @MediumTest
+    public void testAddSameDefault() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        mRegistrar.unregisterPhoneAccount(telAccount1);
+
+        // Register Emergency Account and unregister
+        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertNull(defaultAccount);
+        mRegistrar.unregisterPhoneAccount(emerAccount);
+
+        // Re-register the same account and make sure the default is in place
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroup() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        mRegistrar.unregisterPhoneAccount(telAccount1);
+
+        // Register Emergency Account and unregister
+        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertNull(defaultAccount);
+        mRegistrar.unregisterPhoneAccount(emerAccount);
+
+        // Re-register a new account with the same group
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount2, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroupButDifferentComponent() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+
+        // Register a new account with the same group, but different Component, so don't replace
+        // Default
+        PhoneAccountHandle telAccount2 =  makeQuickAccountHandle(
+                new ComponentName("other1", "other2"), "tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
+
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroupButDifferentComponent2() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL));
+
+        // Register first tel: account
+        PhoneAccountHandle telAccount1 =  makeQuickAccountHandle(
+                new ComponentName("other1", "other2"), "tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+
+        // Register second account with the same group, but a second Component, so don't replace
+        // Default
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Register third account with the second component name, but same group id
+        PhoneAccountHandle telAccount3 = makeQuickAccountHandle("tel_acct3");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount3, "tel_acct3")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+
+        // Make sure that the default account is still the original PhoneAccount and that the
+        // second PhoneAccount with the second ComponentName was replaced by the third PhoneAccount
+        defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount3));
+    }
+
+    @MediumTest
     public void testPhoneAccountParceling() throws Exception {
         PhoneAccountHandle handle = makeQuickAccountHandle("foo");
         roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build());
@@ -268,6 +489,7 @@
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
+                        .setGroupId("testGroup")
                         .build());
         roundTripPhoneAccount(
                 new PhoneAccount.Builder(handle, "foo")
@@ -281,6 +503,7 @@
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
+                        .setGroupId("testGroup")
                         .build());
     }
 
@@ -291,10 +514,11 @@
     }
 
     private static PhoneAccountHandle makeQuickAccountHandle(String id) {
-        return new PhoneAccountHandle(
-                makeQuickConnectionServiceComponentName(),
-                id,
-                Process.myUserHandle());
+        return makeQuickAccountHandle(makeQuickConnectionServiceComponentName(), id);
+    }
+
+    private static PhoneAccountHandle makeQuickAccountHandle(ComponentName name, String id) {
+        return new PhoneAccountHandle(name, id, Process.myUserHandle());
     }
 
     private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
@@ -457,7 +681,8 @@
                 new ComponentName("pkg0", "cls0"), "id0");
         UserHandle userHandle = phoneAccountHandle.getUserHandle();
         s.defaultOutgoingAccountHandles
-                .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle));
+                .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
+                        "testGroup"));
         return s;
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 98231ce..8de54bf 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -53,7 +53,9 @@
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
+import org.mockito.Matchers;
 import org.mockito.Mock;
+import org.mockito.internal.matchers.VarargMatcher;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -139,6 +141,13 @@
         }
     }
 
+    private static class IntVarArgMatcher extends ArgumentMatcher<int[]> implements VarargMatcher {
+        @Override
+        public boolean matches(Object argument) {
+            return true;
+        }
+    }
+
     private ITelecomService.Stub mTSIBinder;
     private AppOpsManager mAppOpsManager;
     private UserManager mUserManager;
@@ -859,7 +868,7 @@
     public void testEndCallWithNoForegroundCall() throws Exception {
         Call call = mock(Call.class);
         when(call.getState()).thenReturn(CallState.ACTIVE);
-        when(mFakeCallsManager.getFirstCallWithState(anyInt(), anyInt(), anyInt(), anyInt()))
+        when(mFakeCallsManager.getFirstCallWithState(argThat(new IntVarArgMatcher())))
                 .thenReturn(call);
         assertTrue(mTSIBinder.endCall());
         verify(call).disconnect();
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 3bb069d..fab4540 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -44,11 +45,13 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
 import android.provider.BlockedNumberContract;
 import android.telecom.Call;
 import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
 import android.telecom.ParcelableCall;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -59,6 +62,7 @@
 import com.android.server.telecom.AsyncRingtonePlayer;
 import com.android.server.telecom.BluetoothPhoneServiceImpl;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.CallAudioRouteStateMachine;
 import com.android.server.telecom.CallerInfoAsyncQueryFactory;
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.CallsManagerListenerBase;
@@ -67,12 +71,17 @@
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockController;
 import com.android.server.telecom.InCallWakeLockControllerFactory;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
+import com.android.server.telecom.PhoneNumberUtilsAdapter;
+import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
 import com.android.server.telecom.ProximitySensorManager;
 import com.android.server.telecom.ProximitySensorManagerFactory;
+import com.android.server.telecom.Runnable;
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.Timeouts;
+import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
 import com.android.server.telecom.components.UserCallIntentProcessor;
 import com.android.server.telecom.ui.MissedCallNotifierImpl.MissedCallNotifierImplFactory;
 
@@ -87,6 +96,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Implements mocks and functionality required to implement telecom system tests.
@@ -146,12 +157,40 @@
     }
 
     MissedCallNotifierFakeImpl mMissedCallNotifier = new MissedCallNotifierFakeImpl();
+    private class EmergencyNumberUtilsAdapter extends PhoneNumberUtilsAdapterImpl {
+
+        @Override
+        public boolean isLocalEmergencyNumber(Context context, String number) {
+            return mIsEmergencyCall;
+        }
+
+        @Override
+        public boolean isPotentialLocalEmergencyNumber(Context context, String number) {
+            return mIsEmergencyCall;
+        }
+    }
+    PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter = new EmergencyNumberUtilsAdapter();
+
+    public static class MockInterruptionFilterProxy implements InterruptionFilterProxy {
+        private int mInterruptionFilter = NotificationManager.INTERRUPTION_FILTER_ALL;
+        @Override
+        public void setInterruptionFilter(int interruptionFilter) {
+            mInterruptionFilter = interruptionFilter;
+        }
+
+        @Override
+        public int getCurrentInterruptionFilter() {
+            return mInterruptionFilter;
+        }
+    }
+
     @Mock HeadsetMediaButton mHeadsetMediaButton;
     @Mock ProximitySensorManager mProximitySensorManager;
     @Mock InCallWakeLockController mInCallWakeLockController;
     @Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
     @Mock AsyncRingtonePlayer mAsyncRingtonePlayer;
     @Mock ViceNotifier mViceNotifier;
+    @Mock InterruptionFilterProxy mInterruptionFilterProxy;
 
     final ComponentName mInCallServiceComponentNameX =
             new ComponentName(
@@ -183,7 +222,8 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
     final PhoneAccount mPhoneAccountA1 =
             PhoneAccount.builder(
@@ -194,7 +234,8 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
     final PhoneAccount mPhoneAccountB0 =
             PhoneAccount.builder(
@@ -205,7 +246,35 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
+                    .build();
+    final PhoneAccount mPhoneAccountE0 =
+            PhoneAccount.builder(
+                    new PhoneAccountHandle(
+                            mConnectionServiceComponentNameA,
+                            "id E 0"),
+                    "Phone account service E ID 0")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
+                    .build();
+
+    final PhoneAccount mPhoneAccountE1 =
+            PhoneAccount.builder(
+                    new PhoneAccountHandle(
+                            mConnectionServiceComponentNameA,
+                            "id E 1"),
+                    "Phone account service E ID 1")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
 
     ConnectionServiceFixture mConnectionServiceFixtureA;
@@ -222,6 +291,8 @@
 
     private int mNumOutgoingCallsMade;
 
+    private boolean mIsEmergencyCall;
+
     class IdPair {
         final String mConnectionId;
         final String mCallId;
@@ -240,6 +311,8 @@
 
         mNumOutgoingCallsMade = 0;
 
+        mIsEmergencyCall = false;
+
         // First set up information about the In-Call services in the mock Context, since
         // Telecom will search for these as soon as it is instantiated
         setupInCallServices();
@@ -299,14 +372,15 @@
 
         mTimeoutsAdapter = mock(Timeouts.Adapter.class);
         when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
-                .thenReturn(TEST_TIMEOUT / 10L);
+                .thenReturn(TEST_TIMEOUT / 5L);
 
         mTelecomSystem = new TelecomSystem(
                 mComponentContextFixture.getTestDouble(),
                 new MissedCallNotifierImplFactory() {
                     @Override
                     public MissedCallNotifier makeMissedCallNotifierImpl(Context context,
-                            PhoneAccountRegistrar phoneAccountRegistrar) {
+                            PhoneAccountRegistrar phoneAccountRegistrar,
+                            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
                         return mMissedCallNotifier;
                     }
                 },
@@ -330,8 +404,9 @@
                 },
                 mTimeoutsAdapter,
                 mAsyncRingtonePlayer,
-                mViceNotifier
-            );
+                mViceNotifier,
+                mPhoneNumberUtilsAdapter,
+                mInterruptionFilterProxy);
 
         mComponentContextFixture.setTelecomManager(new TelecomManager(
                 mComponentContextFixture.getTestDouble(),
@@ -361,6 +436,8 @@
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0);
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1);
 
         mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
                 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle());
@@ -464,10 +541,46 @@
                 phoneAccountHandle, connectionServiceFixture);
     }
 
-    protected String startOutgoingPhoneCallPendingCreateConnection(String number,
+    protected IdPair triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)
+            throws Exception {
+        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
+        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+
+        // Send the message to disconnect the Emergency call due to an error.
+        // CreateConnectionProcessor should now try the second SIM account
+        connectionServiceFixture.sendSetDisconnected(emergencyIds.mConnectionId,
+                DisconnectCause.ERROR);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(
+                emergencyIds.mCallId).getState());
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(
+                emergencyIds.mCallId).getState());
+
+        return redialingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
+                phoneAccountHandle, connectionServiceFixture);
+    }
+
+    protected IdPair startOutgoingEmergencyCall(String number,
             PhoneAccountHandle phoneAccountHandle,
             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
             int videoState) throws Exception {
+        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
+        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+
+        mIsEmergencyCall = true;
+        // Call will not use the ordered broadcaster, since it is an Emergency Call
+        startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle,
+                connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/);
+
+        return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
+                phoneAccountHandle, connectionServiceFixture);
+    }
+
+    protected void startOutgoingPhoneCallWaitForBroadcaster(String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
+            int videoState, boolean isEmergency) throws Exception {
         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
                 mInCallServiceFixtureY.getTestDouble());
 
@@ -483,7 +596,11 @@
         Intent actionCallIntent = new Intent();
         actionCallIntent.setData(Uri.parse("tel:" + number));
         actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
-        actionCallIntent.setAction(Intent.ACTION_CALL);
+        if(isEmergency) {
+            actionCallIntent.setAction(Intent.ACTION_CALL_EMERGENCY);
+        } else {
+            actionCallIntent.setAction(Intent.ACTION_CALL);
+        }
         if (phoneAccountHandle != null) {
             actionCallIntent.putExtra(
                     TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
@@ -511,6 +628,14 @@
                     .setInCallAdapter(
                             any(IInCallAdapter.class));
         }
+    }
+
+    protected String startOutgoingPhoneCallPendingCreateConnection(String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
+            int videoState) throws Exception {
+        startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle,
+                connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/);
 
         ArgumentCaptor<Intent> newOutgoingCallIntent =
                 ArgumentCaptor.forClass(Intent.class);
@@ -542,6 +667,30 @@
         return mInCallServiceFixtureX.mLatestCallId;
     }
 
+    // When Telecom is redialing due to an error, we need to make sure the number of connections
+    // increase, but not the number of Calls in the InCallService.
+    protected IdPair redialingCallCreateConnectionComplete(int startingNumConnections,
+            int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+
+        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+
+        verify(connectionServiceFixture.getTestDouble())
+                .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
+                        eq(false)/*isIncoming*/, anyBoolean());
+        // Wait for handleCreateConnectionComplete
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+
+        // Make sure the number of registered InCallService Calls stays the same.
+        assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
+        assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
+
+        assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
+
+        return new IdPair(connectionServiceFixture.mLatestConnectionId,
+                mInCallServiceFixtureX.mLatestCallId);
+    }
+
     protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections,
             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
             ConnectionServiceFixture connectionServiceFixture) throws Exception {
@@ -550,9 +699,11 @@
 
         verify(connectionServiceFixture.getTestDouble())
                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
-                        anyBoolean(), anyBoolean());
-        connectionServiceFixture.sendHandleCreateConnectionComplete(
-                connectionServiceFixture.mLatestConnectionId);
+                        eq(false)/*isIncoming*/, anyBoolean());
+        // Wait for handleCreateConnectionComplete
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        // Wait for the callback in ConnectionService#onAdapterAttached to execute.
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
 
         assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
         assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
@@ -740,6 +891,20 @@
         return ids;
     }
 
+    protected IdPair startAndMakeDialingEmergencyCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle,
+                connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
+
+        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        return ids;
+    }
+
     protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
         int elapsed = 0;
         while (elapsed < TEST_TIMEOUT) {
diff --git a/tests/src/com/android/server/telecom/tests/VideoCallTests.java b/tests/src/com/android/server/telecom/tests/VideoCallTests.java
index c079857..0319e81 100644
--- a/tests/src/com/android/server/telecom/tests/VideoCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/VideoCallTests.java
@@ -18,10 +18,14 @@
 
 import org.mockito.ArgumentCaptor;
 
+import android.os.RemoteException;
 import android.telecom.CallAudioState;
 import android.telecom.VideoProfile;
+import android.test.suitebuilder.annotation.MediumTest;
 
+import com.android.server.telecom.CallAudioModeStateMachine;
 import com.android.server.telecom.CallAudioRouteStateMachine;
+import com.android.server.telecom.Log;
 
 import java.util.List;
 
@@ -39,6 +43,7 @@
      * Tests to ensure an incoming video-call is automatically routed to the speakerphone when
      * the call is answered and neither a wired headset nor bluetooth headset are connected.
      */
+    @MediumTest
     public void testAutoSpeakerphoneIncomingBidirectional() throws Exception {
         // Start an incoming video call.
         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
@@ -54,6 +59,7 @@
      * always answer incoming video calls as bi-directional.  It is, however, possible for a third
      * party dialer to answer an incoming video call a a one-way video call.
      */
+    @MediumTest
     public void testAutoSpeakerphoneIncomingReceiveOnly() throws Exception {
         // Start an incoming video call.
         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
@@ -67,6 +73,7 @@
      * Tests audio routing for an outgoing video call made with bidirectional video.  Expect to be
      * in speaker mode.
      */
+    @MediumTest
     public void testAutoSpeakerphoneOutgoingBidirectional() throws Exception {
         // Start an incoming video call.
         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
@@ -81,6 +88,7 @@
      * in speaker mode.  Note: The default UI does not support making one-way video calls, but the
      * APIs do and a third party incall UI could choose to support that.
      */
+    @MediumTest
     public void testAutoSpeakerphoneOutgoingTransmitOnly() throws Exception {
         // Start an incoming video call.
         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
@@ -95,6 +103,7 @@
      * in speaker mode.  Note: The default UI does not support making one-way video calls, but the
      * APIs do and a third party incall UI could choose to support that.
      */
+    @MediumTest
     public void testNoAutoSpeakerphoneOnOutgoing() throws Exception {
         // Start an incoming video call.
         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
@@ -107,6 +116,7 @@
     /**
      * Tests to ensure an incoming audio-only call is routed to the earpiece.
      */
+    @MediumTest
     public void testNoAutoSpeakerphoneOnIncoming() throws Exception {
 
         // Start an incoming video call.
@@ -127,13 +137,25 @@
     private void verifyAudioRoute(int expectedRoute) throws Exception {
         // Capture all onCallAudioStateChanged callbacks to InCall.
         CallAudioRouteStateMachine carsm = mTelecomSystem.getCallsManager()
-                        .getCallAudioManager().getCallAudioRouteStateMachine();
+                .getCallAudioManager().getCallAudioRouteStateMachine();
+        CallAudioModeStateMachine camsm = mTelecomSystem.getCallsManager()
+                .getCallAudioManager().getCallAudioModeStateMachine();
+        waitForHandlerAction(camsm.getHandler(), TEST_TIMEOUT);
+        final boolean[] success = {true};
+        carsm.sendMessage(CallAudioRouteStateMachine.RUN_RUNNABLE, (Runnable) () -> {
+            ArgumentCaptor<CallAudioState> callAudioStateArgumentCaptor = ArgumentCaptor.forClass(
+                    CallAudioState.class);
+            try {
+                verify(mInCallServiceFixtureX.getTestDouble(), atLeastOnce())
+                        .onCallAudioStateChanged(callAudioStateArgumentCaptor.capture());
+            } catch (RemoteException e) {
+                fail("Remote exception in InCallServiceFixture");
+            }
+            List<CallAudioState> changes = callAudioStateArgumentCaptor.getAllValues();
+            assertEquals(expectedRoute, changes.get(changes.size() - 1).getRoute());
+            success[0] = true;
+        });
         waitForHandlerAction(carsm.getHandler(), TEST_TIMEOUT);
-        ArgumentCaptor<CallAudioState> callAudioStateArgumentCaptor = ArgumentCaptor.forClass(
-                CallAudioState.class);
-        verify(mInCallServiceFixtureX.getTestDouble(), atLeastOnce()).onCallAudioStateChanged(
-                callAudioStateArgumentCaptor.capture());
-        List<CallAudioState> changes = callAudioStateArgumentCaptor.getAllValues();
-        assertEquals(expectedRoute, changes.get(changes.size() - 1).getRoute());
+        assertTrue(success[0]);
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/VideoProviderTest.java b/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
index bc7f9e1..993679e 100644
--- a/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
+++ b/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
@@ -43,6 +43,7 @@
 import android.telecom.VideoCallImpl;
 import android.telecom.VideoProfile;
 import android.telecom.VideoProfile.CameraCapabilities;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.Surface;
 
 import com.google.common.base.Predicate;
@@ -112,6 +113,7 @@
 
         mConnectionInfo = mConnectionServiceFixtureA.mConnectionById.get(mCallIds.mConnectionId);
         mVerificationLock = new CountDownLatch(1);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
     }
 
     @Override
@@ -124,6 +126,7 @@
      * and {@link VideoCall.Callback#onCameraCapabilitiesChanged(CameraCapabilities)}
      * APIS.
      */
+    @MediumTest
     public void testCameraChange() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -157,6 +160,7 @@
      * Tests the {@link VideoCall#setPreviewSurface(Surface)} and
      * {@link VideoProvider#onSetPreviewSurface(Surface)} APIs.
      */
+    @MediumTest
     public void testSetPreviewSurface() throws Exception {
         final Surface surface = new Surface(new SurfaceTexture(1));
         mVideoCall.setPreviewSurface(surface);
@@ -182,6 +186,7 @@
      * Tests the {@link VideoCall#setDisplaySurface(Surface)} and
      * {@link VideoProvider#onSetDisplaySurface(Surface)} APIs.
      */
+    @MediumTest
     public void testSetDisplaySurface() throws Exception {
         final Surface surface = new Surface(new SurfaceTexture(1));
         mVideoCall.setDisplaySurface(surface);
@@ -207,6 +212,7 @@
      * Tests the {@link VideoCall#setDeviceOrientation(int)} and
      * {@link VideoProvider#onSetDeviceOrientation(int)} APIs.
      */
+    @MediumTest
     public void testSetDeviceOrientation() throws Exception {
         mVideoCall.setDeviceOrientation(ORIENTATION_0);
 
@@ -230,6 +236,7 @@
     /**
      * Tests the {@link VideoCall#setZoom(float)} and {@link VideoProvider#onSetZoom(float)} APIs.
      */
+    @MediumTest
     public void testSetZoom() throws Exception {
         mVideoCall.setZoom(ZOOM_LEVEL);
 
@@ -251,6 +258,7 @@
      * Emulates a scenario where an InCallService sends a request to upgrade to video, which the
      * peer accepts as-is.
      */
+    @MediumTest
     public void testSessionModifyRequest() throws Exception {
         VideoProfile requestProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
 
@@ -288,6 +296,7 @@
      * Tests the {@link VideoCall#sendSessionModifyResponse(VideoProfile)},
      * and {@link VideoProvider#onSendSessionModifyResponse(VideoProfile)} APIs.
      */
+    @MediumTest
     public void testSessionModifyResponse() throws Exception {
         VideoProfile sessionModifyResponse = new VideoProfile(VideoProfile.STATE_TX_ENABLED);
 
@@ -308,6 +317,7 @@
      * {@link VideoProvider#onRequestCameraCapabilities()} ()}, and
      * {@link VideoCall.Callback#onCameraCapabilitiesChanged(CameraCapabilities)} APIs.
      */
+    @MediumTest
     public void testRequestCameraCapabilities() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -325,6 +335,7 @@
      * Tests the {@link VideoCall#setPauseImage(Uri)}, and
      * {@link VideoProvider#onSetPauseImage(Uri)} APIs.
      */
+    @MediumTest
     public void testSetPauseImage() throws Exception {
         final Uri testUri = Uri.fromParts("file", "test.jpg", null);
         mVideoCall.setPauseImage(testUri);
@@ -343,6 +354,7 @@
      * {@link VideoProvider#onRequestConnectionDataUsage()}, and
      * {@link VideoCall.Callback#onCallDataUsageChanged(long)} APIs.
      */
+    @MediumTest
     public void testRequestDataUsage() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -360,6 +372,7 @@
      * Tests the {@link VideoProvider#receiveSessionModifyRequest(VideoProfile)},
      * {@link VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)} APIs.
      */
+    @MediumTest
     public void testReceiveSessionModifyRequest() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -382,6 +395,7 @@
      * Tests the {@link VideoProvider#handleCallSessionEvent(int)}, and
      * {@link VideoCall.Callback#onCallSessionEvent(int)} APIs.
      */
+    @MediumTest
     public void testSessionEvent() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -400,6 +414,7 @@
      * Tests the {@link VideoProvider#changePeerDimensions(int, int)} and
      * {@link VideoCall.Callback#onPeerDimensionsChanged(int, int)} APIs.
      */
+    @MediumTest
     public void testPeerDimensionChange() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)
@@ -419,6 +434,7 @@
      * Tests the {@link VideoProvider#changeVideoQuality(int)} and
      * {@link VideoCall.Callback#onVideoQualityChanged(int)} APIs.
      */
+    @MediumTest
     public void testVideoQualityChange() throws Exception {
         // Wait until the callback has been received before performing verification.
         doAnswer(mVerification).when(mVideoCallCallback)