Merge "DO NOT MERGE - Restrict ability to add call based on device provision status" into lmp-mr1-dev am: b204dee494 am: bb2dbba478
am: b34b14a3f8  -s ours

* commit 'b34b14a3f8ddd8ec9076407f71594892a3dac976':
  DO NOT MERGE - Restrict ability to add call based on device provision status
diff --git a/Android.mk b/Android.mk
index c5482b4..b2fbc16 100644
--- a/Android.mk
+++ b/Android.mk
@@ -12,7 +12,7 @@
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 
-LOCAL_PROGUARD_FLAGS := $(proguard.flags)
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 include $(BUILD_PACKAGE)
 
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a2c0b91..f4ae711 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,21 +23,22 @@
     <!-- Prevents the activity manager from delaying any activity-start
          requests by this package, including requests immediately after
          the user presses "home". -->
+    <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
+    <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
+    <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" />
     <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CALL_LOG" />
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
-    <uses-permission android:name="android.permission.BIND_CONNECTION_SERVICE" />
-    <uses-permission android:name="android.permission.BIND_INCALL_SERVICE" />
-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
-    <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO" />
 
     <permission
             android:name="android.permission.BROADCAST_CALLLOG_INFO"
@@ -49,6 +50,16 @@
             android:label="Register to handle the broadcasted call type/duration information"
             android:protectionLevel="signature|system"/>
 
+    <permission
+            android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION"
+            android:label="Broadcast phone account registration"
+            android:protectionLevel="signature|system"/>
+
+    <permission
+            android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"
+            android:label="Process phone account registration"
+            android:protectionLevel="signature|system"/>
+
     <!-- Declare which SDK level this application was built against. This is needed so that IDEs
          can check for incompatible APIs. -->
     <uses-sdk android:minSdkVersion="19" />
@@ -57,7 +68,8 @@
             android:icon="@mipmap/ic_launcher_phone"
             android:allowBackup="false"
             android:supportsRtl="true"
-            android:process="system">
+            android:process="system"
+            android:usesCleartextTraffic="false">
 
         <!-- CALL vs CALL_PRIVILEGED vs CALL_EMERGENCY
              We have three different intents through which a call can be initiated each with its
@@ -75,7 +87,8 @@
              contain contact information in the intent's data. CallActivity handles any data
              URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
              contacts provider entries. Any data not fitting the schema described is ignored. -->
-        <activity android:name="CallActivity"
+        <activity android:name=".components.UserCallActivity"
+                android:label="@string/userCallActivityLabel"
                 android:theme="@style/Theme.Telecomm.Transparent"
                 android:permission="android.permission.CALL_PHONE"
                 android:excludeFromRecents="true"
@@ -114,7 +127,7 @@
              processed. High priority of 1000 is used in all intent filters to prevent anything but
              the system from processing this intent (b/8871505). -->
         <activity-alias android:name="PrivilegedCallActivity"
-                android:targetActivity="CallActivity"
+                android:targetActivity=".components.UserCallActivity"
                 android:permission="android.permission.CALL_PRIVILEGED"
                 android:process=":ui">
             <intent-filter android:priority="1000">
@@ -149,7 +162,7 @@
         <!-- TODO: Is there really a notion of an emergency SIP number? If not, can
              that scheme be removed from this activity? -->
         <activity-alias android:name="EmergencyCallActivity"
-                android:targetActivity="CallActivity"
+                android:targetActivity=".components.UserCallActivity"
                 android:permission="android.permission.CALL_PRIVILEGED"
                 android:process=":ui">
             <intent-filter android:priority="1000">
@@ -176,16 +189,16 @@
             </intent-filter>
         </activity-alias>
 
-        <receiver android:name="TelecomBroadcastReceiver" android:exported="false"
+        <receiver android:name=".components.TelecomBroadcastReceiver" android:exported="false"
                 android:process="system">
             <intent-filter>
-                <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
+                <action android:name="com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS" />
                 <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
                 <action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION" />
             </intent-filter>
         </receiver>
 
-        <receiver android:name="PhoneAccountBroadcastReceiver"
+        <receiver android:name=".components.PhoneAccountBroadcastReceiver"
                 android:process="system">
             <intent-filter>
                 <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
@@ -193,17 +206,30 @@
             </intent-filter>
         </receiver>
 
-        <activity android:name=".RespondViaSmsSettings$Settings"
+        <activity android:name=".RespondViaSmsSettings"
                   android:label="@string/respond_via_sms_setting_title"
                   android:configChanges="orientation|screenSize|keyboardHidden"
                   android:theme="@style/Theme.Telecom.DialerSettings"
                   android:process=":ui">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
 
-        <activity android:name=".ErrorDialogActivity"
+        <activity android:name=".settings.EnableAccountPreferenceActivity"
+                  android:label="@string/enable_account_preference_title"
+                  android:configChanges="orientation|screenSize|keyboardHidden"
+                  android:theme="@style/Theme.Telecom.DialerSettings"
+                  android:process=":ui">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".components.ErrorDialogActivity"
                 android:configChanges="orientation|screenSize|keyboardHidden"
                 android:excludeFromRecents="true"
                 android:launchMode="singleInstance"
@@ -211,13 +237,25 @@
                 android:process=":ui">
         </activity>
 
-        <receiver android:name=".CallReceiver"
+        <activity android:name=".components.ChangeDefaultDialerDialog"
+                  android:label="@string/change_default_dialer_dialog_title"
+                  android:excludeFromRecents="true"
+                  android:theme="@*android:style/Theme.Material.Light.Dialog.Alert"
+                  android:priority="1000"
+                  android:process=":ui" >
+            <intent-filter>
+                <action android:name="android.telecom.action.CHANGE_DEFAULT_DIALER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <receiver android:name=".components.PrimaryCallReceiver"
                 android:exported="true"
                 android:permission="android.permission.MODIFY_PHONE_STATE"
                 android:process="system">
         </receiver>
 
-        <service android:name="BluetoothPhoneService"
+        <service android:name=".components.BluetoothPhoneService"
                 android:singleUser="true"
                 android:process="system">
             <intent-filter>
@@ -225,11 +263,11 @@
             </intent-filter>
         </service>
 
-        <service android:name=".TelecomService"
+        <service android:name=".components.TelecomService"
                 android:singleUser="true"
                 android:process="system">
             <intent-filter>
-                <android android:name="android.telecom.ITelecomService" />
+                <action android:name="android.telecom.ITelecomService" />
             </intent-filter>
         </service>
 
diff --git a/proguard.flags b/proguard.flags
index e52ac20..357336b 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,4 +1,8 @@
 -verbose
-
-# Keep @VisibleForTesting elements
 -keep @com.android.internal.annotations.VisibleForTesting class *
+-keep class com.android.server.telecom.TelecomSystem {
+  *;
+}
+-keep class com.android.server.telecom.Log {
+  *;
+}
diff --git a/res/drawable-hdpi/ic_arrow_back_white_24dp.png b/res/drawable-hdpi/ic_arrow_back_24dp.png
similarity index 100%
rename from res/drawable-hdpi/ic_arrow_back_white_24dp.png
rename to res/drawable-hdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_message_24dp.png b/res/drawable-hdpi/ic_message_24dp.png
new file mode 100644
index 0000000..57177b7
--- /dev/null
+++ b/res/drawable-hdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_more_vert_white_24dp.png b/res/drawable-hdpi/ic_more_vert_24dp.png
similarity index 100%
rename from res/drawable-hdpi/ic_more_vert_white_24dp.png
rename to res/drawable-hdpi/ic_more_vert_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_phone_24dp.png b/res/drawable-hdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..4dc5065
--- /dev/null
+++ b/res/drawable-hdpi/ic_phone_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_text_holo_dark.png b/res/drawable-hdpi/ic_text_holo_dark.png
deleted file mode 100644
index 6d21e42..0000000
--- a/res/drawable-hdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/stat_sys_phone_call.png b/res/drawable-hdpi/stat_sys_phone_call.png
deleted file mode 100644
index 7eda84c..0000000
--- a/res/drawable-hdpi/stat_sys_phone_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/ic_text_holo_dark.png b/res/drawable-ldrtl-hdpi/ic_text_holo_dark.png
deleted file mode 100644
index b99073e..0000000
--- a/res/drawable-ldrtl-hdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/stat_sys_phone_call.png b/res/drawable-ldrtl-hdpi/stat_sys_phone_call.png
deleted file mode 100644
index e0f33f8..0000000
--- a/res/drawable-ldrtl-hdpi/stat_sys_phone_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/ic_text_holo_dark.png b/res/drawable-ldrtl-mdpi/ic_text_holo_dark.png
deleted file mode 100644
index 4106c32..0000000
--- a/res/drawable-ldrtl-mdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/stat_sys_phone_call.png b/res/drawable-ldrtl-mdpi/stat_sys_phone_call.png
deleted file mode 100644
index d771d87..0000000
--- a/res/drawable-ldrtl-mdpi/stat_sys_phone_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/ic_text_holo_dark.png b/res/drawable-ldrtl-xhdpi/ic_text_holo_dark.png
deleted file mode 100644
index 99e7e38..0000000
--- a/res/drawable-ldrtl-xhdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/stat_sys_phone_call.png b/res/drawable-ldrtl-xhdpi/stat_sys_phone_call.png
deleted file mode 100644
index 86af9c2..0000000
--- a/res/drawable-ldrtl-xhdpi/stat_sys_phone_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_white_24dp.png b/res/drawable-mdpi/ic_arrow_back_24dp.png
similarity index 100%
rename from res/drawable-mdpi/ic_arrow_back_white_24dp.png
rename to res/drawable-mdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_message_24dp.png b/res/drawable-mdpi/ic_message_24dp.png
new file mode 100644
index 0000000..3072b75
--- /dev/null
+++ b/res/drawable-mdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_more_vert_white_24dp.png b/res/drawable-mdpi/ic_more_vert_24dp.png
similarity index 100%
rename from res/drawable-mdpi/ic_more_vert_white_24dp.png
rename to res/drawable-mdpi/ic_more_vert_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_phone_24dp.png b/res/drawable-mdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..77f9de5
--- /dev/null
+++ b/res/drawable-mdpi/ic_phone_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_text_holo_dark.png b/res/drawable-mdpi/ic_text_holo_dark.png
deleted file mode 100644
index 80b95ee..0000000
--- a/res/drawable-mdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/stat_sys_phone_call.png b/res/drawable-mdpi/stat_sys_phone_call.png
deleted file mode 100644
index 70a4bbe..0000000
--- a/res/drawable-mdpi/stat_sys_phone_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_back_white_24dp.png b/res/drawable-xhdpi/ic_arrow_back_24dp.png
similarity index 100%
rename from res/drawable-xhdpi/ic_arrow_back_white_24dp.png
rename to res/drawable-xhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_message_24dp.png b/res/drawable-xhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..763767b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_more_vert_white_24dp.png b/res/drawable-xhdpi/ic_more_vert_24dp.png
similarity index 100%
rename from res/drawable-xhdpi/ic_more_vert_white_24dp.png
rename to res/drawable-xhdpi/ic_more_vert_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_phone_24dp.png b/res/drawable-xhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..ef45e93
--- /dev/null
+++ b/res/drawable-xhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_text_holo_dark.png b/res/drawable-xhdpi/ic_text_holo_dark.png
deleted file mode 100644
index e80a042..0000000
--- a/res/drawable-xhdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
similarity index 100%
rename from res/drawable-xxhdpi/ic_arrow_back_white_24dp.png
rename to res/drawable-xxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_message_24dp.png b/res/drawable-xxhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..0a79824
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_more_vert_white_24dp.png b/res/drawable-xxhdpi/ic_more_vert_24dp.png
similarity index 100%
rename from res/drawable-xxhdpi/ic_more_vert_white_24dp.png
rename to res/drawable-xxhdpi/ic_more_vert_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_phone_24dp.png b/res/drawable-xxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..90ead2e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png b/res/drawable-xxxhdpi/ic_arrow_back_24dp.png
similarity index 100%
rename from res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png
rename to res/drawable-xxxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_message_24dp.png b/res/drawable-xxxhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..fa7c17a
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png b/res/drawable-xxxhdpi/ic_more_vert_24dp.png
similarity index 100%
rename from res/drawable-xxxhdpi/ic_more_vert_white_24dp.png
rename to res/drawable-xxxhdpi/ic_more_vert_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_phone_24dp.png b/res/drawable-xxxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..b0e0205
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/res/drawable/ic_back_arrow.xml b/res/drawable/ic_back_arrow.xml
index cbb4c11..07b3cb0 100644
--- a/res/drawable/ic_back_arrow.xml
+++ b/res/drawable/ic_back_arrow.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License
   -->
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/ic_arrow_back_white_24dp"
+        android:src="@drawable/ic_arrow_back_24dp"
         android:autoMirrored="true" />
diff --git a/res/drawable/ic_message.xml b/res/drawable/ic_message.xml
new file mode 100644
index 0000000..ae32073
--- /dev/null
+++ b/res/drawable/ic_message.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_message_24dp"
+        android:autoMirrored="true" />
diff --git a/res/drawable/ic_phone.xml b/res/drawable/ic_phone.xml
new file mode 100644
index 0000000..15c2a48
--- /dev/null
+++ b/res/drawable/ic_phone.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_phone_24dp"
+        android:autoMirrored="true" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
new file mode 100644
index 0000000..2cf0fd8
--- /dev/null
+++ b/res/values-af/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Foonoproepbestuur"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Foon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Onbekend"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Gemiste oproep"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Gemiste oproepe"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> gemiste oproepe"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Gemiste oproep van <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Bel terug"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Boodskap"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Oproep stilgemaak."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Luidsprekerfoon geaktiveer."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kan nie nou praat nie. Wat\'s nuus?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ek bel jou nou-nou terug."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ek bel jou later."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kan nie nou praat nie. Bel my later?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Vinnige antwoorde"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Redigeer vinnige antwoorde"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Vinnige antwoord"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Boodskap gestuur na <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Oproeprekeninge"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Net noodoproepe word deur die toesteleienaar toegelaat."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Hierdie program kan nie uitgaande oproepe maak sonder die foon se toestemming nie."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Voer \'n geldige nommer in om \'n oproep te maak."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Oproep kan nie op die oomblik bygevoeg word nie."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Deaktiveer TTY-modus om video-oproepe te maak."</string>
+    <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>
+</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
new file mode 100644
index 0000000..14d383c
--- /dev/null
+++ b/res/values-am/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"የስልክ ጥሪ አስተዳደር"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ስልክ"</string>
+    <string name="unknown" msgid="6878797917991465859">"ያልታወቀ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ያመለጠጥሪ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ያመለጡ ጥሪዎች"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ያመለጡ ጥሪዎች"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"ከ<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> ያመለጠ ጥሪ"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"መልሰህ ደውል"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"መልዕክት"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ጥሪ ፀጥ  ብሏል"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"የስልክ ድምፅ ማጉያ ነቅቷል።"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"አሁን ማውራት አልችልም። ሰላም ነው?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ወዲያው መልሼ እደውላለሁ።"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ኋላ እደውላለሁ።"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"አሁን ማውራት አልችልም። ትንሽ ቆይተው ይደውሉ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ፈጣን ምላሾች"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ፈጣን ምላሾች አርትዕ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ፈጣን ምላሽ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"ለ <xliff:g id="PHONE_NUMBER">%s</xliff:g> የተላከ መልዕክት"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"የመደወያ መለያዎች"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"የአስቸኳይ አደጋ ጥሪዎች ብቻ ናቸው በባለቤቱ የተፈቀዱት።"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ይህ መተግበሪያ ያለስልኩ ፈቃድ ወጪ ጥሪዎችን ማድረግ አይችልም።"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"አንድ ጥሪ ለማድረግ የሚሰራ ቁጥር ያስገቡ።"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ጥሪ በዚህ ጊዜ ላይ ሊታከል አይችልም።"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"የቪዲዮ ጥሪዎችን ለማድረግ እባክዎ የTTY ሁነታን ያሰናክሉ።"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"የድምፅመልዕክት ቁጥርአመለጠ"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"በSIM ካርዱ ላይምንም የድምፅመልዕክት ቁጥር አልከተቀመጠም።"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"ቁጥር አክል"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"ነባሪ መደወያ መተግበሪያ ይለወጥ?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g>ን በ<xliff:g id="CURRENT_APP">%2$s</xliff:g> ምትክ እንደ የእርስዎ ነባሪ መደወያ መተግበሪያ ይጠቀም?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g>ን እንደ የእርስዎ ነባሪ መደወያ መተግበሪያ ይጠቀም?"</string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
new file mode 100644
index 0000000..cade2ea
--- /dev/null
+++ b/res/values-ar/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"إدارة المكالمات الهاتفية"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"الهاتف"</string>
+    <string name="unknown" msgid="6878797917991465859">"غير معروف"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"مكالمة فائتة"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"المكالمات الفائتة"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> من المكالمات الفائتة"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"مكالمة فائتة من <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"معاودة الاتصال"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"رسالة"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"تم كتم صوت المكالمة."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"تم تمكين مكبر صوت الهاتف."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"لا يمكنني التحدث الآن. ماذا هناك؟"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"سأعاود الاتصال بك."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"سأتصل بك لاحقًا."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"لا يمكنني التحدث الآن. اتصل بي لاحقًا."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"الردود السريعة"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"تعديل الردود السريعة"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"رد سريع"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"تم إرسال الرسالة إلى <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"حسابات الاتصال"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"لم يسمح مالك الجهاز إلا بإجراء مكالمات الطوارئ فقط."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"يتعذر على هذا التطبيق إجراء مكالمات صادرة بدون إذن من الهاتف."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"لإجراء مكالمة، أدخل رقمًا صالحًا."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"لا يمكن إضافة مكالمة في الوقت الحالي."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"‏يُرجى تعطيل وضع TTY لإجراء مكالمات فيديو."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"رقم البريد الصوتي مفقود"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"‏لم يتم تخزين رقم بريد صوتي على شريحة SIM."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"إضافة رقم"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"هل تريد تغيير التطبيق الافتراضي لبرنامج الاتصال؟"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"هل تريد استخدام <xliff:g id="NEW_APP">%1$s</xliff:g> بدلاً من <xliff:g id="CURRENT_APP">%2$s</xliff:g> تطبيقًا افتراضيًا لبرنامج الاتصال؟"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"هل تريد استخدام <xliff:g id="NEW_APP">%s</xliff:g> تطبيقًا افتراضيًا لبرنامج الاتصال؟"</string>
+</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..ee5a86e
--- /dev/null
+++ b/res/values-az-rAZ/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefon Zənglərin İdarə Olunması"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Naməlum"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Buraxılmış zəng"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Buraxılmış zənglər"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> buraxılmış zənglər"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> tərəfindən zəng buraxılıb"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Geriyə zəng"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mesaj"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Səssiz zəng edin."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Spikerfon aktivdir."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"İndi danışmaq olmur. Nə olub?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Özüm zəng edəcəm."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Özüm sonra zəng edəcəm."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"İndi danışa bilmirəm. Sonra zəng edin."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Tez cavablar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Tez cavablara düzəliş edin"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Tez cavab"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesaj <xliff:g id="PHONE_NUMBER">%s</xliff:g> nömrəsinə göndərildi."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Hesabların çağırılması"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Cihazın sahibi yalnız fövqəladə zənglərə icazə verir."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Bu proqram Telefon icazəsi olmadan zəng edə bilməz."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Zəngi yerləşdirmək üçün düzgün nömrə daxil edin."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hazırda çağrı edilə bilməz."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Video zəng etmək üçün TTY Rejimini deaktiv edin."</string>
+    <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>
+</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
new file mode 100644
index 0000000..8d852b4
--- /dev/null
+++ b/res/values-bg/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Управление на телефонните обаждания"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Неизвестен номер"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропуснато обаждане"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропуснати обаждания"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> пропуснати обаждания"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Пропуснато обаждане от <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Обратно обаждане"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Съобщение"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Обаждането бе спряно."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Високоговорителят бе активиран."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Сега не мога да говоря. Какво има?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ще ви се обадя веднага обратно."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ще ви се обадя по-късно."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Сега не мога да говоря. По-късно?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Бързи отговори"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Редакт. на бързи отговори"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Бърз отговор"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"До <xliff:g id="PHONE_NUMBER">%s</xliff:g> бе изпратено съобщение."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Профили за обаждане"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Собственикът на устройството разрешава само спешни обаждания."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Това приложение не може да извършва изходящи обаждания без разрешението за телефон."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"За да извършите обаждане, въведете валиден номер."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Понастоящем обаждането не може да бъде добавено."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Моля, деактивирайте режима на TTY, за да извършвате видеообаждания."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Липсващ номер на гласова поща"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM картата няма съхранен номер за гласова поща."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Добавяне на номер"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Да се промени ли основното приложение за дайлер?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g> да се използва ли вместо <xliff:g id="CURRENT_APP">%2$s</xliff:g> като основното ви приложение за дайлер?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Да се използва ли <xliff:g id="NEW_APP">%s</xliff:g> като основното ви приложение за дайлер?"</string>
+</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
new file mode 100644
index 0000000..c09003c
--- /dev/null
+++ b/res/values-bn-rBD/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ফোন কল ব্যবস্থাপনা"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ফোন"</string>
+    <string name="unknown" msgid="6878797917991465859">"অজানা"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"মিসড কল"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"মিসড কলগুলি"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>টি মিসড কল"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> এর থেকে মিসড কল"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"কল ব্যাক করুন"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"বার্তা"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"কল নিঃশব্দ করা আছে৷"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"স্পীকারফোন সক্ষম করা আছে৷"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"এখন কথা বলতে পারছি না৷ কি খবর?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"আমি আপনাকে কিছুক্ষণ পরেই কল করছি৷"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"আমি পরে আপনাকে কল করে নেব৷"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"এখন কথা বলতে পারছি না৷ আমাকে একটু পরে কল করবেন?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"দ্রুত প্রতিক্রিয়াগুলি"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"দ্রুত প্রতিক্রিয়াগুলির সম্পাদনা করুন"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"দ্রুত প্রতিক্রিয়া"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> এ বার্তা পাঠানো হয়েছে৷"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"কলিং অ্যাকাউন্টগুলি"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ডিভাইসের মালিক শুধুমাত্র জরুরি কলগুলিতে অনুমতি দিয়েছেন৷"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"এই অ্যাপ্লিকেশানটি ফোনের অনুমতি ছাড়া আউটগোয়িং কলগুলি করতে পারবে না।"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"কোনো কল স্থাপন করতে, একটি বৈধ নম্বর লিখুন৷"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"এই মুহূর্তে কল যোগ করা যাবে না৷"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"অনুগ্রহ করে ভিডিও কলগুলি করতে TTY মোড অক্ষম করুন৷"</string>
+    <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>
+</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
new file mode 100644
index 0000000..2fe7797
--- /dev/null
+++ b/res/values-ca/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gestió de trucades telefòniques"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telèfon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Desconegut"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Trucada perduda"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Trucades perdudes"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> trucades perdudes"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Trucada perduda de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Torna la trucada"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Missatge"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Trucada silenciada."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altaveu activat."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ara no puc parlar. Què passa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Et truco de seguida."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Et truco més tard."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ara no puc parlar. Truques després?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respostes ràpides"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edita les respostes ràpides"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Resposta ràpida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Missatge enviat a <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Comptes de trucades"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"El propietari del dispositiu només permet les trucades d\'emergència."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Aquesta aplicació no pot fer trucades sortints sense el permís del telèfon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Per realitzar una trucada, introdueix un número vàlid."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"En aquest moment no es pot afegir la trucada."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Desactiva el mode de TTY per fer videotrucades."</string>
+    <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>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
new file mode 100644
index 0000000..18f7c86
--- /dev/null
+++ b/res/values-cs/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Správa telefonních hovorů"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Neznámý volající"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Zmeškaný hovor"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Zmeškané hovory"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Zmeškané hovory: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>."</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Zmeškaný hovor od volajícího <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>."</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Zavolat zpět"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Zpráva"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Hovor ztlumen."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Reproduktor je zapnutý."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Teď nemůžu telefonovat, o co jde?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Zavolám zpátky."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Zavolám později."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nemůžu telefonovat, volejte jindy."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Rychlé odpovědi"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Upravit rychlé odpovědi"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Rychlá odpověď"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Zpráva byla odeslána na číslo <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Účty pro volání"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Vlastník zařízení povolil pouze tísňová volání."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Tato aplikace nemůže provádět odchozí hovory bez oprávnění k použití telefonu."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Chcete-li uskutečnit hovor, zadejte platné telefonní číslo."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hovor aktuálně nelze přidat."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Chcete-li vést videohovory, vypněte režim TTY."</string>
+    <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>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
new file mode 100644
index 0000000..0124059
--- /dev/null
+++ b/res/values-da/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Opkaldsstyring"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Ukendt"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Ubesvarede opkald"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Ubesvarede opkald"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ubesvarede opkald"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Ubesvarede opkald fra <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Ring tilbage"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Besked"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Lyd slået fra opkald."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Højttalertelefon aktiveret."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kan ikke tale nu. Hvad sker der?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Jeg ringer tilbage lige om lidt."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Jeg ringer til dig senere."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kan ikke tale nu. Ringer du senere?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Hurtige svar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Rediger hurtige svar"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Hurtigt svar"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Meddelelsen er sendt til <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Opkaldskonti"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Enhedens ejer tillader kun nødopkald."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Denne app kan ikke foretage udgående opkald uden opkaldstilladelse."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Indtast et gyldigt nummer for at foretage et opkald."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Opkaldet kan ikke tilføjes på nuværende tidspunkt."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Deaktiver TTY-tilstanden for at foretage videoopkald."</string>
+    <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>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
new file mode 100644
index 0000000..e940f4b
--- /dev/null
+++ b/res/values-de/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Anrufverwaltung"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Unbekannt"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Entgangener Anruf"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Entgangene Anrufe"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> entgangene Anrufe"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Entgangener Anruf von <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Zurückrufen"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Nachricht"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Anruf stummgeschaltet"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Freisprechfunktion aktiviert"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kann jetzt nicht sprechen. Was gibt\'s?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ich rufe gleich zurück."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ich rufe später zurück."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kann jetzt nicht sprechen. Später?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Kurzantworten"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Kurzantworten bearbeiten"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Kurzantwort"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Nachricht an <xliff:g id="PHONE_NUMBER">%s</xliff:g> gesendet"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Anrufkonten"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Der Geräteeigentümer hat nur Notrufe zugelassen."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Diese App darf ohne die Berechtigung \"Standard-App für Telefonie\" keine ausgehenden Anrufe tätigen."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Geben Sie eine gültige Nummer ein."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Der Anruf kann momentan nicht hinzugefügt werden."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Bitte deaktivieren Sie den TTY-Modus, um Videoanrufe tätigen zu können."</string>
+    <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>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
new file mode 100644
index 0000000..a36fd5a
--- /dev/null
+++ b/res/values-el/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Διαχείριση τηλεφωνικών κλήσεων"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Τηλέφωνο"</string>
+    <string name="unknown" msgid="6878797917991465859">"Άγνωστος"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Αναπάντητη κλήση"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Αναπάντητες κλήσεις"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> αναπάντητες κλήσεις"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Αναπάντητη κλήση από <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Επανάκληση"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Μήνυμα"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Η κλήση τέθηκε σε σίγαση."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Η ανοικτή συνομιλία ενεργοποιήθηκε."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Δεν μπορώ τώρα. Συμβαίνει κάτι;"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Θα σου τηλεφωνήσω αμέσως."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Θα σου τηλεφωνήσω αργότερα."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Δεν μπορώ τώρα. Πάρε με αργότερα."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Γρήγορες απαντήσεις"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Επεξεργασία"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Γρήγορη απάντηση"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Το μήνυμα εστάλη στο <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Λογαριασμοί κλήσης"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Από τον κάτοχο της συσκευής επιτρέπονται μόνο κλήσεις έκτακτης ανάγκης."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Αυτή η εφαρμογή δεν μπορεί να πραγματοποιήσει εξερχόμενες κλήσεις χωρίς την άδεια \"Τηλέφωνο\"."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Για να πραγματοποιήσετε μια κλήση, εισαγάγετε έναν έγκυρο αριθμό."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Δεν είναι δυνατή η προσθήκη κλήσης αυτήν τη στιγμή."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Απενεργοποιήστε τη λειτουργία TTY για να πραγματοποιήσετε βιντεοκλήσεις."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Λείπει ο αριθμός αυτόματου τηλεφωνητή"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"Δεν έχει αποθηκευτεί αριθμός για τον αυτόματο τηλεφωνητή στην κάρτα SIM."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Προσθήκη αριθμού"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Αλλαγή της προεπιλεγμένης εφαρμογής 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>
+</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..16eeaf2
--- /dev/null
+++ b/res/values-en-rAU/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Phone Call Management"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telephone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Unknown"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Missed call from <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Call back"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Call muted."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Speakerphone enabled."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Can\'t talk now. What\'s up?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"I\'ll call you right back."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"I\'ll call you later."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Can\'t talk now. Call me later?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Quick responses"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit quick responses"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Quick response"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message sent to <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Calling accounts"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Only emergency calls are allowed by the device owner."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"This application cannot make outgoing calls without Phone permission."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"To place a call, enter a valid number."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Call cannot be added at this time."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Please disable TTY Mode to make video calls."</string>
+    <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>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..16eeaf2
--- /dev/null
+++ b/res/values-en-rGB/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Phone Call Management"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telephone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Unknown"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Missed call from <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Call back"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Call muted."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Speakerphone enabled."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Can\'t talk now. What\'s up?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"I\'ll call you right back."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"I\'ll call you later."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Can\'t talk now. Call me later?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Quick responses"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit quick responses"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Quick response"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message sent to <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Calling accounts"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Only emergency calls are allowed by the device owner."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"This application cannot make outgoing calls without Phone permission."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"To place a call, enter a valid number."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Call cannot be added at this time."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Please disable TTY Mode to make video calls."</string>
+    <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>
+</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..16eeaf2
--- /dev/null
+++ b/res/values-en-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Phone Call Management"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telephone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Unknown"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Missed call from <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Call back"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Call muted."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Speakerphone enabled."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Can\'t talk now. What\'s up?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"I\'ll call you right back."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"I\'ll call you later."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Can\'t talk now. Call me later?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Quick responses"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit quick responses"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Quick response"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message sent to <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Calling accounts"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Only emergency calls are allowed by the device owner."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"This application cannot make outgoing calls without Phone permission."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"To place a call, enter a valid number."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Call cannot be added at this time."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Please disable TTY Mode to make video calls."</string>
+    <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>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..4474b52
--- /dev/null
+++ b/res/values-es-rUS/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Administración de llamadas telefónicas"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Teléfono"</string>
+    <string name="unknown" msgid="6878797917991465859">"Desconocida"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Llamada perdida"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Llamadas perdidas"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> llamadas perdidas"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Se perdieron las llamadas de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Llamar"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mensaje"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Llamada silenciada"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altavoz habilitado"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"No puedo hablar ahora. ¿Todo bien?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Te llamo enseguida."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Te llamo más tarde."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"No puedo hablar ahora. ¿Me llamas más tarde?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respuestas rápidas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editar respuestas rápidas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Respuesta rápida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mensaje enviado a <xliff:g id="PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Cuentas telefónicas"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"El propietario del dispositivo solo permite que se realicen llamadas de emergencia."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Esta aplicación no puede realizar llamadas salientes sin permiso del teléfono."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Para realizar una llamada, ingresa un número válido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"No se puede agregar la llamada en este momento."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Inhabilita el modo TTY para realizar una videollamada."</string>
+    <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>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
new file mode 100644
index 0000000..acb3e43
--- /dev/null
+++ b/res/values-es/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gestión de llamadas del teléfono"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Teléfono"</string>
+    <string name="unknown" msgid="6878797917991465859">"Desconocido"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Llamada perdida"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Llamadas perdidas"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> llamadas perdidas"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Llamada perdida de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Llamar"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mensaje"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Llamada silenciada"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altavoz habilitado"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"No puedo hablar. ¿Es importante?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Te llamo en cuanto pueda."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Te llamo más tarde."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"No puedo hablar. Llámame luego."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respuestas rápidas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editar respuestas rápidas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Respuestas rápidas"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mensaje enviado a <xliff:g id="PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Cuentas de llamadas"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"El propietario del dispositivo solo permite llamadas de emergencia."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Esta aplicación no puede hacer llamadas sin permiso del teléfono."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Para realizar una llamada, introduce un número válido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"No se puede añadir la llamada en este momento."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Inhabilita el modo TTY para hacer videollamadas."</string>
+    <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>
+</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..77340ad
--- /dev/null
+++ b/res/values-et-rEE/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefonikõnede haldus"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Tundmatu"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Vastamata kõne"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Vastamata kõned"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> vastamata kõnet"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Vastamata kõne helistajalt <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Helista tagasi"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Sõnum"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Kõne on summutatud."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Valjuhääldi on sisse lülitatud."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ei saa praegu rääkida. Milles asi?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Helistan kohe tagasi."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Helistan sulle hiljem."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ei saa rääkida. Helistad hiljem?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Kiirvastused"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Kiirvastuste muutmine"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Kiirvastus"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Sõnum on saadetud numbrile <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Kõnekontod"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Seadme omanik on lubanud ainult hädaabikõned."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"See rakendus ei saa ilma telefoni kasutamise loata välja helistada."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Helistamiseks sisestage kehtiv number."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Kõnet ei saa praegu lisada."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Videokõnede tegemiseks keelake TTY-režiim."</string>
+    <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>
+</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
new file mode 100644
index 0000000..8f74aa8
--- /dev/null
+++ b/res/values-eu-rES/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefono-deien kudeaketa"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefonoa"</string>
+    <string name="unknown" msgid="6878797917991465859">"Ezezaguna"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Dei galdua"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Dei galduak"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> dei galdu"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Deitzaile honen dei galdua: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Erantzun deiari"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mezua"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Deiaren audioa desaktibatu da."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Bozgorailua gaitu da."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ezin dut hitz egin. Arazoren bat al dago?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Oraintxe deituko dizut bueltan."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Geroago deituko dizut."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ezin dut hitz egin. Deitu geroago."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Erantzun bizkorrak"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editatu erantzun bizkorrak"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Erantzun bizkorra"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mezua bidali da <xliff:g id="PHONE_NUMBER">%s</xliff:g> zenbakira."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Deiak egiteko kontuak"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Gailuaren jabeak larrialdi-deiak bakarrik egin ditzake."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Aplikazioak irteerako deiak egin ahal izan ditzan, telefonoaren eginbidea erabiltzeko baimena behar du."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Deitzeko, idatzi balio duen zenbaki bat."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Une honetan ezin da deirik gehitu."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Desgaitu TTY modua bideo-deiak egiteko."</string>
+    <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>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
new file mode 100644
index 0000000..be81219
--- /dev/null
+++ b/res/values-fa/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"مدیریت تماس تلفنی"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"تلفن"</string>
+    <string name="unknown" msgid="6878797917991465859">"ناشناس"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"تماس بی پاسخ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"تماس‌های بی پاسخ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> تماس بی پاسخ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"تماس بی پاسخ از <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"پاسخ تماس"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"پیام"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"تماس نادیده گرفته شد."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"تلفن آیفون‌دار فعال شد."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"اکنون نمی‌توانم صحبت کنم. موضوع چیست؟"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"به زودی با شما تماس می‌گیرم."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"بعداً با شما تماس می‌گیرم."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"اکنون نمی‌توانم صحبت کنم. بعداً به من زنگ می‌زنید؟"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"پاسخ‌های سریع"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ویرایش پاسخ‌های سریع"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"پاسخ سریع"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"پیام به <xliff:g id="PHONE_NUMBER">%s</xliff:g> ارسال شد."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"حساب‌های تماس"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"مالک دستگاه فقط تماس‌های اضطراری را مجاز کرده است."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"این برنامه نمی‌تواند بدون اجازه تلفن، تماس‌های خروجی برقرار کند."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"برای برقراری تماس، یک شماره معتبر وارد کنید."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"در این زمان نمی‌توان تماسی اضافه کرد."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"‏لطفاً حالت TTY را برای برقراری تماس‌های ویدیویی غیرفعال کنید."</string>
+    <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>
+</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
new file mode 100644
index 0000000..371c83d
--- /dev/null
+++ b/res/values-fi/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Puhelujen hallinta"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Puhelin"</string>
+    <string name="unknown" msgid="6878797917991465859">"Tuntematon"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Vastaamatta jäänyt puhelu"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Vastaamattomat puhelut"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> vastaamatonta puhelua"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Vastaamatta jäänyt puhelu numerosta <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Soita"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Viesti"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Puhelu mykistetty."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Kaiutin käytössä."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"En voi vastata - mitä asiaa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Soitan sinulle pian."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Soitan sinulle myöhemmin."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"En voi vastata. Soitatko myöhemmin?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Pikavastaukset"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Muokkaa pikavastausta"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Pikavastaukset"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Viesti lähetetty numeroon <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Puhelutilit"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Laitteen omistaja on sallinut vain hätäpuhelut."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Tämä sovellus ei voi soittaa puheluita ilman Puhelin-lupaa."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Soita antamalla kelvollinen numero."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Puhelua ei voi lisätä juuri nyt."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Poista TTY-tila käytöstä, jos haluat soittaa videopuheluita."</string>
+    <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>
+</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..9b9655f
--- /dev/null
+++ b/res/values-fr-rCA/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gestion des appels téléphoniques"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Téléphone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Inconnu"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Appel manqué"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Appels manqués"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> appels manqués"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Appel manqué de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Rappeler"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Son coupé"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Haut-parleur activé"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Peux pas parler. Quoi de neuf?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Je te rappelle tout de suite."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Je t\'appellerai plus tard."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Peux pas parler. On se rappelle?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Réponses rapides"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Modif. rép. rapides"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Réponse rapide"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message envoyé à <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Comptes d\'appel"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Seuls les appels d\'urgence sont autorisés par le propriétaire de l\'appareil."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Cette application ne peut pas faire d\'appels sans l\'autorisation de l\'application Téléphone."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Pour faire un appel, entrez un numéro valide."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Impossible d\'ajouter l\'appel pour le moment."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Veuillez désactiver le mode ATS pour faire un appel vidéo."</string>
+    <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>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
new file mode 100644
index 0000000..b72c4d0
--- /dev/null
+++ b/res/values-fr/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gestion des appels téléphoniques"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Téléphone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Inconnu"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Appel manqué"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Appels manqués"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> appels manqués"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Appel manqué de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Rappeler"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Message"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Son coupé"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Haut-parleur activé"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Peux pas parler. Quoi de neuf ?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Je te rappelle tout de suite."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Je t\'appellerai plus tard."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Peux pas parler. On se rappelle ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Réponses rapides"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Modifier réponses rapides"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Réponse rapide"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Message envoyé à <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Comptes téléphoniques"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Le propriétaire de l\'appareil n\'autorise que les appels d\'urgence."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Cette application ne peut pas passer d\'appels sortants sans l\'autorisation de l\'application Téléphone."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Pour émettre un appel, veuillez saisir un numéro valide."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Impossible d\'ajouter un appel pour le moment."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Veuillez désactiver le mode TTY pour passer des appels vidéo."</string>
+    <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>
+</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
new file mode 100644
index 0000000..0ecb413
--- /dev/null
+++ b/res/values-gl-rES/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Xestión de chamadas do teléfono"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Teléfono"</string>
+    <string name="unknown" msgid="6878797917991465859">"Descoñecido"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chamada perdida"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chamadas perdidas"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chamadas perdidas"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Chamada perdida de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Devolver chamada"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mensaxe"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Chamada silenciada"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altofalante activado"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Non podo falar agora. Que pasa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Chámote agora."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Chámote máis tarde."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Non podo falar. Chámasme despois?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respostas rápidas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editar respostas rápidas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Resposta rápida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mensaxe enviada ao <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Contas de chamadas"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"O propietario do dispositivo só permite as chamadas de emerxencia."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Esta aplicación non pode facer chamadas saíntes sen permiso do teléfono."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Para realizar unha chamada, introduce un número válido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Neste momento non se pode engadir a chamada."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Desactiva o modo TTY para realizar videochamadas."</string>
+    <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>
+</resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000..b8ee2e2
--- /dev/null
+++ b/res/values-gu-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ફોન કૉલ સંચાલન"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ફોન"</string>
+    <string name="unknown" msgid="6878797917991465859">"અજાણ્યું"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"છૂટેલો કૉલ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"છૂટેલા કૉલ્સ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> છૂટેલા કૉલ્સ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> નો કૉલ ચૂકી ગયાં"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"કૉલ બેક"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"સંદેશ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"કૉલ મ્યૂટ કરેલ છે."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"સ્પીકરફોન પસંદ કરેલ છે."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"હમણાં વાત કરી શકાતી નથી. શું ચાલે છે?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"હું તરત જ પાછો કૉલ કરીશ."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"હું પછીથી કૉલ કરીશ."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"હમણાં વાત કરી શકાતી નથી. મને પછીથી કૉલ કરી શકશો?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ઝડપી પ્રતિસાદ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ઝડપી પ્રતિસાદ સંપાદિત કરો"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ઝડપી પ્રતિસાદ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> પર સંદેશ મોકલ્યો."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"કૉલિંગ એકાઉન્ટ્સ"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ઉપકરણના માલિક દ્વારા ફક્ત કટોકટીના કૉલ્સને મંજૂરી અપાયેલ છે."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ફોન પરવાનગી વિના આ એપ્લિકેશન આઉટગોઇંગ કૉલ્સ કરી શકતી નથી."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"કૉલ કરવા માટે, માન્ય નંબર દાખલ કરો."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"આ સમયે કૉલ ઉમેરી શકાતો નથી."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"કૃપા કરીને વિડિઓ કૉલ્સ કરવા માટે TTY મોડ અક્ષમ કરો."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"વૉઇસમેઇલ નંબર ખૂટે છે"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM કાર્ડ પર કોઈ વૉઇસમેઇલ નંબર સંગ્રહિત નથી."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"નંબર ઉમેરો"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"ડિફોલ્ટ ડાયલર એપ્લિકેશન બદલીએ?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"તમારી ડિફોલ્ટ ડાયલર એપ્લિકેશન તરીકે <xliff:g id="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>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
new file mode 100644
index 0000000..a4c9ba4
--- /dev/null
+++ b/res/values-hi/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"फ़ोन कॉल प्रबंधन"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"फ़ोन"</string>
+    <string name="unknown" msgid="6878797917991465859">"अज्ञात"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"छूटी कॉल"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"छूटी कॉल"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> छूटी कॉल"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> की कॉल छूटी"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"वापस कॉल करें"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"संदेश"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"कॉल म्‍यूट की गई."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"स्‍पीकरफ़ोन सक्षम."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"अभी बात नहीं हो सकती. क्‍या चल रहा है?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"मैं आपको वापस कॉल करूंगा/करूंगी."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"मैं आपको बाद में कॉल करूंगा/करूंगी."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"अभी बात नहीं हो सकती. बाद में कॉल करें?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"झटपट उत्तर"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"झटपट उत्तर संपादित करें"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"झटपट उत्तर"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> को संदेश भेजा गया."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"कॉलिंग खाते"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"डिवाइस स्‍वामी द्वारा केवल आपातकालीन कॉल करने की अनुमति है."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"यह ऐप्‍लिकेशन फ़ोन अनुमति के बिना आउटगोइंग कॉल नहीं कर सकता."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"कॉल करने के लिए, मान्‍य नंबर डालें."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"इस समय कॉल नहीं जोड़ा जा सकता."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"कृपया वीडियो कॉल करने के लिए TTY मोड अक्षम करें."</string>
+    <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>
+</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
new file mode 100644
index 0000000..77ec01f
--- /dev/null
+++ b/res/values-hr/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Upravljanje telefonskim pozivima"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Nepoznato"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Propušteni poziv"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Propušteni pozivi"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Broj propuštenih poziva: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Propušten poziv kontakta <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Povratni poziv"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Poruka"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvuk poziva isključen."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Zvučnik je omogućen."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Sada ne mogu razgovarati. Što ima?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Nazvat ću vas odmah."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Zvat ću vas kasnije."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Sada ne mogu razgovarati. Nazovite me kasnije."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Brzi odgovori"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Uređivanje brzih odgovora"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Brzi odgovor"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Poruka poslana na broj <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Računi za pozivanje"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Vlasnik uređaja dopušta samo hitne pozive."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ova aplikacija ne može uspostavljati odlazne pozive bez dopuštenja za telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Unesite važeći broj da biste uspostavili poziv."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Poziv trenutačno nije moguć."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Onemogućite TTY način da biste omogućili videopozive."</string>
+    <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>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
new file mode 100644
index 0000000..5100262
--- /dev/null
+++ b/res/values-hu/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Híváskezelés"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Ismeretlen"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Nem fogadott hívás"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Nem fogadott hívások"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> nem fogadott hívás"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Nem fogadott hívás: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Visszahívás"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Üzenet"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Hívás némítva."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Kihangosítás engedélyezve."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Most nem alkalmas. Mi újság?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Hamarosan visszahívom."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Később visszahívom."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Most nem alkalmas. Hívna később?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Gyors válaszok"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Gyors válaszok szerkesztése"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Gyors válasz"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Üzenet elküldve ide: <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Telefonos fiókok"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Az eszköz tulajdonosa csak a segélyhívást engedélyezte."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Az alkalmazásból nem lehet kimenő hívást kezdeményezni a Telefon (Phone) engedély nélkül."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Hívásindításhoz adjon meg egy érvényes számot."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Jelenleg nem lehet videohívást hozzáadni."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Videohívások indításához kapcsolja ki a TTY módot."</string>
+    <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>
+</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..6143735
--- /dev/null
+++ b/res/values-hy-rAM/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Հեռախոսային զանգերի կառավարում"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Հեռախոս"</string>
+    <string name="unknown" msgid="6878797917991465859">"Անհայտ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Բաց թողնված զանգ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Բաց թողնված զանգեր"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> բաց թողնված զանգ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Բաց թողնված զանգ <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>-ից"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Հետ զանգել"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Ուղարկել հաղորդագրություն"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Զանգը խլացված է:"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Բարձրախոսը միացված է:"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Չեմ կարող խոսել հիմա: Ի՞նչ կա չկա:"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ես ձեզ հիմա հետ կզանգեմ:"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ես ձեր մի փոքր ուշ կզանգեմ:"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Չեմ կարող խոսել հիմա: Զանգե՞մ ձեզ մի փոքր ուշ:"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Արագ պատասխաններ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Խմբագրել արագ պատասխանները"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Արագ պատասխան"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Հաղորդագրությունն ուղարկվել է <xliff:g id="PHONE_NUMBER">%s</xliff:g>-ին:"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Հաշիվներ զանգերի համար"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Սարքի սեփականատերը թույլատրում է միայն արտակարգ իրավիճակի զանգերը:"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Առանց Հեռախոսի թույլտվության այս ծրագիրը չի կարող ելքային զանգեր կատարել:"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Զանգ կատարելու համար մուտքագրեք ճիշտ համար:"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Հնարավոր չէ ևս մեկ զանգ ավելացնել այս պահին:"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Տեսազանգեր կատարելու համար անջատեք TTY ռեժիմը:"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Բացակայում է ձայնային փոստի համարը"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM քարտում ձայնային փոստի ոչ մի համար գրանցված չէ:"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Ավելացնել համար"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Փոխե՞լ կանխադրված Համարհավաքի հավելվածը:"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Օգտագործե՞լ <xliff:g id="NEW_APP">%1$s</xliff:g> հավելվածը <xliff:g id="CURRENT_APP">%2$s</xliff:g>-ի փոխարեն որպես համարհավաքի կանխադրված հավելված:"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Դարձնե՞լ <xliff:g id="NEW_APP">%s</xliff:g> հավելվածը համարհավաքի կանխադրված հավելված:"</string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
new file mode 100644
index 0000000..ee111a7
--- /dev/null
+++ b/res/values-in/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Pengelolaan Panggilan Telepon"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telepon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Tidak diketahui"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Panggilan tak terjawab"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Panggilan tak terjawab"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> panggilan tak terjawab"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Panggilan tak terjawab dari <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Telepon"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Pesan"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Panggilan disenyapkan."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Pengeras suara ponsel diaktifkan."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Tak bisa bicara sekarang. Ada apa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Saya segera telepon balik."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Nanti saya telepon balik."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Tak bisa bicara skrg. Tlp lg nanti?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respons cepat"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit respons cepat"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Respons cepat"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Pesan dikirim ke <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Akun pemanggil"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Hanya panggilan darurat yang diizinkan oleh pemilik perangkat."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Aplikasi ini tidak dapat melakukan panggilan keluar tanpa izin Telepon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Untuk melakukan panggilan telepon, masukkan nomor yang valid."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Panggilan tidak dapat ditambahkan untuk saat ini."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Nonaktifkan Mode TTY untuk melakukan panggilan video."</string>
+    <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>
+</resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
new file mode 100644
index 0000000..c3c6a2f
--- /dev/null
+++ b/res/values-is-rIS/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Símtalastjórnun"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Sími"</string>
+    <string name="unknown" msgid="6878797917991465859">"Óþekkt"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Ósvarað símtal"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Ósvöruð símtöl"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ósvöruð símtöl"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Ósvarað símtal frá <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Hringja til baka"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Skilaboð"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Símtal þaggað."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Kveikt á hátalara."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kemst ekki í símann. Eitthvað títt?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ég hringi strax í þig til baka."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ég hringi í þig seinna."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Get ekki svarað. Heyrast síðar?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Snarsvör"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Breyta snarsvörum"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Snarsvar"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Skilaboð send til <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Símtalareikningar"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Eigandi tækisins leyfir aðeins neyðarsímtöl."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Þetta forrit getur ekki hringt án heimildar í símanum."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Sláðu inn gilt númer til að hringja símtal."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Ekki er hægt að bæta símtali við sem stendur."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Slökktu á fjarritastillingu til að hringja myndsímtöl."</string>
+    <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>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
new file mode 100644
index 0000000..ad998d1
--- /dev/null
+++ b/res/values-it/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Phone Call Management"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefono"</string>
+    <string name="unknown" msgid="6878797917991465859">"Sconosciuto"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chiamata senza risposta"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chiamate senza risposta"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chiamate senza risposta"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Chiamata senza risposta da <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Richiama"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Messaggio"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Chiamata disattivata."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Vivavoce attivo."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Non posso parlare ora. Che succede?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ti richiamo subito."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ti chiamo dopo."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Non posso parlare ora. Mi chiami dopo?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Risposte rapide"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Modifica risposte rapide"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Risposta rapida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Messaggio inviato a <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Account di chiamata"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Il proprietario del dispositivo consente soltanto chiamate di emergenza."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Non è possibile effettuare chiamate tramite questa applicazione senza l\'autorizzazione sul telefono."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Per effettuare una chiamata, inserisci un numero valido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Al momento non è possibile aggiungere la chiamata."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Per poter fare videochiamate devi disattivare la modalità TTY."</string>
+    <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>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
new file mode 100644
index 0000000..092559c
--- /dev/null
+++ b/res/values-iw/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ניהול שיחות טלפון"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"טלפון"</string>
+    <string name="unknown" msgid="6878797917991465859">"לא ידוע"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"שיחה שלא נענתה"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"שיחות שלא נענו"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> שיחות שלא נענו"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"שיחה שלא נענתה מאת <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"התקשר חזרה"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"שלח הודעה"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"שיחה מושתקת."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"רמקול מופעל."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"אני לא יכול לדבר עכשיו. מה קורה?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"אני מיד חוזר אליך."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"אני אתקשר אליך יותר מאוחר."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"אני לא יכול לדבר עכשיו. תתקשר אלי מאוחר יותר?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"תגובות מהירות"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ערוך תגובות מהירות"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"תגובה מהירה"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"הודעה נשלחה אל <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"חשבונות לביצוע שיחות"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"בעל המכשיר מתיר לבצע שיחות חירום בלבד."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"לא ניתן לבצע שיחות יוצאות באמצעות האפליקציה הזו ללא ההרשאה \'טלפון\'."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"כדי להתקשר, הזן מספר טלפון חוקי."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"לא ניתן כעת להוסיף את השיחה."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"‏השבת את מצב TTY כדי לבצע שיחות וידאו."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"חסר מספר של דואר קולי"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"‏בכרטיס ה-SIM לא מאוחסן מספר של דואר קולי."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"הוסף מספר"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"האם לשנות את אפליקציית החייגן שבברירת מחדל?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"האם להשתמש ב-<xliff:g id="NEW_APP">%1$s</xliff:g> במקום ב-<xliff:g id="CURRENT_APP">%2$s</xliff:g> כאפליקציית החייגן שבברירת מחדל?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"האם להשתמש ב-<xliff:g id="NEW_APP">%s</xliff:g> כאפליקציית החייגן שבברירת מחדל?"</string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
new file mode 100644
index 0000000..5d02108
--- /dev/null
+++ b/res/values-ja/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"通話管理"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"電話"</string>
+    <string name="unknown" msgid="6878797917991465859">"通知不可能"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"不在着信"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"不在着信"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"不在着信<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>件"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>さんからの不在着信"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"コールバック"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"メッセージ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"通話がミュートされています。"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"スピーカーが有効です。"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ただいま電話に出られません。ご用件をお知らせください。"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ただいま電話に出られません。すぐに折り返しご連絡いたします。"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ただいま電話に出られません。後ほど折り返しご連絡いたします。"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ただいま電話に出られません。後ほどご連絡をお願いいたします。"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"クイック返信"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"クイック返信の編集"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"クイック返信"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>にメッセージを送信しました。"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"通話アカウント"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"端末の所有者によって許可されているのは緊急通報のみです。"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"このアプリは、電話権限がないため発信できません。"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"発信するには、有効な番号を入力してください。"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"通話は現在追加できません。"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ビデオハングアウトを行うにはTTYモードを無効にしてください。"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"ボイスメール番号がありません"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIMカードにボイスメールの番号がありません。"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"番号を追加"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"既定の電話アプリを変更しますか?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g>を<xliff:g id="CURRENT_APP">%2$s</xliff:g>の代わりに既定の電話アプリとして使用しますか?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g>を既定の電話アプリとして使用しますか?"</string>
+</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..4c1fc06
--- /dev/null
+++ b/res/values-ka-rGE/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ტელეფონის ზარების მართვა"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ტელეფონი"</string>
+    <string name="unknown" msgid="6878797917991465859">"უცნობი"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"გამოტოვებული ზარი"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"გამოტოვებული ზარები"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> გამოტოვებული ზარები"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"გამოტოვებული ზარი <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>-ისგან"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"გადარეკვა"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"შეტყობინების გაგზავნა"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ზარი დადუმებულია."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"სპიკერები ჩართულია."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ვერ ვლაპარაკობ. რა ხდება?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ცოტა ხანში გადმოვრეკავ."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"მოგვიანებით გადმოვრეკავ."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ვერ ვპასუხობ. მოგვიანებით დამირეკე."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"სწრაფი პასუხი"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"სწრაფი პასუხის რედაქტირება"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"სწრაფი პასუხი"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"შეტყობინება გაიგზავნა <xliff:g id="PHONE_NUMBER">%s</xliff:g>-თან."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"დარეკვის ანგარიშები"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"მოწყობილობის მფლობელის მიერ ნებადართულია მხოლოდ საგანგებო ზარების განხორციელება."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ეს აპლიკაცია ტელეფონის ნებართვის გარეშე გამავალ ზარებს ვერ განახორციელებს."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ზარის განხორციელებისათვის, შეიყვანეთ მოქმედი ნომერი."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ამ ეტაპზე ზარის დამატება ვერ ხერხდება."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ვიდეოზარების განხორციელებისათვის, გთხოვთ, გამორთოთ TTY რეჟიმი"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"ხმოვანი ფოსტის ნომერი არ არის"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM ბარათზე ხმოვანი ფოსტის ნომერი შენახული არ არის."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"ნომრის დამატება"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"გსურთ ამკრეფის ნაგულისხმევი აპის შეცვლა?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"გსურთ ამკრეფის ნაგულისხმევ აპად <xliff:g id="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>
+</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
new file mode 100644
index 0000000..dc087f1
--- /dev/null
+++ b/res/values-kk-rKZ/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Телефон қоңырауларын басқару"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Белгісіз"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Қабылданбаған қоңырау"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Қабылданбаған қоңыраулар"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> қабылданбаған қоңыраулар"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> қоңырауы қабылданбаған"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Қоңырау шалу"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Хабар"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Қоңырау үнсіздендірілген."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Үндеткішті телефон қосылды."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Қазір сөйлесе алмаймын. Не болды?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Сізге кері қоңырау шаламын."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Сізге кейінірек қоңырау шаламын."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Қазір сөйлесе алмаймын. Кейінірек?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Жылдам жауаптар"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Жылдам жауаптарды жөндеу"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Жылдам жауап"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Хабар <xliff:g id="PHONE_NUMBER">%s</xliff:g> нөміріне жіберілді."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Қоңырау шалу есептік жазбалары"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Құрылғы иесі тек жедел қоңырауларға рұқсат еткен."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"\"Телефон\" рұқсатынсыз бұл қолданба шығыс қоңырауларды соға алмайды."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Қоңырау шалу үшін жарамды нөмірді енгізіңіз."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Қоңырауды қазіргі уақытта қосу мүмкін емес."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Бейне қоңырау шалу үшін Телетайп режимін өшіріңіз."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Дауыс хабарының нөмірі жоқ"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM картасында ешқандай дауыс хабарының нөмірі сақталмаған."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Нөмір қосу"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Әдепкі нөмір тергіш қолданбаны өзгерткіңіз келе ме?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="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>
+</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..4507e35
--- /dev/null
+++ b/res/values-km-rKH/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ការគ្រប់គ្រងការហៅទូរស័ព្ទ"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ទូរស័ព្ទ"</string>
+    <string name="unknown" msgid="6878797917991465859">"មិន​ស្គាល់"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ខកខាន​ទទួល"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ខកខាន​ទទួល"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ខកខាន​ការ​​ទទួល"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"ខកខាន​ទទួល​ពី <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ហៅ​ទៅ​វិញ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"សារ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ការ​ហៅ​បិទ​សំឡេង។"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"បាន​បើក​អូប៉ាល័រ​ទូរស័ព្ទ។"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"មិន​អាច​និយាយ​បាន​ឥឡូវ​នេះ។ មាន​អ្វី​កើត​ឡើង?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ខ្ញុំ​នឹង​ហៅ​​​​ទៅ​អ្នក​​វិញ។"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ខ្ញុំ​នឹង​ហៅ​ទៅ​អ្នក​នៅ​ពេល​ក្រោយ។"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"មិន​អាច​និយាយ​បាន​ទេ​ឥឡូវ​នេះ។ ហៅ​​​​មក​ខ្ញុំ​ពេល​ក្រោយ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ការ​ឆ្លើយតប​រហ័ស"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"កែ​ការ​ឆ្លើយតប​រហ័ស"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ឆ្លើយតប​រហ័ស"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"បាន​ផ្ញើ​សារ​ទៅ <xliff:g id="PHONE_NUMBER">%s</xliff:g> ។"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"គណនីហៅទូរស័ព្ទ"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"មានតែការហៅពេលអាសន្នប៉ុណ្ណោះត្រូវបានអនុញ្ញាតដោយម្ចាស់ឧបករណ៍។"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"កម្មវិធីនេះមិនអាចធ្វើការហៅចេញដោយគ្មានការអនុញ្ញាត ទូរស័ព្ទ បានទេ។"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ដើម្បីធ្វើការហៅ បញ្ចូលលេខដែលមានសុពលភាព។"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"មិន​អាច​បន្ថែម​​​នៅ​ពេល​នេះ​​បាន​ទេ។"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"សូមបិទដំណើរការរបៀប TTY ដើម្បីធ្វើការហៅជាវីដេអូ។"</string>
+    <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>
+</resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
new file mode 100644
index 0000000..e6a72c8
--- /dev/null
+++ b/res/values-kn-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ಫೋನ್ ಕರೆ ನಿರ್ವಹಣೆ"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ಫೋನ್"</string>
+    <string name="unknown" msgid="6878797917991465859">"ಅಜ್ಞಾತ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ಮಿಸ್ಡ್‌ ಕಾಲ್‌"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ತಪ್ಪಿದ ಕರೆಗಳು"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ತಪ್ಪಿದ ಕರೆಗಳು"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> ಅವರಿಂದ ಮಿಸ್ಡ್‌ ಕಾಲ್‌"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ಮರಳಿ ಕರೆ ಮಾಡಿ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"ಸಂದೇಶ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ಕರೆಯನ್ನು ಮ್ಯೂಟ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"ಸ್ಪೀಕರ್‌ಫೋನ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ಈಗ ಮಾತನಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಏನು ವಿಷಯ?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ನಾನು ಮರಳಿ ನಿಮಗೆ ಕರೆ ಮಾಡುತ್ತೇನೆ."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ನಾನು ನಂತರ ನಿಮಗೆ ಕರೆ ಮಾಡುತ್ತೇನೆ."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ಈಗ ಮಾತನಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಂತರ ಮಾಡುವಿರಾ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ತ್ವರಿತ ಪ್ರತಿಕ್ರಿಯೆಗಳು"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ತ್ವರಿತ ಪ್ರತಿಕ್ರಿಯೆ ಸಂಪಾದಿಸಿ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ತ್ವರಿತ ಪ್ರತಿಕ್ರಿಯೆ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> ಗೆ ಸಂದೇಶ ಕಳುಹಿಸಲಾಗಿದೆ."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"ಕರೆ ಮಾಡುವ ಖಾತೆಗಳು"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ಸಾಧನದ ಮಾಲೀಕರಿಂದ ತುರ್ತು ಕರೆಗಳನ್ನು ಮಾಡಲು ಮಾತ್ರ ಅವಕಾಶವಿದೆ."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಫೋನ್ ಅನುಮತಿಯಿಲ್ಲದೆ ಹೊರಹೋಗುವ ಕರೆಗಳನ್ನು ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ಕರೆಯನ್ನು ಮಾಡಲು, ಮಾನ್ಯವಾದ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ಕರೆಯನ್ನು ಈ ಸಮಯದಲ್ಲಿ ಸೇರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ವೀಡಿಯೊ ಕರೆಗಳನ್ನು ಮಾಡಲು TTY ಮೋಡ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
+    <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>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
new file mode 100644
index 0000000..55c639a
--- /dev/null
+++ b/res/values-ko/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"통화 관리"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"전화"</string>
+    <string name="unknown" msgid="6878797917991465859">"알 수 없음"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"부재중 전화"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"부재중 통화"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"부재중 통화 <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>통"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>의 부재중 전화"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"통화하기"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"문자 메시지"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"통화가 음소거되었습니다."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"스피커폰이 사용 설정되었습니다."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"통화 불가. 용무를 남겨주세요."</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"바로 다시 전화드리겠습니다."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"나중에 전화드리겠습니다."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"통화 불가. 나중에 전화주세요."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"빠른 응답"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"빠른 응답 수정"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"빠른 응답"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>(으)로 메시지를 보냈습니다."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"통화 계정"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"기기 소유자만 긴급 전화를 사용할 수 있습니다."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"전화 권한이 없으므로 애플리케이션에서 발신 전화를 걸 수 없습니다."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"전화를 걸려면 올바른 번호를 입력하세요."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"현재 통화를 추가할 수 없습니다."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"화상 통화를 하려면 TTY 모드를 중지하세요."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"음성사서함 번호 없음"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 카드에 저장된 음성사서함 번호가 없습니다."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"번호 추가"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"기본 다이얼러 앱을 변경하시겠습니까?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="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>
+</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
new file mode 100644
index 0000000..67ba196
--- /dev/null
+++ b/res/values-ky-rKG/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Телефон чалууларын башкаруу"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Белгисиз"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Кабыл алынбаган чалуу"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Кабыл алынбаган чалуулар"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> кабыл алынбаган чалуу"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> дегенден кабыл алынбаган чалуу"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Кайра чалуу"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Билдирүү"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Чалуу үнсүз тартипте."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Динамик иштеп жатат."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Азыр сүйлөшө албайм. Эмне болду?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Кайра чалам."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Кийинчерээк чалып коём."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Сүйлөшө албайм. Кийин чаласызбы?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Тез жооптор"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Тез жоопторду өзгөртүү"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Тез жооп"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> номуруна билдирүү жөнөтүлдү."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Чалуу каттоо эсептери"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Түзмөк ээси шашылыш кырдаалдарда чалууга гана уруксат берген"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Бул колдонмо тийиштүү уруксатсыз чалууларды жасай албайт."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Чалуу үчүн, жарактуу номер киргизиңиз."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Бул жолу чалууну кошуу мүмкүн эмес."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Видео чалууларды аткаруу үчүн Телетайп түзмөк режимин өчүрүңүз."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Үн почтасынын номери жок болуп жатат"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-картада сакталган үн почтасынын номери жок."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Номер кошуу"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Демейки номер тергич колдонмо өзгөрүлсүнбү?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Демейки номер тергич колдонмо катары мурунку <xliff:g id="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>
+</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..8e8b776
--- /dev/null
+++ b/res/values-lo-rLA/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ການ​ຈັດ​ການການ​ໂທລະ​ສັບ"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ໂທລະສັບ"</string>
+    <string name="unknown" msgid="6878797917991465859">"ບໍ່ຮູ້ຈັກ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ສາຍທີ່ບໍ່ໄດ້ຮັບ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ສາຍທີ່ບໍ່ໄດ້ຮັບ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ສາຍບໍ່ໄດ້ຮັບ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"ສາຍທີ່ບໍ່ໄດ້ຮັບຈາກ <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ໂທກັບ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"ຂໍ້ຄວາມ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ປິດສຽງການໂທແລ້ວ."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"ເປີດລຳໂພງແລ້ວ."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ບໍ່ສາມາດລົມໄດ້ໃນຕອນນີ້. ມີຫຍັງບໍ່?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ຂ້ອຍຈະໂທກັບຫາເຈົ້າທັນທີ."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ຂ້ອຍຈະໂທຫາເຈົ້ານຳຫຼັງ."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ຕອນນີ້ລົມບໍ່ໄດ້ເທື່ອ. ເຈົ້າຄ່ອຍໂທຫາຂ້ອຍໃໝ່ໄດ້ບໍ່?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ຕອບກັບດ່ວນ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ແກ້ໄຂຂໍ້ຄວາມຕອບກັບດ່ວນ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ຕອບກັບດ່ວນ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"ສົ່ງຂໍ້ຄວາມຫາ <xliff:g id="PHONE_NUMBER">%s</xliff:g> ແລ້ວ."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"ບັນ​ຊີ​ໂທ"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ພຽງ​ແຕ່​ການ​ໂທ​ສຸກ​ເສີນ​ທີ່​ໄດ້​ຮັບ​ອະ​ນຸ​ຍາດ​ຈາກ​ເຈົ້າ​ຂອງ​ອຸ​ປະ​ກອນ​ເທົ່າ​ນັ້ນ."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ນີ້​ບໍ່​ສາ​ມາດ​ໂທ​ອອກ​ໄດ້ ໂດຍ​ບໍ່​ມີ​ການ​ອະ​ນຸ​ຍາດ​ຂອງ​ໂທ​ລະ​ສັບ."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ເພື່ອ​ທີ່​ຈະ​ໂທ, ປ້ອນ​ເບີ​ໂທ​ທີ່​ໃຊ້​ໄດ້​ເຂົ້າ​ໄປ."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"​ບໍ່​ສາ​ມາດ​ເພີ່ມ​ການ​ໂທ​ໄດ້​ໃນ​ເວ​ລາ​ນີ້."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ກະ​ລຸ​ນາ​ປິດ​ໃຊ້​ງານ​ໂໝດ TTY ເພື່ອ​ໂທວິ​ດີ​ໂອ."</string>
+    <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>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
new file mode 100644
index 0000000..8c0734c
--- /dev/null
+++ b/res/values-lt/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefono skambučių tvarkymas"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefonas"</string>
+    <string name="unknown" msgid="6878797917991465859">"Nežinomas"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Praleistas skambutis"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Praleisti skambučiai"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> praleisti (-ų) skambučiai (-ų)"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"praleistas skambutis nuo <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Perskambinti"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Pranešimas"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Skambutis nutildytas."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Garsiakalbis įgalintas."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Dabar negaliu kalbėti. Kas nutiko?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Netrukus perskambinsiu."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Paskambinsiu vėliau."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Dabar negaliu kalb. Pask. vėliau."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Greiti atsakai"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Redaguoti greitus atsakus"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Greitas atsakas"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Pranešimas išsiųstas numeriu <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Skambinimo paskyros"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Įrenginio savininkas leidžia skambinti tik pagalbos numeriais."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Naudojant šią programą negalima skambinti be telefono leidimo."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Kad galėtumėte paskambinti, įveskite tinkamą numerį."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Šiuo metu dar vieno skambučio atlikti negalima."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Išjunkite TTY režimą, kad galėtumėte atlikti vaizdo skambučius."</string>
+    <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>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
new file mode 100644
index 0000000..9d7d729
--- /dev/null
+++ b/res/values-lv/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Tālruņa zvanu pārvaldība"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Tālrunis"</string>
+    <string name="unknown" msgid="6878797917991465859">"Nezināms"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Neatbildēts zvans"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Neatbildētie zvani"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> neatbildēts(-i) zvans(-i)"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Neatbildēts zvans no: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Atzvanīt"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Ziņojums"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvana skaņa ir izslēgta."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Skaļrunis ir iespējots."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Nevaru runāt. Kas gadījās?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Tūlīt atzvanīšu."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Piezvanīšu vēlāk."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nevaru runāt. Vai piezvanīsi vēlāk?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Ātrās atbildes"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Ātro atbilžu rediģēšana"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Ātrā atbilde"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Ziņojums nosūt. uz šādu tālr. nr.: <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Zvanu konti"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Ierīces īpašnieks ļauj veikt tikai ārkārtas zvanus."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Šajā lietojumprogrammā nevar veikt izejošos zvanus bez tālruņa atļaujas."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Lai veiktu zvanu, ievadiet derīgu numuru."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Šobrīd nevar pievienot zvanu."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Lai veiktu videozvanus, lūdzu, atspējojiet teksta tālruņa režīmu."</string>
+    <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>
+</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
new file mode 100644
index 0000000..dc15c2b
--- /dev/null
+++ b/res/values-mk-rMK/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Управување со телефонски повици"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Непознато"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропуштен повик"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропуштени повици"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> пропуштени повици"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Пропуштен повик од <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Повикува назад"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Порака"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Повикот е со исклучен звук"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Интерфонот е овозможен."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Не можам да зборувам сега. Што има?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Веднаш ќе ти се јавам."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ќе ти се јавам подоцна."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Не можам да зборувам сега. Јави ми се подоцна?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Брзи одговори"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Уреди брзи одговори"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Брз одговор"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Порака е испратена на <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Сметки за повици"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Дозволени се само итни повици од страна на сопственикот на уредот."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Оваа апликација не може да прави појдовни повици без дозволата Телефон."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"За да повикате, внесете важечки број."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Повикот не може да се додаде во моментов."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Оневозможете го режимот TTY за да остварите видеоповици."</string>
+    <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>
+</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
new file mode 100644
index 0000000..f1f882e
--- /dev/null
+++ b/res/values-ml-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ഫോൺ കോൾ മാനേജ്‌മെന്റ്"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ഫോണ്‍"</string>
+    <string name="unknown" msgid="6878797917991465859">"അജ്ഞാതം"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"മിസ്‌ഡ് കോൾ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"മിസ്‌ഡ് കോളുകൾ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> മിസ്‌ഡ് കോളുകൾ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> എന്നതിൽ നിന്നുള്ള മിസ്‌ഡ് കോൾ"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"കോൾബാക്ക്"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"സന്ദേശം"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"കോൾ നിശബ്‌ദമാക്കി."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"സ്‌പീക്കർഫോൺ പ്രവർത്തനക്ഷമമാക്കി."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ഇപ്പോൾ സംസാരിക്കാനാകില്ല. എന്തുചെയ്യുന്നു?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ഞാൻ നിങ്ങളെ ഉടൻ തിരിച്ചുവിളിക്കാം."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ഞാൻ നിങ്ങളെ പിന്നീട് വിളിക്കാം."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ഇപ്പോൾ സംസാരിക്കാനാകില്ല. എന്നെ പിന്നീട് വിളിക്കാമോ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ദ്രുത പ്രതികരണങ്ങൾ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"പ്രതികരണം എഡിറ്റുചെയ്യൂ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ദ്രുത പ്രതികരണം"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> എന്നതിലേക്ക് സന്ദേശമയച്ചു."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"കോളിംഗ് അക്കൗണ്ട്"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ഉപകരണ ഉടമ അടിയന്തിര കോളുകൾ മാത്രമേ അനുവദിച്ചിട്ടുള്ളൂ."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ഫോൺ അനുമതിയില്ലാതെ ഈ അപ്ലിക്കേഷന് ഔട്ട്‌ഗോയിംഗ് കോളുകൾ വിളിക്കാൻ കഴിയില്ല."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ഒരു കോൾ ചെയ്യുന്നതിന്, സാധുതയുള്ള നമ്പർ നൽകുക."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"കോൾ ഇപ്പോൾ ചേർക്കാനാകില്ല."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"വീഡിയോ കോളുകൾ നടത്താൻ TTY മോഡ് പ്രവർത്തനരഹിതമാക്കുക."</string>
+    <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>
+</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..ec359db
--- /dev/null
+++ b/res/values-mn-rMN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Гар утасны Дуудлагын Удирдлага"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Гар утас"</string>
+    <string name="unknown" msgid="6878797917991465859">"Тодорхойгүй"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Аваагүй дуудлага"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Аваагүй дуудлагууд"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> аваагүй дуудлага"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>-н аваагүй дуудлага"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Буцааж залгах"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Зурвас"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Дууг хаасан."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Чанга яригчийг идэвхжүүлсэн."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ярих боломжгүй байна. Сонин юу байна?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Би тань руу яг одоо буцаагаад залгана."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Би тань руу дараа залгана."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Одоо ярих боломжгүй байна. Дараа надруу залгах уу?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Шуурхай хариунууд"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Шуурхай хариунуудыг засах"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Шуурхай хариу"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Зурвасыг <xliff:g id="PHONE_NUMBER">%s</xliff:g> руу илгээв."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Дуудлагын эрхтэй бүртгэлүүд"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Энэхүү төхөөрөмжийн эзэмшигч нь зөвхөн түргэн тусламжийн дуудлага хийх боломжтой болгосон."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Энэ апп нь утасны зөвшөөрөлгүйгээр дуудлага хийх боломжгүй."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Дуудлага хийхийн тулд хүчин төгөлдөр дугаар оруулна уу."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Одоо дуудлага нэмэх боломжгүй."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Видео дуудлага хийхийн тулд TTY горимыг идэвхгүй болгоно уу."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Дуут шуудангийн дугаар байхгүй"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM карт дээр дуут шуудангийн дугаар хадгалагдаагүй байна."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Дугаар нэмэх"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Үндсэн залгагч апп-ыг өөрчлөх үү?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="NEW_APP">%1$s</xliff:g>-ыг <xliff:g id="CURRENT_APP">%2$s</xliff:g>-ын оронд таны үндсэн залгагч апп болгон тохируулах уу?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"<xliff:g id="NEW_APP">%s</xliff:g>-ыг таны үндсэн залгагч апп болгон тохируулах уу?"</string>
+</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
new file mode 100644
index 0000000..9bb0d9d
--- /dev/null
+++ b/res/values-mr-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"फोन कॉल व्यवस्थापन"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"फोन"</string>
+    <string name="unknown" msgid="6878797917991465859">"अज्ञात"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"सुटलेला कॉल"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"सुटलेले कॉल"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> सुटलेले कॉल"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> कडील सुटलेला कॉल"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"पुन्हा कॉल करा"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"संदेश"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"कॉल नि.शब्‍द केला."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"स्‍पीकरफोन सक्षम केला."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"आत्ता बोलू शकत नाही. काय चालले आहे?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"मी आपल्‍याला परत कॉल करेन."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"मी आपल्‍याला नंतर कॉल करेन."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"आत्ता बोलू शकत नाही. नंतर कॉल करा?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"द्रुत प्रतिसाद"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"द्रुत प्रतिसाद संपादित करा"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"द्रुत प्रतिसाद"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"संदेश <xliff:g id="PHONE_NUMBER">%s</xliff:g> वर पाठविला."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"कॉल करण्याची खाती"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"डिव्हाइस मालकाद्वारे केवळ आणीबाणी कॉलना अनुमती आहे."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"हा अनुप्रयोग फोन परवानगी शिवाय कॉल करू शकत नाही."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"कॉल करण्यासाठी, एक वैध नंबर प्रविष्ट करा."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"यावेळी कॉल जोडला जाऊ शकत नाही."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"कृपया व्हिडिओ कॉल करण्‍यासाठी TTY मोड अक्षम करा."</string>
+    <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>
+</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..27309de
--- /dev/null
+++ b/res/values-ms-rMY/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Pengurusan Panggilan Telefon"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Tidak diketahui"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Panggilan tidak dijawab"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Panggilan tidak dijawab"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> panggilan tidak dijawab"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Panggilan tidak dijawab daripada <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Panggil balik"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mesej"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Panggilan diredam."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Telefon pembesar suara didayakan."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Sedang sibuk. Ada apa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Saya akn segera hubungi awak nanti."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Saya akan hubungi awak kemudian."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Sedang sibuk. Telefon saya nanti?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respons pantas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edit respons pantas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Respons pantas"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesej dihantar ke <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Akaun panggilan"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Panggilan kecemasan sahaja yang dibenarkan oleh pemilik peranti."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Aplikasi ini tidak boleh membuat panggilan keluar tanpa kebenaran Telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Untuk membuat panggilan, masukkan nombor yang sah."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Panggilan tidak boleh ditambahkan pada masa ini."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Sila lumpuhkan Mod TTY untuk membuat panggilan video."</string>
+    <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>
+</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
new file mode 100644
index 0000000..8782c9d
--- /dev/null
+++ b/res/values-my-rMM/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ဖုန်းခေါ်ဆိုခြင်း စီမံမှု"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ဖုန်း"</string>
+    <string name="unknown" msgid="6878797917991465859">"အကြောင်းအရာ မသိရှိ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"လွဲသွားသော ဖုန်းခေါ်မှု"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"လွဲသွားသော ဖုန်းခေါ်မှုများ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> လွဲသွားသော ဖုန်းခေါ်မှုများ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> က ဖုန်းခေါ်မှုကို မကိုင်မိပါ"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ပြန်ခေါ်ပါ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"စာတို"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"နားထောင်ရုံသာ (စကားပြောပိတ်ထားသည်)"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"စပီကာဖုန်း သုံးလို့ရသည်"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"အခုပြောလို့မရဘူး။အကြောင်းထူးရှိလား?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ပြန်ခေါ်လိုက်မယ်နော်"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"နောက်မှ ပြန်ခေါ်လိုက်မယ်"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"အခုပြောလို့မရဘူး။ထပ်ခေါ်နော်?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"အမြန်တုံ့ပြန်ချက်များ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"အမြန်တုံ့ပြန်ချက်များပြင်ခြင်း"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"အမြန်တုံ့ပြန်ချက်"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> ထံ စာတိုပို့လိုက်ပါပြီ"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"ခေါ်ဆိုသော အကောင့်များ"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"အရေးပေါ်ဖုန်းများကိုသာ ခေါ်ဆိုနိုင်ရန် စက်ကိရိယာပိုင်ရှင်က ခွင့်ပြုထားသည်။"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ဤအပ္ပလီကေးရှင်းသည် ဖုန်းခွင့်ပြုချက်မရှိဘဲ အထွက်ခေါ်ဆိုမှု ပြုလုပ်၍မရပါ။"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ဖုန်းခေါ်ရန်အတွက်၊ သင့်လျော်သည့်နံပါတ် ရိုက်ထည့်ပါ။"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ဗွီဒီယိုခေါ်နေစဉ် ထပ်ခေါ်မရပါ။"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ဗီဒီယိုခေါ်ဆိုမှုများ ပြုလုပ်ရန် ကျေးဇူးပြု၍ TTY မုဒ်ကို ပိတ်ထားပါ။"</string>
+    <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>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
new file mode 100644
index 0000000..6244a0c
--- /dev/null
+++ b/res/values-nb/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Administrering av telefonsamtaler"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Ukjent"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Tapt anrop"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Tapte anrop"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> tapte anrop"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Tapt anrop fra <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Ring tilbake"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Melding"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Samtalelyd er kuttet."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Høyttaler er aktivert."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kan ikke snakke nå. Hva skjer?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Jeg ringer deg tilbake straks."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Jeg ringer deg senere."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kan ikke nå. Ring meg senere."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Hurtigsvar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Rediger hurtigsvar"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Hurtigsvar"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Melding er sendt til <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Ringekontoer"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Eieren av enheten tillater bare nødanrop."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Denne appen kan ikke ringe uten tillatelse fra telefonen."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Skriv inn et gyldig nummer for å plassere en samtale."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Anrop kan ikke legges til akkurat nå."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Slå av TTY-modus for å starte videosamtaler."</string>
+    <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>
+</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000..bd7097e
--- /dev/null
+++ b/res/values-ne-rNP/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"फोन कल व्यवस्थापन"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"फोन"</string>
+    <string name="unknown" msgid="6878797917991465859">"अज्ञात"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"छुटेका कल"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"छुटेका कल"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> छुटेका कलहरू"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>बाट छुटेका कल"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"फेरि कल गर्नुहोस्"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"सन्देश"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"कल म्युट भयो।"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"स्पिकरफोन सक्षम भयो।"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"अहिले कुरा गर्न मिल्दैन। के भइरहेको छ?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"मैले तपाईंलाई तुरुन्तै कल गर्ने छु।"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"म तपाईंलाई पछि कल गर्ने छु।"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"अहिले कुरा गर्न सक्नु हुन्न। मलाई पछि कल गर्नुहोस्?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"द्रुत प्रतिक्रियाहरू"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"द्रुत प्रतिक्रियाहरू सम्पादन गर्नुहोस्"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"द्रुत प्रतिक्रिया"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> लाई सन्देश पठाइयो।"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"कलिङ खाताहरू"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"यन्त्र मालिकद्वारा आपतकालीन कलहरू मात्र गर्न अनुमति दिइएको छ।"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"यो अनुप्रयोगले फोनको अनुमति बिना बहिर्गमन कलहरू गर्न सक्दैन।"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"एक कल गर्नको लागि, एक वैध नम्बर प्रविष्ट गर्नुहोस्।"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"यस समयमा कल थप गर्न सकिँदैन।"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"कृपया भिडियो कलहरू गर्न TTY मोड निष्क्रिय गर्नुहोस्।"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"भ्वाइसमेल नम्बर हराइरहेको छ"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM कार्डमा कुनै पनि भ्वाइसमेल नम्बर भण्डारण भएको छैन।"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"नम्बर थप्नुहोस्"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"पूर्वनिर्धारित डायलर अनुप्रयोग फेर्ने हो?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="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>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
new file mode 100644
index 0000000..06dc193
--- /dev/null
+++ b/res/values-nl/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefoonoproepbeheer"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefoon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Onbekend"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Gemiste oproep"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Gemiste oproepen"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> gemiste oproepen"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Gemiste oproep van <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Terugbellen"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Bericht"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Oproep gedempt."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Telefoonluidspreker is ingeschakeld."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kan nu niet opnemen. Alles goed?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Ik bel je zo terug."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ik bel je later."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kan nu niet opnemen. Bel me later."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Snelle reacties"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Snelle reacties bewerken"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Snelle reactie"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Bericht verzonden naar <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Oproepaccounts"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Alleen noodoproepen zijn toegestaan door de apparaateigenaar."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Deze app kan geen uitgaande oproepen starten zonder telefoonrechten."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Als u wilt bellen, moet u een geldig nummer invoeren."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Oproep kan momenteel niet worden toegevoegd."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Schakel de TTY-modus uit om videogesprekken te voeren."</string>
+    <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>
+</resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000..343c28d
--- /dev/null
+++ b/res/values-pa-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ਫ਼ੋਨ - ਕਾਲ ਪ੍ਰਬੰਧਨ"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ਫ਼ੋਨ"</string>
+    <string name="unknown" msgid="6878797917991465859">"ਅਗਿਆਤ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"ਮਿਸਡ ਕਾਲ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ਮਿਸਡ ਕਾਲਾਂ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ਮਿਸਡ ਕਾਲਾਂ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> ਵੱਲੋਂ ਮਿਸਡ ਕਾਲ"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"ਕਾਲ ਬੈਕ ਕਰੋ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"ਸੁਨੇਹਾ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ਕਾਲ ਮਿਊਟ ਕੀਤੀ।"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"ਸਪੀਕਰਫੋਨ ਸਮਰਥਿਤ।"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ਹੁਣ ਗੱਲ ਨਹੀਂ ਕਰ ਸਕਦਾ। ਕੀ ਹੋ ਰਿਹਾ ਹੈ?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"ਮੈਂ ਤੁਹਾਨੂੰ ਹੁਣੇ ਵਾਪਸ ਕਾਲ ਕਰਾਂਗਾ।"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"ਮੈਂ ਤੁਹਾਨੂੰ ਬਾਅਦ ਵਿੱਚ ਕਾਲ ਕਰਾਂਗਾ।"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ਹੁਣ ਗੱਲ ਨਹੀਂ ਕਰ ਸਕਦਾ। ਕੀ ਮੈਨੂੰ ਬਾਅਦ ਵਿੱਚ ਫੋਨ ਕਰ ਸਕਦੇ ਹੋ?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ਤਤਕਾਲ ਜਵਾਬ"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ਤਤਕਾਲ ਜਵਾਬ ਸੰਪਾਦਿਤ ਕਰੋ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ਤਤਕਾਲ ਜਵਾਬ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"ਸੁਨੇਹਾ <xliff:g id="PHONE_NUMBER">%s</xliff:g> ਨੂੰ ਭੇਜਿਆ ਗਿਆ।"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"ਕਾਲਿੰਗ ਖਾਤੇ"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"ਡਿਵਾਈਸ ਦੇ ਮਾਲਕ ਵੱਲੋਂ ਕੇਵਲ ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ ਦੀ ਆਗਿਆ ਹੈ।"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ਇਹ ਐਪਲੀਕੇਸ਼ਨ ਫੋਨ ਅਨੁਮਤੀ ਦੇ ਬਿਨਾਂ ਆਉਟਗੋਇੰਗ ਕਾਲਾਂ ਨਹੀਂ ਕਰ ਸਕਦੀ।"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ਇੱਕ ਕਾਲ ਕਰਨ ਲਈ, ਇੱਕ ਪ੍ਰਮਾਣਿਕ ਨੰਬਰ ਦਰਜ ਕਰੋ।"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ਇਸ ਵੇਲੇ ਕਾਲ ਨਹੀਂ ਜੋੜੀ ਸਕਦੀ।"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"ਕਿਰਪਾ ਕਰਕੇ ਵੀਡੀਓ ਕਾਲਾਂ ਨੂੰ ਕਰਨ ਲਈ TTY ਮੋਡ ਅਸਮਰਥਿਤ ਕਰੋ."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"ਲੁਪਤ ਵੌਇਸਮੇਲ ਨੰਬਰ"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM ਕਾਰਡ ਤੇ ਕੋਈ ਵੌਇਸਮੇਲ ਨੰਬਰ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ।"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"ਨੰਬਰ ਜੋੜੋ"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"ਕੀ ਡਿਫ਼ੌਲਟ ਡਾਇਲਰ ਐਪ ਨੂੰ ਬਦਲਣਾ ਹੈ?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"ਕੀ <xliff:g id="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>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
new file mode 100644
index 0000000..5c5f722
--- /dev/null
+++ b/res/values-pl/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefon – zarządzanie połączeniami"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Nieznany"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Nieodebrane połączenie"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Połączenia nieodebrane"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> nieodebranych połączeń"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Nieodebrane połączenie z <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Oddzwoń"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Wiadomość"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Połączenie wyciszone."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Głośnik włączony."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Nie mogę rozmawiać. Co słychać?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Za chwilę do Ciebie oddzwonię."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Zadzwonię do Ciebie później."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nie mogę rozmawiać. Zadzwonisz później?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Szybkie odpowiedzi"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Edytuj szybkie odpowiedzi"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Szybka odpowiedź"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Wiadomość wysłano na numer <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Konta telefoniczne"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Właściciel urządzenia zezwala tylko na połączenia alarmowe."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ta aplikacja nie może wykonywać połączeń bez uprawnienia Telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Aby zadzwonić, wybierz prawidłowy numer."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Nie można w tej chwili dodać połączenia."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Wyłącz tryb TTY, by korzystać z rozmów wideo."</string>
+    <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>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..b3dfff6
--- /dev/null
+++ b/res/values-pt-rPT/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gestão de chamadas do telemóvel"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telemóvel"</string>
+    <string name="unknown" msgid="6878797917991465859">"Desconhecido"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chamada não atendida"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chamadas não atendidas"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chamadas não atendidas"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Chamada não atendida de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Ligar de volta"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mensagem"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Chamada sem som."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Alta voz ativada."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Não posso falar agora. Que se passa?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Telefono-lhe já a seguir."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Telefono-lhe mais tarde."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Pode telefonar-me mais tarde?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respostas rápidas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editar respostas rápidas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Resposta rápida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mensagem enviada para <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Contas de chamadas"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Só são permitidas chamadas de emergência pelo proprietário do dispositivo."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Esta aplicação não pode fazer chamadas sem a autorização do telefone."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Para telefonar, introduza um número válido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Não é possível adicionar a chamada neste momento."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Desative o modo teletipo para efetuar videochamadas."</string>
+    <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>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
new file mode 100644
index 0000000..5daa496
--- /dev/null
+++ b/res/values-pt/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Gerenciamento de chamadas telefônicas"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefone"</string>
+    <string name="unknown" msgid="6878797917991465859">"Desconhecido"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chamada perdida"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chamadas perdidas"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chamadas perdidas"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Chamada perdida de <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Retornar chamada"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mensagem"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Chamada sem áudio."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Viva-voz ativado."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Não posso falar agora. Manda um SMS, por favor?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Já te ligo de volta."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Eu te ligo mais tarde."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Não posso falar agora. Liga depois, por favor?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Respostas rápidas"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editar respostas rápidas"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Resposta rápida"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mensagem enviada para <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Contas de chamadas"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Apenas chamadas de emergência são permitidas pelo proprietário do dispositivo."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Este aplicativo não pode fazer chamadas sem a permissão do smartphone."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Para realizar uma chamada, digite um número válido."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"No momento, não é possível adicionar a chamada."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Desative o modo TTD para realizar vídeo chamadas."</string>
+    <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>
+</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
new file mode 100644
index 0000000..5478e7f
--- /dev/null
+++ b/res/values-ro/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefon – Gestionarea apelurilor"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Necunoscut"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Apel nepreluat"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Apeluri nepreluate"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> (de) apeluri nepreluate"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Apel nepreluat de la <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Sunați"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mesaj"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Apel cu sunet dezactivat."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Difuzor activat."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Nu pot acum. Despre ce e vorba?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Te sun imediat înapoi."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Te sun mai târziu."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nu pot acum. Vorbim mai târziu?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Răspunsuri rapide"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Editaţi răspunsurile rapide"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Răspuns rapid"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesajul a fost trimis la <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Conturi pentru apelare"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Proprietarul dispozitivului permite numai apelurile de urgență."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Această aplicație nu poate efectua apeluri fără permisiunea Telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Pentru a apela, introduceți un număr valid."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Apelul nu poate fi adăugat în acest moment."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Dezactivați modul TTY pentru a iniția apeluri video."</string>
+    <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>
+</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
new file mode 100644
index 0000000..fe8c5be
--- /dev/null
+++ b/res/values-ru/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Телефон – управление звонками"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Неизвестный абонент"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропущенный вызов"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропущенные вызовы"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Пропущенных вызовов: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Пропущенные вызовы от абонента <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Позвонить"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Написать"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Звук выключен."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Громкая связь включена."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Не могу говорить. Что случилось?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Я сейчас вам перезвоню."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Я перезвоню вам позже."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Не могу говорить. Позвоните позже."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Быстрые ответы"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Быстрые ответы"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Быстрый ответ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Сообщение отправлено на номер <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Аккаунты для звонков"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Владелец устройства разрешил только экстренные вызовы."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Приложение не может совершать звонки без соответствующего разрешения."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Недействительный номер."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Невозможно позвонить в данный момент"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Чтобы делать видеозвонки, отключите режим телетайпа"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Не указан номер голосовой почты"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карте нет ни одного номера голосовой почты."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Добавить номер"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Новое приложение для звонков"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"\"<xliff:g id="NEW_APP">%1$s</xliff:g>\" станет приложением для звонков по умолчанию вместо \"<xliff:g id="CURRENT_APP">%2$s</xliff:g>\". Продолжить?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"\"<xliff:g id="NEW_APP">%s</xliff:g>\" станет приложением для звонков по умолчанию. Продолжить?"</string>
+</resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
new file mode 100644
index 0000000..215b699
--- /dev/null
+++ b/res/values-si-rLK/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"දුරකථන ඇමතුම් කළමනාකරණය"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"දුරකථනය"</string>
+    <string name="unknown" msgid="6878797917991465859">"නොදනී"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"මඟ හැරුණු ඇමතුම"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"මඟ හැරුණු ඇමතුම්"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"මඟ හැරුණු ඇමතුම් <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> වෙතින් මඟ හැරුණු ඇමතුම්"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"නැවත අමතන්න"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"පණිවිඩය"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ඇමතුම නිශ්ශබ්දයි."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"ස්පිකර්ෆෝන් සබලයි."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"දැන් කතාකරන්න බැහැ. මොකද වෙලා තියෙන්නෙ?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"මම ඔබට දැන්ම ඇමතුමක් ගන්න."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"මම ඔබට පසුව අමතන්නම්."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"දැන් කථා කරන්න බෑ. පසුව අමතන්නද?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"ක්ෂණික ප්‍රතිචාර"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"ක්ෂණික ප්‍රතිචාර සංස්කරණය කරන්න"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"ක්ෂණික ප්‍රතිචාරය"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> හට පණිවිඩය යවන්න."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"ඇමතීමේ ගිණුම්"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"උපාංගයේ හිමිකරු හදිසි ඇමතුම්වලට පමණක් ඉඩ දෙයි."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"දුරකථන අවසරයෙන් තොරව මෙම යෙදුමට පිටතට යන ඇමතුම් සිදු කළ නොහැකිය."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"ඇමතුමක් ලබාගැනීමට, වලංගු අංකයක් ලබාගන්න."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"මේ වේලාවේ ඇමතුම එකතු කළ නොහැක."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"වීඩියෝ ඇමතුම් ලබා ගැනීමට කරුණාකර TTY මෝඩය අබල කරන්න."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"හඬ තැපැල් අංකය නැත"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM කාඩ් පතෙහි හඬ තැපැල් අංකයක් ආචිත වී නැත."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"අංකයක් එක් කරන්න"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"සුපුරුදු දුරකථන යෙදුම වෙනස් කරන්න ද?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="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>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
new file mode 100644
index 0000000..7bb553c
--- /dev/null
+++ b/res/values-sk/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Správa telefónnych hovorov"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefón"</string>
+    <string name="unknown" msgid="6878797917991465859">"Neznáme"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Zmeškaný hovor"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Zmeškané hovory"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Zmeškané hovory: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>."</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Zmeškaný hovor od volajúceho <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Zavolať"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Napísať"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvuk hovoru bol vypnutý."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Reproduktor je povolený."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Teraz nemôžem hovoriť, o čo ide?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Zavolám späť."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Zavolám neskôr."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Teraz nemôžem, zavolajte inokedy."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Rýchle odpovede"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Upraviť rýchle odpovede"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Rýchla odpoveď"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Správa bola odoslaná na číslo <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Telefónne účty"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Vlastník zariadenia povolil iba tiesňové volania"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"V tejto aplikácii nie je možné uskutočňovať odchádzajúce hovory bez povolenia Telefón"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Ak chcete volať, zadajte platné číslo"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hovor momentálne nie je možné pridať."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Ak chcete uskutočňovať videohovory, deaktivujte režim TTY."</string>
+    <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>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
new file mode 100644
index 0000000..1ea6801
--- /dev/null
+++ b/res/values-sl/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Upravljanje telefonskih klicev"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Neznano"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Neodgovorjeni klic"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Neodgovorjeni klici"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> neodgovorjenih klicev"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Neodgovorjeni klic od <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Povratni klic"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Sporočilo"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Klic izključen."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Zvočnik omogočen."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Zdaj ne morem govoriti. Za kaj gre?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Takoj bom poklical."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Poklical bom pozneje."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Zdaj ne morem govoriti. Pozneje?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Hitri odgovori"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Urejanje hitrih odgovorov"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Hiter odgovor"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"SMS poslan na številko <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Računi za klicanje"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Lastnik naprave dovoljuje samo opravljanje klicev v sili"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ta aplikacija lahko opravlja odhodne klice brez dovoljenja za telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Če želite opraviti klic, vnesite veljavno številko."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Klica trenutno ni mogoče dodati."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Če želite opravljati videoklice, onemogočite način TTY."</string>
+    <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>
+</resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
new file mode 100644
index 0000000..de628f7
--- /dev/null
+++ b/res/values-sq-rAL/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Menaxhimi i telefonatave"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefoni"</string>
+    <string name="unknown" msgid="6878797917991465859">"I panjohur"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Telefonatë e humbur"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Telefonata të humbura"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> telefonata të humbura"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Telefonatë e humbur nga <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Telefono"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mesazh"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Telefonata kaloi në heshtje."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Altoparlanti u aktivizua."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Nuk flas dot tani. Si është puna?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Do të të telefonoj menjëherë."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Do të të telefonoj më vonë."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Nuk mund të flas tani. Do më telefonosh më vonë?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Përgjigje të shpejta"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Redakto përgjigjet e shpejta"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Përgjigje e shpejtë"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesazhi u dërgua te <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Llogaritë e telefonatave"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Vetëm telefonatat e urgjencës lejohen nga zotëruesi i pajisjes."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ky aplikacion nuk mund të kryejë telefonata dalëse pa lejen e Telefonit."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Për të kryer një telefonatë, fut një numër të vlefshëm."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Telefonata nuk mund të shtohet këtë herë."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Çaktivizo modalitetin TTY për të kryer telefonata me video."</string>
+    <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>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
new file mode 100644
index 0000000..fcd44e0
--- /dev/null
+++ b/res/values-sr/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Управљање телефонским позивима"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Непознато"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропуштен позив"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропуштени позиви"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Број пропуштених позива: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Пропуштен позив од: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Узврати позив"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Порука"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Звук позива је искључен."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Спикерфон је омогућен."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"У гужви сам. О чему се ради?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Позваћу те ускоро."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Позваћу те касније."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"У гужви сам. Да се чујемо касније?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Брзи одговори"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Измена брзих одговора"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Брзи одговор"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Порука је послата на број <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Налози за позивање"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Власник уређаја је дозволио само хитне позиве."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ова апликација не може да позива без дозволе за телефонирање."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Да бисте упутили позив, унесите важећи број."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Тренутно није могуће додати позив."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Онемогућите TTY режим да бисте упућивали видео позиве."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Недостаје број за говорну пошту"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"Није ускладиштен ниједан број говорне поште на SIM картици."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Додај број"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Променити подразумевану апликацију Телефон?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Желите ли да користите апликацију <xliff:g id="NEW_APP">%1$s</xliff:g> уместо апликације <xliff:g id="CURRENT_APP">%2$s</xliff:g> као подразумевану апликацију за позивање телефонских бројева?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Желите ли да користите апликацију <xliff:g id="NEW_APP">%s</xliff:g> као подразумевану апликацију за позивање телефонских бројева?"</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
new file mode 100644
index 0000000..e342c05
--- /dev/null
+++ b/res/values-sv/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Samtalshantering"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Okänd"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missat samtal"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missade samtal"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missade samtal"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Missat samtal från <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Ring upp"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Sms:a"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Samtalets ljud avstängt."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Högtalartelefon aktiverad."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Kan inte prata nu. Läget?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Jag ringer tillbaka alldeles strax."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Jag ringer dig senare."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Kan inte prata nu. Ring senare!"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Snabbsvar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Redigera snabbsvar"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Snabbsvar"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Meddelandet har skickats till <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Konton för samtal"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Endast nödsamtal är tillåtna av enhetens ägare."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Den här appen kan inte göra utgående samtal utan behörigheten Telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Ange ett giltigt nummer om du vill ringa ett samtal."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Det går inte att lägga till samtalet just nu."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Inaktivera texttelefonläget om du vill ringa videosamtal."</string>
+    <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>
+</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
new file mode 100644
index 0000000..2ea9014
--- /dev/null
+++ b/res/values-sw/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Usimamizi wa Mazunguzo ya Simu"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Simu"</string>
+    <string name="unknown" msgid="6878797917991465859">"Haijulikani"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Simu isiyojibiwa"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Simu zisizojibiwa"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> simu ambazo hazijajibiwa"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Simu isiyojibiwa kutoka <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Mpigie"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Ujumbe"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Simu imezimwa."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Spika za simu zimewezeshwa"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Siwezi kuongea sasa. Kuna nini?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Nitakupigia sasa hivi."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Nitakupigia baadaye."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Siwezi kuongea sasa. Nipigie baadaye"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Majibu ya haraka"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Hariri majibu ya haraka"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Majibu ya haraka"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Ujumbe uliotumwa kwa <xliff:g id="PHONE_NUMBER">%s</xliff:g> ."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Akaunti za simu"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Ni simu za dharura pekee ndizo zinazoruhusiwa na mmiliki wa kifaa."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Programu hii haiwezi kupiga simu bila ruhusa ya Simu."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Ili upige simu, weka nambari sahihi."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hangout ya video haiwezi kuongezwa kwa wakati huu."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Tafadhali zima Hali ya TTY ili uanzishe Hangout ya video."</string>
+    <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>
+</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
new file mode 100644
index 0000000..a6eca09
--- /dev/null
+++ b/res/values-ta-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ஃபோன் அழைப்பு நிர்வாகம்"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ஃபோன்"</string>
+    <string name="unknown" msgid="6878797917991465859">"தெரியாதவர்"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"தவறிய அழைப்பு"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"தவறிய அழைப்புகள்"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> தவறிய அழைப்புகள்"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> இடமிருந்து தவறிய அழைப்பு"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"அழை"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"செய்தி"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"அழைப்பு முடக்கப்பட்டது."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"ஸ்பீக்கர்ஃபோன் இயக்கப்பட்டது."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"இப்போது பேச முடியாது. ஏதேனும் முக்கிய செய்தியா?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"சிறிதுநேரம் கழித்து நான் அழைக்கிறேன்."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"பிறகு அழைக்கிறேன்."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"இப்போது பேச முடியவில்லை. பிறகு அழைக்க முடியுமா?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"விரைவு பதில்கள்"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"விரைவு பதில்களை மாற்று"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"விரைவு பதில்"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> க்குச் செய்தி அனுப்பப்பட்டது."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"அழைப்புக் கணக்குகள்"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"சாதன உரிமையாளர் அவசர அழைப்புகளை மட்டுமே அனுமதித்துள்ளார்."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ஃபோன் அனுமதியில்லாமல், பயன்பாட்டினால் வெளிச்செல்லும் அழைப்புகளைச் செய்ய முடியாது."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"அழைக்க, சரியான எண்ணை உள்ளிடவும்."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"இப்போது அழைக்க முடியாது."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"வீடியோ அழைப்புகளை மேற்கொள்ள, TTY பயன்முறையை முடக்கவும்."</string>
+    <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>
+</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
new file mode 100644
index 0000000..ccc09e2
--- /dev/null
+++ b/res/values-te-rIN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"ఫోన్ కాల్ నిర్వహణ"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"ఫోన్"</string>
+    <string name="unknown" msgid="6878797917991465859">"తెలియదు"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"సమాధానం ఇవ్వని కాల్"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"సమాధానం ఇవ్వని కాల్‌లు"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> సమాధానం ఇవ్వని కాల్‌లు"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> నుండి సమాధానం ఇవ్వని కాల్"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"కాల్ చేయి"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"సందేశం"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"కాల్ మ్యూట్ చేయబడింది."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"స్పీకర్ ఫోన్ ప్రారంభించబడింది."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ఇప్పుడు మాట్లాడలేను. విషయం ఏమిటి?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"నేను ఇప్పుడే మీకు కాల్ చేస్తాను."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"నేను మీకు తర్వాత కాల్ చేస్తాను."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ఇప్పుడు మాట్లాడలేను. నాకు తర్వాత కాల్ చేస్తారా?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"శీఘ్ర ప్రతిస్పందనలు"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"శీఘ్ర ప్రతిస్పందనల సవరణ"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"శీఘ్ర ప్రతిస్పందన"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>కు సందేశం పంపబడింది."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"కాలింగ్ ఖాతాలు"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"పరికరం యజమాని అత్యవసర కాల్‌లను మాత్రమే అనుమతించారు."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"ఈ అనువర్తనం ఫోన్ అనుమతి లేకుండా అవుట్‌గోయింగ్ కాల్‌లను చేయలేదు."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"కాల్ చేయడానికి, చెల్లుబాటు అయ్యే నంబర్‌ను నమోదు చేయండి."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ఈ సమయంలో కాల్‌ను జోడించడం సాధ్యపడదు."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"దయచేసి వీడియో కాల్‌లు చేయడానికి TTY మోడ్ నిలిపివేయండి."</string>
+    <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>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
new file mode 100644
index 0000000..89dc2bd
--- /dev/null
+++ b/res/values-th/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"การจัดการการโทรศัพท์"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"โทรศัพท์"</string>
+    <string name="unknown" msgid="6878797917991465859">"ไม่ทราบ"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"สายที่ไม่ได้รับ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"สายที่ไม่ได้รับ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> สายที่ไม่ได้รับ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"สายที่ไม่ได้รับจาก <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"โทรกลับ"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"ข้อความ"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"ปิดเสียงการโทร"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"เปิดใช้งานลำโพงแล้ว"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ตอนนี้คุยไม่ได้ มีอะไรหรือเปล่า"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"เดี๋ยวจะโทรกลับทันที"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"เดี๋ยวจะโทรหาทีหลัง"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ตอนนี้คุยไม่ได้ โทรมาใหม่ได้ไหม"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"คำตอบด่วน"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"แก้ไขคำตอบด่วน"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"คำตอบด่วน"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"ส่งข้อความไปยัง <xliff:g id="PHONE_NUMBER">%s</xliff:g> แล้ว"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"บัญชีการโทร"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"เจ้าของอุปกรณ์อนุญาตเฉพาะหมายเลขฉุกเฉิน"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"แอปพลิเคชันนี้ไม่สามารถโทรออกโดยไม่มีสิทธิ์ใช้โทรศัพท์"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"หากต้องการโทรออก โปรดป้อนหมายเลขที่ถูกต้อง"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"ไม่สามารถเพิ่มสายได้ในขณะนี้"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"โปรดปิดใช้โหมด TTY เพื่อแฮงเอาท์วิดีโอ"</string>
+    <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>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
new file mode 100644
index 0000000..5fe5b38
--- /dev/null
+++ b/res/values-tl/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Pamamahala sa Tawag sa Telepono"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telepono"</string>
+    <string name="unknown" msgid="6878797917991465859">"Di-kilala"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Hindi nasagot na tawag"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Mga hindi nasagot na tawag"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> (na) hindi nasagot na tawag"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Hindi nasagot na tawag mula kay <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Tawagan"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Padalhan ng mensahe"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Naka-mute ang tawag."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Pinapagana ang speakerphone."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Di masagot ngayon. Ano\'ng meron?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Tawagan kita ulit."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Tawagan kita mamaya."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Di masagot ngayon. Tawag ka mamaya?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Mga mabilisang tugon"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"I-edit ang mga quick response"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Mabilisang tugon"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Naipadala ang mensahe sa <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Account sa pagtawag"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Mga pang-emergency na tawag lang ang pinapayagan ng may-ari ng device."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Hindi makakapagsagawa ng mga papalabas na tawag ang application na ito nang wala ang pahintulot ng Telepono."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Upang tumawag, maglagay ng wastong numero."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hindi maidadagdag ang tawag sa oras na ito."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Paki-disable ang TTY Mode upang makapag-video call."</string>
+    <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>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
new file mode 100644
index 0000000..f043fbb
--- /dev/null
+++ b/res/values-tr/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefon Çağrısı Yönetimi"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Bilinmiyor"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Cevapsız çağrı"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Cevapsız çağrılar"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> cevapsız çağrı"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Cevapsız çağrı: <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Geri ara"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Mesaj gönder"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Çağrı sesi kapatıldı."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Hoparlör etkin."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Şimdi konuşamam. Konu nedir?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Seni hemen geri arayacağım."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Seni daha sonra ararım."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Şimdi konuşamam. Daha sonra arar mısın?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Hızlı yanıtlar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Hızlı yanıtları düzenle"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Hızlı yanıt"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Mesaj, <xliff:g id="PHONE_NUMBER">%s</xliff:g> numaralı telefona gönderildi."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Çağrı hesapları"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Cihaz sahibi sadece acil durum çağrılarına izin veriyor."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Bu uygulama, Telefonun izni olmadan giden çağrılar yapamaz."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Telefon etmek için geçerli bir numara girin."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Çağrı şu anda eklenemiyor."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Video görüşmesi yapmak için lütfen TTY Modu\'nu devre dışı bırakın."</string>
+    <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>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
new file mode 100644
index 0000000..909563b
--- /dev/null
+++ b/res/values-uk/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Керування дзвінками"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Телефон"</string>
+    <string name="unknown" msgid="6878797917991465859">"Невідомий"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропущений виклик"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропущ. дзвінки"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Пропущ. дзвінк: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Пропущ. виклик від <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Передзвонити"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Повідомлення"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Звук виклику вимкнено."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Гучний зв’язок увімкнено."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Не можу говорити. У чому справа?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Я зараз передзвоню."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Я передзвоню пізніше."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Не можу говорити. Передзвоніть."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Швидкі відповіді"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Редагувати швидкі відповіді"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Швидка відповідь"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Повідомлення надіслано на номер <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Облікові записи для дзвінків"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Власник пристрою дозволив лише екстрені виклики."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Цей додаток не може телефонувати без відповідного дозволу."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Щоб зателефонувати, введіть дійсний номер."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Зараз не можна почати дзвінок."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Щоб здійснювати відеодзвінки, вимкніть режим TTY."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Відстуній номер голосової пошти"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карті немає збереж. номерів голос. пошти."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Додати номер"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Змінити додаток для дзвінків за умовчанням?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Зробити <xliff:g id="NEW_APP">%1$s</xliff:g> додатком для дзвінків за умовчанням замість додатка <xliff:g id="CURRENT_APP">%2$s</xliff:g>?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Зробити <xliff:g id="NEW_APP">%s</xliff:g> додатком для дзвінків за умовчанням?"</string>
+</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
new file mode 100644
index 0000000..b77a05c
--- /dev/null
+++ b/res/values-ur-rPK/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"فون کال کا نظم"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"فون"</string>
+    <string name="unknown" msgid="6878797917991465859">"نامعلوم"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"چھوٹی ہوئی کال"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"چھوٹی ہوئی کالیں"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> چھوٹی ہوئی کالیں"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> کی جانب سے چھوٹی ہوئی کال"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"واپس کال کریں"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"پیغام"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"کال خاموش کر دی گئی۔"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"اسپیکر فون فعال ہوگیا۔"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"ابھی بات نہیں کرسکتے۔ کیا ہو رہا ہے؟"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"میں ابھی آپ کو واپسی کال کروں گا۔"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"میں آپ کو بعد میں کال کروں گا۔"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"ابھی بات نہیں کرسکتے۔ مجھے بعد میں کال کریں؟"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"فوری جوابات"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"فوری جوابات میں ترمیم کریں"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"فوری جواب"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"پیغام <xliff:g id="PHONE_NUMBER">%s</xliff:g> کو بھیج دیا گیا۔"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"کالنگ اکاؤنٹس"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"آلہ کے مالک نے صرف ہنگامی کالز کی اجازت دی ہے۔"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"یہ ایپلی کیشن فون کی اجازت کے بغیر باہر جانے والی کالیں نہیں کر سکتی۔"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"کال کرنے کیلئے، ایک درست نمبر درج کریں۔"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"اس وقت کال شامل نہیں کی جا سکتی ہے۔"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"‏براہ کرم ویڈیو کالز کرنے کیلئے TTY وض‏ع غیر فعال کریں۔"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"صوتی میل نمبر درج نہیں ہے"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"‏SIM کارڈ پر کوئی بھی صوتی میل نمبر اسٹور نہیں ہے۔"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"نمبر شامل کریں"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"ڈیفالٹ ڈائلر ایپ تبدیل کریں"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"<xliff:g id="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>
+</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
new file mode 100644
index 0000000..53f8704
--- /dev/null
+++ b/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Telefon – qo‘ng‘iroqlarni boshqarish"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Noma’lum"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Javobsiz qo‘ng‘iroq"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Javobsiz qo‘ng‘iroqlar"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ta javobsiz qo‘ng‘iroq"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g> qo‘ng‘irog‘i javobsiz qoldirildi"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Telefon"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"SMS"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Qo‘ng‘iroq ovozi o‘chirildi."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Karnaychalar yoqildi."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Hozir gaplasholmayman. Tinchlikmi?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Hozir telefon qilaman."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Keyinroq telefon qilaman."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Bandman, keyinroq telefon qiling."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Tezkor javoblar"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Tezkor javoblar"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Tezkor javob"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Xabar <xliff:g id="PHONE_NUMBER">%s</xliff:g>ga jo‘natildi."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Qo‘ng‘iroq hisoblari"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Qurilma egasi faqat favqulodda qo‘ng‘iroqlarga ruxsat bergan."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Bu ilova Telefon ruxsatnomasisiz chiquvchi qo‘ng‘iroqlarni amalga oshira olmaydi."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Qo‘ng‘iroq qilish uchun raqamni to‘g‘ri kiriting."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Hozirgi vaqtda qo‘ng‘iroq qo‘shib bo‘lmaydi."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Video qo\'ng\'iroqlarni amalga oshirish uchun TTY rejimini o‘chirib qo‘yish kerak"</string>
+    <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>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
new file mode 100644
index 0000000..29f4eee
--- /dev/null
+++ b/res/values-vi/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Quản lý cuộc gọi điện thoại"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Điện thoại"</string>
+    <string name="unknown" msgid="6878797917991465859">"Không xác định"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Cuộc gọi nhỡ"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Cuộc gọi nhỡ"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> cuộc gọi nhỡ"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Cuộc gọi nhỡ từ <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Gọi lại"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Tin nhắn"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Đã tắt tiếng cuộc gọi."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Đã bật loa ngoài."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Giờ tôi ko thể nói chuyện. Gì vậy?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Tôi sẽ gọi lại ngay."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Tôi sẽ gọi lại sau."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Giờ tôi ko thể nói chuyện. Gọi sau nhé?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Trả lời nhanh"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Chỉnh sửa trả lời nhanh"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Trả lời nhanh"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Đã gửi tin nhắn tới <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Tài khoản gọi"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Chỉ chủ sở hữu thiết bị mới được phép thực hiện cuộc gọi khẩn cấp."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ứng dụng này không thể thực hiện cuộc gọi đi mà không có quyền của Điện thoại."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Để thực hiện cuộc gọi, hãy nhập một số hợp lệ."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Không thể thêm cuộc gọi tại thời điểm này."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Vui lòng tắt Chế độ TTY để thực hiện cuộc gọi điện video."</string>
+    <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>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..cdb80cc
--- /dev/null
+++ b/res/values-zh-rCN/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"通话管理"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"电话"</string>
+    <string name="unknown" msgid="6878797917991465859">"未知"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"未接电话"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"未接电话"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> 个未接电话"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"来自<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>的未接电话"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"回拨"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"短信"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"通话已静音。"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"扬声器已启用。"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"现在无法接听。有什么事吗?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"我马上会打给你。"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"我稍后会再打给你。"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"现在无法接听。能稍后再打给我吗?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"快速回复"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"修改快速回复"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回复"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"讯息已发送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"通话帐户"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"设备机主仅允许拨打紧急呼救电话。"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"此应用没有电话权限,无法拨出电话。"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"要拨打电话,请输入有效的电话号码。"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"目前无法添加通话。"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"要进行视频通话,请停用 TTY 模式。"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"缺少语音信箱号码"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM卡上未存储语音信箱号码。"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"添加号码"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"要更改默认拨号器应用吗?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"要使用<xliff:g id="NEW_APP">%1$s</xliff:g>(而非<xliff:g id="CURRENT_APP">%2$s</xliff:g>)作为您的默认拨号器应用吗?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"要使用<xliff:g id="NEW_APP">%s</xliff:g>作为您的默认拨号器应用吗?"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..7be47a1
--- /dev/null
+++ b/res/values-zh-rHK/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"手機通話管理"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"電話"</string>
+    <string name="unknown" msgid="6878797917991465859">"未知"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"未接來電"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"未接來電"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> 未接電話"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>打來的未接來電"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"回撥"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"短訊"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"通話已靜音。"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"擴音器已啟用"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"我現在不方便通話,有什麼事?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"我待會就打電話給你。"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"我晚點打電話給你。"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"我現在不方便通話,晚點再打來好嗎?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"快速回應"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"編輯快速回應"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回應"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"訊息已傳送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"通話帳戶"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"只有裝置擁有者才可撥打緊急電話。"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"此應用程式沒有電話權限,無法撥出電話。"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"要撥打電話,請輸入有效的號碼。"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"目前無法新增視像通話。"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"請停用 TTY 模式以進行視像通話。"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"未填留言信箱號碼"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 卡中沒有儲存任何留言信箱號碼。"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"新增電話號碼"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"變更預設撥號器應用程式?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"使用 <xliff:g id="NEW_APP">%1$s</xliff:g> 取代 <xliff:g id="CURRENT_APP">%2$s</xliff:g> 作為預設撥號器應用程式?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"使用 <xliff:g id="NEW_APP">%s</xliff:g> 為預設撥號器應用程式?"</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..fb8ac7f
--- /dev/null
+++ b/res/values-zh-rTW/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"通話管理"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"電話"</string>
+    <string name="unknown" msgid="6878797917991465859">"不明"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"未接來電"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"未接來電"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> 通未接來電"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"來自 <xliff:g id="MISSED_CALL_FROM">%s</xliff:g> 的未接來電"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"回撥"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"簡訊"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"通話已靜音。"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"喇叭已啟用"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"我現在不方便通話,有什麼事?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"我待會就回電。"</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"我晚點回電。"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"我現在不方便通話,晚點再打來好嗎?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"快速回應"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"編輯快速回應"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"快速回應"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"訊息已傳送至 <xliff:g id="PHONE_NUMBER">%s</xliff:g>。"</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"通話帳戶"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"裝置擁有者限定只能撥打緊急電話。"</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"這個應用程式不具備電話應用程式存取權限,無法撥出電話。"</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"如要撥打電話,請輸入有效的號碼。"</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"目前無法新增通話。"</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"如要進行視訊通話,請停用 TTY 模式。"</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"遺失語音信箱號碼"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 卡中未儲存語音信箱號碼。"</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"新增號碼"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"要變更預設撥號應用程式嗎?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"要將 <xliff:g id="NEW_APP">%1$s</xliff:g> (而非 <xliff:g id="CURRENT_APP">%2$s</xliff:g>) 設為預設撥號應用程式嗎?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"要將 <xliff:g id="NEW_APP">%s</xliff:g> 設為預設撥號應用程式嗎?"</string>
+</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
new file mode 100644
index 0000000..3fb5b0c
--- /dev/null
+++ b/res/values-zu/strings.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Ukuphathwa kwekholi yefoni"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Ifoni"</string>
+    <string name="unknown" msgid="6878797917991465859">"Akwaziwa"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Ikholi ekulahlekele"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Amakholi akuphuthele"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> amakholi akulahlekele"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Uphuthelwe ikholi ephuma ku-<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Phinda ushaye"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Umlayezo"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Ikholu ithulisiwe"</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Isipikha sefoni sinikwe amandla"</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Angikwazi ukukhuluma okwamanje. Kwenzenjani?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">" Ngizophinde ngikushayele ucingo."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Ngizokushayela ucingo emva kwesikhathi"</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Angikwazi ukukhuluma okwamanje. Ngicela uphinde ungishayele ucingo kamuva?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Izimpendulo ezisheshayo"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Hlela izimpendulo ezisheshayo"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Izimpendulo ezisheshayo"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Umlayezo othunyelwe ku <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Ama-akhawunti wokushaya"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="8504993498756056279">"Amakholi aphuthumayo kuphela avunyelwe ngumnikazi wedivayisi."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Lolu hlelo lokusebenza alikwazi ukwenza amakhli aphumayo ngaphandle kwemvume yefoni."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Ukuze wenze ikholi, faka inombolo evumelekile."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Ikholi ayikwazi ukungezwa ngalesi sikhathi."</string>
+    <string name="video_call_not_allowed_if_tty_enabled" msgid="7593649283571253283">"Sicela ukhubaze imodi ye-TTY ukuze wenze amakholi wevidiyo."</string>
+    <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>
+</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 6c6f215..365e758 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -38,9 +38,4 @@
 
     <!-- Flag indicating if the tty is enabled -->
     <bool name="tty_enabled">false</bool>
-
-    <!-- ComponentName for the default connection manager component. If this cannot be resolved, or
-         if this package has not registered any accounts, then it will be ignored.
-         [DO NOT TRANSLATE] -->
-    <string name="default_connection_manager_component" translatable="false"></string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 37e59c0..26df574 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -18,7 +18,11 @@
     <!-- Official label of the Telecomm/Phone app, as seen in "Manage Applications"
          and other settings UIs. This is the "app name" used in notification, recents,
          and app info screens. -->
-    <string name="telecommAppLabel" product="default">Phone</string>
+    <string name="telecommAppLabel" product="default">Phone Call Management</string>
+
+    <!-- Title used for the activity for placing a call. This name appears
+         in activity disambig dialogs -->
+    <string name="userCallActivityLabel" product="default">Phone</string>
 
     <!-- Name for an "unknown" caller. -->
     <string name="unknown">Unknown</string>
@@ -35,11 +39,11 @@
     <string name="notification_missedCallTicker">Missed call from <xliff:g id="missed_call_from">%s</xliff:g></string>
     <!-- Message for "call back" Action, which is displayed in the missed call notificaiton.
          The user will be able to call back to the person or the phone number.
-         [CHAR LIMIT=60] -->
+         [CHAR LIMIT=18] -->
     <string name="notification_missedCall_call_back">Call back</string>
     <!-- Message for "reply via sms" action, which is displayed in the missed call notification.
          The user will be able to send text messages using the phone number.
-         [CHAR LIMIT=60] -->
+         [CHAR LIMIT=18] -->
     <string name="notification_missedCall_message">Message</string>
 
     <!-- Content description of the call muted notification icon for
@@ -73,9 +77,19 @@
         a text response. [CHAR LIMIT=40] -->
     <string name="respond_via_sms_confirmation_format">Message sent to <xliff:g id="phone_number">%s</xliff:g>.</string>
 
+    <!-- Title of settings screen that allows user to enable and disable phone-accounts.
+         Each method for placing a call (SIM1, SIM2, SIP account, etc) has a phone-account.
+         Phone-accounts that are created by third party apps can be disabled and enabled by user.
+         [CHAR LIMIT=30] -->
+    <string name="enable_account_preference_title">Calling accounts</string>
+
     <!-- Message indicating that the user is not allowed to make non-emergency outgoing phone calls
          due to a user restriction -->
-    <string name="outgoing_call_not_allowed">Only emergency calls are allowed by the device owner</string>
+    <string name="outgoing_call_not_allowed_user_restriction">Only emergency calls are allowed by the device owner.</string>
+
+    <!-- Message indicating that the user is not allowed to make non-emergency outgoing phone calls
+         due to the lack of the CALL_PHONE permission -->
+    <string name="outgoing_call_not_allowed_no_permission">This application cannot make outgoing calls without the Phone permission.</string>
 
     <!-- Call failure message displayed in an error dialog used to indicate that a phone number was not provided -->
     <string name="outgoing_call_error_no_phone_number_supplied">To place a call, enter a valid number.</string>
@@ -83,6 +97,9 @@
     <!-- Message shown when the user tries to make a video call when already in a video call. -->
     <string name ="duplicate_video_call_not_allowed">Call cannot be added at this time.</string>
 
+    <!-- Message indicating video calls not allowed if user enabled TTY Mode -->
+    <string name="video_call_not_allowed_if_tty_enabled">Please disable TTY Mode to make video calls.</string>
+
     <!-- missing voicemail number -->
     <!-- Title of the "Missing voicemail number" dialog -->
     <string name="no_vm_number">Missing voicemail number</string>
@@ -91,6 +108,15 @@
     <!-- Button label on the "Missing voicemail number" dialog -->
     <string name="add_vm_number_str">Add number</string>
 
+    <!-- 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>
+
+
     <!-- DO NOT TRANSLATE. Label for test Subscription 0. -->
     <string name="test_account_0_label">Q Mobile</string>
     <!-- DO NOT TRANSLATE. Label for test Subscription 1. -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f073906..d846cda 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -48,6 +48,6 @@
 
     <style name="TelecomDialerSettingsActionOverflowButtonStyle"
             parent="@android:style/Widget.Material.Light.ActionButton.Overflow">
-        <item name="android:src">@drawable/ic_more_vert_white_24dp</item>
+        <item name="android:src">@drawable/ic_more_vert_24dp</item>
     </style>
 </resources>
diff --git a/res/xml/enable_account_preference.xml b/res/xml/enable_account_preference.xml
new file mode 100644
index 0000000..aa9a9c9
--- /dev/null
+++ b/res/xml/enable_account_preference.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Settings screen that lets the user enable and disable registered phone accounts.
+     See EnableAccountPreferenceFragment.java -->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+        android:title="@string/enable_account_preference_title">
+    <!-- content created dynamically. -->
+</PreferenceScreen>
diff --git a/res/xml/respond_via_sms_settings.xml b/res/xml/respond_via_sms_settings.xml
index 7f79a5c..3c658ef 100644
--- a/res/xml/respond_via_sms_settings.xml
+++ b/res/xml/respond_via_sms_settings.xml
@@ -35,24 +35,32 @@
          EditTextPreference here, to allow the preference "title" to wrap
          onto multiple lines if the customized messages are long enough. -->
 
+    <!-- These preferences are not persisted, so that they will update
+         when the localization is changed. RespondViaSmsSettings handles
+         the logic of storing user-specified preference changes. -->
+
     <com.android.server.telecom.MultiLineTitleEditTextPreference
         android:key="canned_response_pref_1"
         android:defaultValue="@string/respond_via_sms_canned_response_1"
-        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title" />
+        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title"
+        android:persistent="false" />
 
     <com.android.server.telecom.MultiLineTitleEditTextPreference
         android:key="canned_response_pref_2"
         android:defaultValue="@string/respond_via_sms_canned_response_2"
-        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title" />
+        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title"
+        android:persistent="false" />
 
     <com.android.server.telecom.MultiLineTitleEditTextPreference
         android:key="canned_response_pref_3"
         android:defaultValue="@string/respond_via_sms_canned_response_3"
-        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title" />
+        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title"
+        android:persistent="false" />
 
     <com.android.server.telecom.MultiLineTitleEditTextPreference
         android:key="canned_response_pref_4"
         android:defaultValue="@string/respond_via_sms_canned_response_4"
-        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title" />
+        android:dialogTitle="@string/respond_via_sms_edittext_dialog_title"
+        android:persistent="false" />
 
 </PreferenceScreen>
diff --git a/src/com/android/server/telecom/BluetoothManager.java b/src/com/android/server/telecom/BluetoothManager.java
index f74349f..aec0d3e 100644
--- a/src/com/android/server/telecom/BluetoothManager.java
+++ b/src/com/android/server/telecom/BluetoothManager.java
@@ -42,11 +42,14 @@
                 public void onServiceConnected(int profile, BluetoothProfile proxy) {
                     mBluetoothHeadset = (BluetoothHeadset) proxy;
                     Log.v(this, "- Got BluetoothHeadset: " + mBluetoothHeadset);
+                    updateBluetoothState();
                 }
 
                 @Override
                 public void onServiceDisconnected(int profile) {
                     mBluetoothHeadset = null;
+                    Log.v(this, "Lost BluetoothHeadset: " + mBluetoothHeadset);
+                    updateBluetoothState();
                 }
            };
 
diff --git a/src/com/android/server/telecom/BluetoothPhoneService.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
similarity index 65%
rename from src/com/android/server/telecom/BluetoothPhoneService.java
rename to src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
index 9a0cae1..9deffbe 100644
--- a/src/com/android/server/telecom/BluetoothPhoneService.java
+++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
@@ -16,7 +16,6 @@
 
 package com.android.server.telecom;
 
-import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
@@ -26,12 +25,9 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
-import android.os.Handler;
+import android.os.Binder;
 import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
-import android.telecom.CallState;
 import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
@@ -49,38 +45,10 @@
  * Bluetooth headset manager for Telecom. This class shares the call state with the bluetooth device
  * and accepts call-related commands to perform on behalf of the BT device.
  */
-public final class BluetoothPhoneService extends Service {
-    /**
-     * Request object for performing synchronous requests to the main thread.
-     */
-    private static class MainThreadRequest {
-        private static final Object RESULT_NOT_SET = new Object();
-        Object result = RESULT_NOT_SET;
-        int param;
-
-        MainThreadRequest(int param) {
-            this.param = param;
-        }
-
-        void setResult(Object value) {
-            result = value;
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-    }
+public final class BluetoothPhoneServiceImpl {
 
     private static final String TAG = "BluetoothPhoneService";
 
-    private static final int MSG_ANSWER_CALL = 1;
-    private static final int MSG_HANGUP_CALL = 2;
-    private static final int MSG_SEND_DTMF = 3;
-    private static final int MSG_PROCESS_CHLD = 4;
-    private static final int MSG_GET_NETWORK_OPERATOR = 5;
-    private static final int MSG_LIST_CURRENT_CALLS = 6;
-    private static final int MSG_QUERY_PHONE_STATE = 7;
-    private static final int MSG_GET_SUBSCRIBER_NUMBER = 8;
-
     // match up with bthf_call_state_t of bt_hf.h
     private static final int CALL_STATE_ACTIVE = 0;
     private static final int CALL_STATE_HELD = 1;
@@ -114,206 +82,192 @@
     private final IBluetoothHeadsetPhone.Stub mBinder = new IBluetoothHeadsetPhone.Stub() {
         @Override
         public boolean answerCall() throws RemoteException {
-            enforceModifyPermission();
-            Log.i(TAG, "BT - answering call");
-            return sendSynchronousRequest(MSG_ANSWER_CALL);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "BT - answering call");
+                    Call call = mCallsManager.getRingingCall();
+                    if (call != null) {
+                        mCallsManager.answerCall(call, call.getVideoState());
+                        return true;
+                    }
+                    return false;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+
+            }
         }
 
         @Override
         public boolean hangupCall() throws RemoteException {
-            enforceModifyPermission();
-            Log.i(TAG, "BT - hanging up call");
-            return sendSynchronousRequest(MSG_HANGUP_CALL);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "BT - hanging up call");
+                    Call call = mCallsManager.getForegroundCall();
+                    if (call != null) {
+                        mCallsManager.disconnectCall(call);
+                        return true;
+                    }
+                    return false;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public boolean sendDtmf(int dtmf) throws RemoteException {
-            enforceModifyPermission();
-            Log.i(TAG, "BT - sendDtmf %c", Log.DEBUG ? dtmf : '.');
-            return sendSynchronousRequest(MSG_SEND_DTMF, dtmf);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "BT - sendDtmf %c", Log.DEBUG ? dtmf : '.');
+                    Call call = mCallsManager.getForegroundCall();
+                    if (call != null) {
+                        // TODO: Consider making this a queue instead of starting/stopping
+                        // in quick succession.
+                        mCallsManager.playDtmfTone(call, (char) dtmf);
+                        mCallsManager.stopDtmfTone(call);
+                        return true;
+                    }
+                    return false;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public String getNetworkOperator() throws RemoteException {
-            Log.i(TAG, "getNetworkOperator");
-            enforceModifyPermission();
-            return sendSynchronousRequest(MSG_GET_NETWORK_OPERATOR);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "getNetworkOperator");
+                    PhoneAccount account = getBestPhoneAccount();
+                    if (account != null) {
+                        return account.getLabel().toString();
+                    } else {
+                        // Finally, just get the network name from telephony.
+                        return TelephonyManager.from(mContext)
+                                .getNetworkOperatorName();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public String getSubscriberNumber() throws RemoteException {
-            Log.i(TAG, "getSubscriberNumber");
-            enforceModifyPermission();
-            return sendSynchronousRequest(MSG_GET_SUBSCRIBER_NUMBER);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "getSubscriberNumber");
+                    String address = null;
+                    PhoneAccount account = getBestPhoneAccount();
+                    if (account != null) {
+                        Uri addressUri = account.getAddress();
+                        if (addressUri != null) {
+                            address = addressUri.getSchemeSpecificPart();
+                        }
+                    }
+                    if (TextUtils.isEmpty(address)) {
+                        address = TelephonyManager.from(mContext).getLine1Number();
+                        if (address == null) address = "";
+                    }
+                    return address;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public boolean listCurrentCalls() throws RemoteException {
-            // only log if it is after we recently updated the headset state or else it can clog
-            // the android log since this can be queried every second.
-            boolean logQuery = mHeadsetUpdatedRecently;
-            mHeadsetUpdatedRecently = false;
+            synchronized (mLock) {
+                enforceModifyPermission();
 
-            if (logQuery) {
-                Log.i(TAG, "listcurrentCalls");
+                long token = Binder.clearCallingIdentity();
+                try {
+                    // only log if it is after we recently updated the headset state or else it can
+                    // clog the android log since this can be queried every second.
+                    boolean logQuery = mHeadsetUpdatedRecently;
+                    mHeadsetUpdatedRecently = false;
+
+                    if (logQuery) {
+                        Log.i(TAG, "listcurrentCalls");
+                    }
+
+                    sendListOfCalls(logQuery);
+                    return true;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             }
-            enforceModifyPermission();
-            return sendSynchronousRequest(MSG_LIST_CURRENT_CALLS, logQuery ? 1 : 0);
         }
 
         @Override
         public boolean queryPhoneState() throws RemoteException {
-            Log.i(TAG, "queryPhoneState");
-            enforceModifyPermission();
-            return sendSynchronousRequest(MSG_QUERY_PHONE_STATE);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "queryPhoneState");
+                    updateHeadsetWithCallState(true /* force */);
+                    return true;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public boolean processChld(int chld) throws RemoteException {
-            Log.i(TAG, "processChld %d", chld);
-            enforceModifyPermission();
-            return sendSynchronousRequest(MSG_PROCESS_CHLD, chld);
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(TAG, "processChld %d", chld);
+                    return BluetoothPhoneServiceImpl.this.processChld(chld);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         }
 
         @Override
         public void updateBtHandsfreeAfterRadioTechnologyChange() throws RemoteException {
-            Log.d(TAG, "RAT change");
+            Log.d(TAG, "RAT change - deprecated");
             // deprecated
         }
 
         @Override
         public void cdmaSetSecondCallState(boolean state) throws RemoteException {
-            Log.d(TAG, "cdma 1");
+            Log.d(TAG, "cdma 1 - deprecated");
             // deprecated
         }
 
         @Override
         public void cdmaSwapSecondCallState() throws RemoteException {
-            Log.d(TAG, "cdma 2");
+            Log.d(TAG, "cdma 2 - deprecated");
             // deprecated
         }
     };
 
     /**
-     * Main-thread handler for BT commands.  Since telecom logic runs on a single thread, commands
-     * that are sent to it from the headset need to be moved over to the main thread before
-     * executing. This handler exists for that reason.
-     */
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            MainThreadRequest request = msg.obj instanceof MainThreadRequest ?
-                    (MainThreadRequest) msg.obj : null;
-            CallsManager callsManager = getCallsManager();
-            Call call = null;
-
-            Log.d(TAG, "handleMessage(%d) w/ param %s",
-                    msg.what, request == null ? null : request.param);
-
-            switch (msg.what) {
-                case MSG_ANSWER_CALL:
-                    try {
-                        call = callsManager.getRingingCall();
-                        if (call != null) {
-                            getCallsManager().answerCall(call, 0);
-                        }
-                    } finally {
-                        request.setResult(call != null);
-                    }
-                    break;
-
-                case MSG_HANGUP_CALL:
-                    try {
-                        call = callsManager.getForegroundCall();
-                        if (call != null) {
-                            callsManager.disconnectCall(call);
-                        }
-                    } finally {
-                        request.setResult(call != null);
-                    }
-                    break;
-
-                case MSG_SEND_DTMF:
-                    try {
-                        call = callsManager.getForegroundCall();
-                        if (call != null) {
-                            // TODO: Consider making this a queue instead of starting/stopping
-                            // in quick succession.
-                            callsManager.playDtmfTone(call, (char) request.param);
-                            callsManager.stopDtmfTone(call);
-                        }
-                    } finally {
-                        request.setResult(call != null);
-                    }
-                    break;
-
-                case MSG_PROCESS_CHLD:
-                    Boolean result = false;
-                    try {
-                        result = processChld(request.param);
-                    } finally {
-                        request.setResult(result);
-                    }
-                    break;
-
-                case MSG_GET_SUBSCRIBER_NUMBER:
-                    String address = null;
-                    try {
-                        PhoneAccount account = getBestPhoneAccount();
-                        if (account != null) {
-                            Uri addressUri = account.getAddress();
-                            if (addressUri != null) {
-                                address = addressUri.getSchemeSpecificPart();
-                            }
-                        }
-
-                        if (TextUtils.isEmpty(address)) {
-                            address = TelephonyManager.from(BluetoothPhoneService.this)
-                                    .getLine1Number();
-                        }
-                    } finally {
-                        request.setResult(address);
-                    }
-                    break;
-
-                case MSG_GET_NETWORK_OPERATOR:
-                    String label = null;
-                    try {
-                        PhoneAccount account = getBestPhoneAccount();
-                        if (account != null) {
-                            label = account.getLabel().toString();
-                        } else {
-                            // Finally, just get the network name from telephony.
-                            label = TelephonyManager.from(BluetoothPhoneService.this)
-                                    .getNetworkOperatorName();
-                        }
-                    } finally {
-                        request.setResult(label);
-                    }
-                    break;
-
-                case MSG_LIST_CURRENT_CALLS:
-                    try {
-                        sendListOfCalls(request.param == 1);
-                    } finally {
-                        request.setResult(true);
-                    }
-                    break;
-
-                case MSG_QUERY_PHONE_STATE:
-                    try {
-                        updateHeadsetWithCallState(true /* force */);
-                    } finally {
-                        if (request != null) {
-                            request.setResult(true);
-                        }
-                    }
-                    break;
-            }
-        }
-    };
-
-    /**
      * Listens to call changes from the CallsManager and calls into methods to update the bluetooth
      * headset with the new states.
      */
@@ -337,7 +291,7 @@
             // When the call later transitions to DIALING/DISCONNECTED we will then send out the
             // aggregated update.
             if (oldState == CallState.ACTIVE && newState == CallState.ON_HOLD) {
-                for (Call otherCall : CallsManager.getInstance().getCalls()) {
+                for (Call otherCall : mCallsManager.getCalls()) {
                     if (otherCall.getState() == CallState.CONNECTING) {
                         return;
                     }
@@ -347,7 +301,7 @@
             // To have an active call and another dialing at the same time is an invalid BT
             // state. We can assume that the active call will be automatically held which will
             // send another update at which point we will be in the right state.
-            if (CallsManager.getInstance().getActiveCall() != null
+            if (mCallsManager.getActiveCall() != null
                     && oldState == CallState.CONNECTING && newState == CallState.DIALING) {
                 return;
             }
@@ -400,12 +354,16 @@
             new BluetoothProfile.ServiceListener() {
         @Override
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            mBluetoothHeadset = (BluetoothHeadset) proxy;
+            synchronized (mLock) {
+                mBluetoothHeadset = (BluetoothHeadset) proxy;
+            }
         }
 
         @Override
         public void onServiceDisconnected(int profile) {
-            mBluetoothHeadset = null;
+            synchronized (mLock) {
+                mBluetoothHeadset = null;
+            }
         }
     };
 
@@ -415,10 +373,17 @@
     private final BroadcastReceiver mBluetoothAdapterReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
-            Log.d(TAG, "Bluetooth Adapter state: %d", state);
-            if (state == BluetoothAdapter.STATE_ON) {
-                mHandler.sendEmptyMessage(MSG_QUERY_PHONE_STATE);
+            synchronized (mLock) {
+                int state = intent
+                        .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+                Log.d(TAG, "Bluetooth Adapter state: %d", state);
+                if (state == BluetoothAdapter.STATE_ON) {
+                    try {
+                        mBinder.queryPhoneState();
+                    } catch (RemoteException e) {
+                        // Remote exception not expected
+                    }
+                }
             }
         }
     };
@@ -431,88 +396,83 @@
 
     private boolean mHeadsetUpdatedRecently = false;
 
-    public BluetoothPhoneService() {
-        Log.v(TAG, "Constructor");
-    }
+    private final Context mContext;
+    private final TelecomSystem.SyncRoot mLock;
+    private final CallsManager mCallsManager;
+    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
 
-    public static final void start(Context context) {
-        if (BluetoothAdapter.getDefaultAdapter() != null) {
-            context.startService(new Intent(context, BluetoothPhoneService.class));
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        Log.d(TAG, "Binding service");
+    public IBinder getBinder() {
         return mBinder;
     }
 
-    @Override
-    public void onCreate() {
-        Log.d(TAG, "onCreate");
+    public BluetoothPhoneServiceImpl(
+            Context context,
+            TelecomSystem.SyncRoot lock,
+            CallsManager callsManager,
+            PhoneAccountRegistrar phoneAccountRegistrar) {
+        Log.d(this, "onCreate");
+
+        mContext = context;
+        mLock = lock;
+        mCallsManager = callsManager;
+        mPhoneAccountRegistrar = phoneAccountRegistrar;
 
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         if (mBluetoothAdapter == null) {
-            Log.d(TAG, "BluetoothPhoneService shutting down, no BT Adapter found.");
+            Log.d(this, "BluetoothPhoneService shutting down, no BT Adapter found.");
             return;
         }
-        mBluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET);
+        mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
 
         IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        registerReceiver(mBluetoothAdapterReceiver, intentFilter);
+        context.registerReceiver(mBluetoothAdapterReceiver, intentFilter);
 
-        CallsManager.getInstance().addListener(mCallsManagerListener);
+        mCallsManager.addListener(mCallsManagerListener);
         updateHeadsetWithCallState(false /* force */);
     }
 
-    @Override
-    public void onDestroy() {
-        Log.d(TAG, "onDestroy");
-        CallsManager.getInstance().removeListener(mCallsManagerListener);
-        super.onDestroy();
-    }
-
     private boolean processChld(int chld) {
-        CallsManager callsManager = CallsManager.getInstance();
-        Call activeCall = callsManager.getActiveCall();
-        Call ringingCall = callsManager.getRingingCall();
-        Call heldCall = callsManager.getHeldCall();
+        Call activeCall = mCallsManager.getActiveCall();
+        Call ringingCall = mCallsManager.getRingingCall();
+        Call heldCall = mCallsManager.getHeldCall();
 
         // TODO: Keeping as Log.i for now.  Move to Log.d after L release if BT proves stable.
         Log.i(TAG, "Active: %s\nRinging: %s\nHeld: %s", activeCall, ringingCall, heldCall);
 
         if (chld == CHLD_TYPE_RELEASEHELD) {
             if (ringingCall != null) {
-                callsManager.rejectCall(ringingCall, false, null);
+                mCallsManager.rejectCall(ringingCall, false, null);
                 return true;
             } else if (heldCall != null) {
-                callsManager.disconnectCall(heldCall);
+                mCallsManager.disconnectCall(heldCall);
                 return true;
             }
         } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) {
             if (activeCall != null) {
-                callsManager.disconnectCall(activeCall);
+                mCallsManager.disconnectCall(activeCall);
                 if (ringingCall != null) {
-                    callsManager.answerCall(ringingCall, 0);
+                    mCallsManager.answerCall(ringingCall, ringingCall.getVideoState());
                 } else if (heldCall != null) {
-                    callsManager.unholdCall(heldCall);
+                    mCallsManager.unholdCall(heldCall);
                 }
                 return true;
             }
         } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) {
             if (activeCall != null && activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
                 activeCall.swapConference();
+                Log.i(TAG, "CDMA calls in conference swapped, updating headset");
+                updateHeadsetWithCallState(true /* force */);
                 return true;
             } else if (ringingCall != null) {
-                callsManager.answerCall(ringingCall, 0);
+                mCallsManager.answerCall(ringingCall, ringingCall.getVideoState());
                 return true;
             } else if (heldCall != null) {
                 // CallsManager will hold any active calls when unhold() is called on a
                 // currently-held call.
-                callsManager.unholdCall(heldCall);
+                mCallsManager.unholdCall(heldCall);
                 return true;
             } else if (activeCall != null && activeCall.can(Connection.CAPABILITY_HOLD)) {
-                callsManager.holdCall(activeCall);
+                mCallsManager.holdCall(activeCall);
                 return true;
             }
         } else if (chld == CHLD_TYPE_ADDHELDTOCONF) {
@@ -523,7 +483,7 @@
                 } else {
                     List<Call> conferenceable = activeCall.getConferenceableCalls();
                     if (!conferenceable.isEmpty()) {
-                        callsManager.conference(activeCall, conferenceable.get(0));
+                        mCallsManager.conference(activeCall, conferenceable.get(0));
                         return true;
                    }
                 }
@@ -533,43 +493,19 @@
     }
 
     private void enforceModifyPermission() {
-        enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
-    }
-
-    private <T> T sendSynchronousRequest(int message) {
-        return sendSynchronousRequest(message, 0);
-    }
-
-    private <T> T sendSynchronousRequest(int message, int param) {
-        if (Looper.myLooper() == mHandler.getLooper()) {
-            Log.w(TAG, "This method will deadlock if called from the main thread.");
-        }
-
-        MainThreadRequest request = new MainThreadRequest(param);
-        mHandler.obtainMessage(message, request).sendToTarget();
-        synchronized (request) {
-            while (request.result == MainThreadRequest.RESULT_NOT_SET) {
-                try {
-                    request.wait();
-                } catch (InterruptedException e) {
-                    // Do nothing, go back and wait until the request is complete.
-                    Log.e(TAG, e, "InterruptedException");
-                }
-            }
-        }
-        if (request.result != null) {
-            @SuppressWarnings("unchecked")
-            T retval = (T) request.result;
-            return retval;
-        }
-        return null;
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MODIFY_PHONE_STATE, null);
     }
 
     private void sendListOfCalls(boolean shouldLog) {
-        Collection<Call> mCalls = getCallsManager().getCalls();
+        Collection<Call> mCalls = mCallsManager.getCalls();
         for (Call call : mCalls) {
             // We don't send the parent conference call to the bluetooth device.
-            if (!call.isConference()) {
+            // We do, however want to send conferences that have no children to the bluetooth
+            // device (e.g. IMS Conference).
+            if (!call.isConference() ||
+                    (call.isConference() && call
+                            .can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN))) {
                 sendClccForCall(call, shouldLog);
             }
         }
@@ -580,9 +516,11 @@
      * Sends a single clcc (C* List Current Calls) event for the specified call.
      */
     private void sendClccForCall(Call call, boolean shouldLog) {
-        boolean isForeground = getCallsManager().getForegroundCall() == call;
+        boolean isForeground = mCallsManager.getForegroundCall() == call;
         int state = convertCallState(call.getState(), isForeground);
         boolean isPartOfConference = false;
+        boolean isConferenceWithNoChildren = call.isConference() && call
+                .can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
 
         if (state == CALL_STATE_IDLE) {
             return;
@@ -619,6 +557,11 @@
                     }
                 }
             }
+        } else if (isConferenceWithNoChildren) {
+            // Handle the special case of an IMS conference call without conference event package
+            // support.  The call will be marked as a conference, but the conference will not have
+            // child calls where conference event packages are not used by the carrier.
+            isPartOfConference = true;
         }
 
         int index = getIndexForCall(call);
@@ -678,10 +621,10 @@
      *      changed.
      */
     private void updateHeadsetWithCallState(boolean force) {
-        CallsManager callsManager = getCallsManager();
-        Call activeCall = callsManager.getActiveCall();
-        Call ringingCall = callsManager.getRingingCall();
-        Call heldCall = callsManager.getHeldCall();
+        CallsManager callsManager = mCallsManager;
+        Call activeCall = mCallsManager.getActiveCall();
+        Call ringingCall = mCallsManager.getRingingCall();
+        Call heldCall = mCallsManager.getHeldCall();
 
         int bluetoothCallState = getBluetoothCallStateForUpdate();
 
@@ -698,13 +641,18 @@
         }
 
         int numActiveCalls = activeCall == null ? 0 : 1;
-        int numHeldCalls = callsManager.getNumHeldCalls();
+        int numHeldCalls = mCallsManager.getNumHeldCalls();
+        // Intermediate state for GSM calls which are in the process of being swapped.
+        // TODO: Should we be hardcoding this value to 2 or should we check if all top level calls
+        //       are held?
+        boolean callsPendingSwitch = (numHeldCalls == 2);
 
         // For conference calls which support swapping the active call within the conference
         // (namely CDMA calls) we need to expose that as a held call in order for the BT device
         // to show "swap" and "merge" functionality.
         boolean ignoreHeldCallChange = false;
-        if (activeCall != null && activeCall.isConference()) {
+        if (activeCall != null && activeCall.isConference() &&
+                !activeCall.can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
             if (activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
                 // Indicate that BT device should show SWAP command by indicating that there is a
                 // call on hold, but only if the conference wasn't previously merged.
@@ -725,13 +673,14 @@
         }
 
         if (mBluetoothHeadset != null &&
-                (numActiveCalls != mNumActiveCalls ||
-                 numHeldCalls != mNumHeldCalls ||
-                 bluetoothCallState != mBluetoothCallState ||
-                 !TextUtils.equals(ringingAddress, mRingingAddress) ||
-                 ringingAddressType != mRingingAddressType ||
-                 (heldCall != mOldHeldCall && !ignoreHeldCallChange) ||
-                 force)) {
+                (force ||
+                        (!callsPendingSwitch &&
+                                (numActiveCalls != mNumActiveCalls ||
+                                 numHeldCalls != mNumHeldCalls ||
+                                 bluetoothCallState != mBluetoothCallState ||
+                                 !TextUtils.equals(ringingAddress, mRingingAddress) ||
+                                 ringingAddressType != mRingingAddressType ||
+                                 (heldCall != mOldHeldCall && !ignoreHeldCallChange))))) {
 
             // If the call is transitioning into the alerting state, send DIALING first.
             // Some devices expect to see a DIALING state prior to seeing an ALERTING state
@@ -791,9 +740,9 @@
     }
 
     private int getBluetoothCallStateForUpdate() {
-        CallsManager callsManager = getCallsManager();
-        Call ringingCall = callsManager.getRingingCall();
-        Call dialingCall = callsManager.getDialingCall();
+        CallsManager callsManager = mCallsManager;
+        Call ringingCall = mCallsManager.getRingingCall();
+        Call dialingCall = mCallsManager.getOutgoingCall();
 
         //
         // !! WARNING !!
@@ -819,7 +768,7 @@
             case CallState.ABORTED:
             case CallState.DISCONNECTED:
             case CallState.CONNECTING:
-            case CallState.PRE_DIAL_WAIT:
+            case CallState.SELECT_PHONE_ACCOUNT:
                 return CALL_STATE_IDLE;
 
             case CallState.ACTIVE:
@@ -848,33 +797,30 @@
         return CALL_STATE_IDLE;
     }
 
-    private CallsManager getCallsManager() {
-        return CallsManager.getInstance();
-    }
-
     /**
      * Returns the best phone account to use for the given state of all calls.
      * First, tries to return the phone account for the foreground call, second the default
      * phone account for PhoneAccount.SCHEME_TEL.
      */
     private PhoneAccount getBestPhoneAccount() {
-        PhoneAccountRegistrar registry = TelecomGlobals.getInstance().getPhoneAccountRegistrar();
-        if (registry == null) {
+        if (mPhoneAccountRegistrar == null) {
             return null;
         }
 
-        Call call = getCallsManager().getForegroundCall();
+        Call call = mCallsManager.getForegroundCall();
 
         PhoneAccount account = null;
         if (call != null) {
             // First try to get the network name of the foreground call.
-            account = registry.getPhoneAccount(call.getTargetPhoneAccount());
+            account = mPhoneAccountRegistrar.getPhoneAccountCheckCallingUser(
+                    call.getTargetPhoneAccount());
         }
 
         if (account == null) {
             // Second, Try to get the label for the default Phone Account.
-            account = registry.getPhoneAccount(
-                    registry.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+            account = mPhoneAccountRegistrar.getPhoneAccountCheckCallingUser(
+                    mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(
+                        PhoneAccount.SCHEME_TEL));
         }
         return account;
     }
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index fb6b2e8..603ea7e 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -22,12 +22,14 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.os.Trace;
 import android.provider.ContactsContract.Contacts;
-import android.telecom.CallState;
 import android.telecom.DisconnectCause;
 import android.telecom.Connection;
 import android.telecom.GatewayInfo;
+import android.telecom.InCallService.VideoCall;
 import android.telecom.ParcelableConnection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -38,9 +40,9 @@
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.IVideoProvider;
 import com.android.internal.telephony.CallerInfo;
-import com.android.internal.telephony.CallerInfoAsyncQuery;
 import com.android.internal.telephony.CallerInfoAsyncQuery.OnQueryCompleteListener;
 import com.android.internal.telephony.SmsApplication;
 import com.android.server.telecom.ContactsAsyncHelper.OnImageLoadCompleteListener;
@@ -60,7 +62,8 @@
  *  from the time the call intent was received by Telecom (vs. the time the call was
  *  connected etc).
  */
-final class Call implements CreateConnectionResponse {
+@VisibleForTesting
+public class Call implements CreateConnectionResponse {
     /**
      * Listener for events on the call.
      */
@@ -82,6 +85,7 @@
         void onCallerInfoChanged(Call call);
         void onIsVoipAudioModeChanged(Call call);
         void onStatusHintsChanged(Call call);
+        void onExtrasChanged(Call call);
         void onHandleChanged(Call call);
         void onCallerDisplayNameChanged(Call call);
         void onVideoStateChanged(Call call);
@@ -92,7 +96,7 @@
         boolean onCanceledViaNewOutgoingCallBroadcast(Call call);
     }
 
-    abstract static class ListenerBase implements Listener {
+    public abstract static class ListenerBase implements Listener {
         @Override
         public void onSuccessfulOutgoingCall(Call call, int callState) {}
         @Override
@@ -128,6 +132,8 @@
         @Override
         public void onStatusHintsChanged(Call call) {}
         @Override
+        public void onExtrasChanged(Call call) {}
+        @Override
         public void onHandleChanged(Call call) {}
         @Override
         public void onCallerDisplayNameChanged(Call call) {}
@@ -147,25 +153,29 @@
         }
     }
 
-    private static final OnQueryCompleteListener sCallerInfoQueryListener =
+    private final OnQueryCompleteListener mCallerInfoQueryListener =
             new OnQueryCompleteListener() {
                 /** ${inheritDoc} */
                 @Override
                 public void onQueryComplete(int token, Object cookie, CallerInfo callerInfo) {
-                    if (cookie != null) {
-                        ((Call) cookie).setCallerInfo(callerInfo, token);
+                    synchronized (mLock) {
+                        if (cookie != null) {
+                            ((Call) cookie).setCallerInfo(callerInfo, token);
+                        }
                     }
                 }
             };
 
-    private static final OnImageLoadCompleteListener sPhotoLoadListener =
+    private final OnImageLoadCompleteListener mPhotoLoadListener =
             new OnImageLoadCompleteListener() {
                 /** ${inheritDoc} */
                 @Override
                 public void onImageLoadComplete(
                         int token, Drawable photo, Bitmap photoIcon, Object cookie) {
-                    if (cookie != null) {
-                        ((Call) cookie).setPhoto(photo, photoIcon, token);
+                    synchronized (mLock) {
+                        if (cookie != null) {
+                            ((Call) cookie).setPhoto(photo, photoIcon, token);
+                        }
                     }
                 }
             };
@@ -173,7 +183,9 @@
     private final Runnable mDirectToVoicemailRunnable = new Runnable() {
         @Override
         public void run() {
-            processDirectToVoicemail();
+            synchronized (mLock) {
+                processDirectToVoicemail();
+            }
         }
     };
 
@@ -207,7 +219,7 @@
 
     private PhoneAccountHandle mTargetPhoneAccountHandle;
 
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
 
     private final List<Call> mConferenceableCalls = new ArrayList<>();
 
@@ -242,6 +254,9 @@
     /**
      * Tracks the video states which were applicable over the duration of a call.
      * See {@link VideoProfile} for a list of valid video states.
+     * <p>
+     * Video state history is tracked when the call is active, and when a call is rejected or
+     * missed.
      */
     private int mVideoStateHistory;
 
@@ -253,8 +268,7 @@
      */
     private DisconnectCause mDisconnectCause = new DisconnectCause(DisconnectCause.UNKNOWN);
 
-    /** Info used by the connection services. */
-    private Bundle mExtras = new Bundle();
+    private Bundle mIntentExtras = new Bundle();
 
     /** Set of listeners on this call.
      *
@@ -294,18 +308,24 @@
     private boolean mCannedSmsResponsesLoadingStarted = false;
 
     private IVideoProvider mVideoProvider;
+    private VideoProviderProxy mVideoProviderProxy;
 
     private boolean mIsVoipAudioMode;
     private StatusHints mStatusHints;
+    private Bundle mExtras;
     private final ConnectionServiceRepository mRepository;
+    private final ContactsAsyncHelper mContactsAsyncHelper;
     private final Context mContext;
+    private final CallsManager mCallsManager;
+    private final TelecomSystem.SyncRoot mLock;
+    private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
 
     private boolean mWasConferencePreviouslyMerged = false;
 
-    // For conferences which support merge/swap at their level, we retain a notion of an active call.
-    // This is used for BluetoothPhoneService.  In order to support hold/merge, it must have the notion
-    // of the current "active" call within the conference call. This maintains the "active" call and
-    // switches every time the user hits "swap".
+    // For conferences which support merge/swap at their level, we retain a notion of an active
+    // call. This is used for BluetoothPhoneService.  In order to support hold/merge, it must have
+    // the notion of the current "active" call within the conference call. This maintains the
+    // "active" call and switches every time the user hits "swap".
     private Call mConferenceLevelActiveCall = null;
 
     private boolean mIsLocallyDisconnecting = false;
@@ -324,9 +344,13 @@
      *         one that was registered with the {@link PhoneAccount#CAPABILITY_CALL_PROVIDER} flag.
      * @param isIncoming True if this is an incoming call.
      */
-    Call(
+    public Call(
             Context context,
+            CallsManager callsManager,
+            TelecomSystem.SyncRoot lock,
             ConnectionServiceRepository repository,
+            ContactsAsyncHelper contactsAsyncHelper,
+            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
             Uri handle,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle connectionManagerPhoneAccountHandle,
@@ -335,7 +359,11 @@
             boolean isConference) {
         mState = isConference ? CallState.ACTIVE : CallState.NEW;
         mContext = context;
+        mCallsManager = callsManager;
+        mLock = lock;
         mRepository = repository;
+        mContactsAsyncHelper = contactsAsyncHelper;
+        mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
         setHandle(handle);
         setHandle(handle, TelecomManager.PRESENTATION_ALLOWED);
         mGatewayInfo = gatewayInfo;
@@ -344,6 +372,8 @@
         mIsIncoming = isIncoming;
         mIsConference = isConference;
         maybeLoadCannedSmsResponses();
+
+        Log.event(this, Log.Events.CREATED);
     }
 
     /**
@@ -363,7 +393,11 @@
      */
     Call(
             Context context,
+            CallsManager callsManager,
+            TelecomSystem.SyncRoot lock,
             ConnectionServiceRepository repository,
+            ContactsAsyncHelper contactsAsyncHelper,
+            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
             Uri handle,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle connectionManagerPhoneAccountHandle,
@@ -371,22 +405,28 @@
             boolean isIncoming,
             boolean isConference,
             long connectTimeMillis) {
-        this(context, repository, handle, gatewayInfo, connectionManagerPhoneAccountHandle,
-                targetPhoneAccountHandle, isIncoming, isConference);
+        this(context, callsManager, lock, repository, contactsAsyncHelper,
+                callerInfoAsyncQueryFactory, handle, gatewayInfo,
+                connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, isIncoming,
+                isConference);
 
         mConnectTimeMillis = connectTimeMillis;
     }
 
-    void addListener(Listener listener) {
+    public void addListener(Listener listener) {
         mListeners.add(listener);
     }
 
-    void removeListener(Listener listener) {
+    public void removeListener(Listener listener) {
         if (listener != null) {
             mListeners.remove(listener);
         }
     }
 
+    public void destroy() {
+        Log.event(this, Log.Events.DESTROYED);
+    }
+
     /** {@inheritDoc} */
     @Override
     public String toString() {
@@ -395,17 +435,47 @@
             component = mConnectionService.getComponentName().flattenToShortString();
         }
 
-        return String.format(Locale.US, "[%s, %s, %s, %s, %d, childs(%d), has_parent(%b), [%s]",
+
+
+        return String.format(Locale.US, "[%s, %s, %s, %s, %s, childs(%d), has_parent(%b), [%s]]",
                 System.identityHashCode(this),
                 CallState.toString(mState),
                 component,
                 Log.piiHandle(mHandle),
-                getVideoState(),
+                getVideoStateDescription(getVideoState()),
                 getChildCalls().size(),
                 getParentCall() != null,
                 Connection.capabilitiesToString(getConnectionCapabilities()));
     }
 
+    /**
+     * Builds a debug-friendly description string for a video state.
+     * <p>
+     * A = audio active, T = video transmission active, R = video reception active, P = video
+     * paused.
+     *
+     * @param videoState The video state.
+     * @return A string indicating which bits are set in the video state.
+     */
+    private String getVideoStateDescription(int videoState) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("A");
+
+        if (VideoProfile.isTransmissionEnabled(videoState)) {
+            sb.append("T");
+        }
+
+        if (VideoProfile.isReceptionEnabled(videoState)) {
+            sb.append("R");
+        }
+
+        if (VideoProfile.isPaused(videoState)) {
+            sb.append("P");
+        }
+
+        return sb.toString();
+    }
+
     int getState() {
         return mState;
     }
@@ -438,7 +508,7 @@
      * misbehave and they do this very often. The result is that we do not enforce state transitions
      * and instead keep the code resilient to unexpected state changes.
      */
-    void setState(int newState) {
+    public void setState(int newState, String tag) {
         if (mState != newState) {
             Log.v(this, "setState %s -> %s", mState, newState);
 
@@ -459,6 +529,12 @@
                     mConnectTimeMillis = System.currentTimeMillis();
                 }
 
+                // Video state changes are normally tracked against history when a call is active.
+                // When the call goes active we need to be sure we track the history in case the
+                // state never changes during the duration of the call -- we want to ensure we
+                // always know the state at the start of the call.
+                mVideoStateHistory = mVideoStateHistory | mVideoState;
+
                 // We're clearly not disconnected, so reset the disconnected time.
                 mDisconnectTimeMillis = 0;
             } else if (mState == CallState.DISCONNECTED) {
@@ -466,6 +542,51 @@
                 setLocallyDisconnecting(false);
                 fixParentAfterDisconnect();
             }
+            if (mState == CallState.DISCONNECTED &&
+                    mDisconnectCause.getCode() == DisconnectCause.MISSED) {
+                // Ensure when an incoming call is missed that the video state history is updated.
+                mVideoStateHistory |= mVideoState;
+            }
+
+            // Log the state transition event
+            String event = null;
+            Object data = null;
+            switch (newState) {
+                case CallState.ACTIVE:
+                    event = Log.Events.SET_ACTIVE;
+                    break;
+                case CallState.CONNECTING:
+                    event = Log.Events.SET_CONNECTING;
+                    break;
+                case CallState.DIALING:
+                    event = Log.Events.SET_DIALING;
+                    break;
+                case CallState.DISCONNECTED:
+                    event = Log.Events.SET_DISCONNECTED;
+                    data = getDisconnectCause();
+                    break;
+                case CallState.DISCONNECTING:
+                    event = Log.Events.SET_DISCONNECTING;
+                    break;
+                case CallState.ON_HOLD:
+                    event = Log.Events.SET_HOLD;
+                    break;
+                case CallState.SELECT_PHONE_ACCOUNT:
+                    event = Log.Events.SET_SELECT_PHONE_ACCOUNT;
+                    break;
+                case CallState.RINGING:
+                    event = Log.Events.SET_RINGING;
+                    break;
+            }
+            if (event != null) {
+                // The string data should be just the tag.
+                String stringData = tag;
+                if (data != null) {
+                    // If data exists, add it to tag.  If no tag, just use data.toString().
+                    stringData = stringData == null ? data.toString() : stringData + "> " + data;
+                }
+                Log.event(this, event, stringData);
+            }
         }
     }
 
@@ -484,7 +605,7 @@
         return mIsConference;
     }
 
-    Uri getHandle() {
+    public Uri getHandle() {
         return mHandle;
     }
 
@@ -497,7 +618,7 @@
         setHandle(handle, TelecomManager.PRESENTATION_ALLOWED);
     }
 
-    void setHandle(Uri handle, int presentation) {
+    public void setHandle(Uri handle, int presentation) {
         if (!Objects.equals(handle, mHandle) || presentation != mHandlePresentation) {
             mHandlePresentation = presentation;
             if (mHandlePresentation == TelecomManager.PRESENTATION_RESTRICTED ||
@@ -541,15 +662,15 @@
         }
     }
 
-    String getName() {
+    public String getName() {
         return mCallerInfo == null ? null : mCallerInfo.name;
     }
 
-    Bitmap getPhotoIcon() {
+    public Bitmap getPhotoIcon() {
         return mCallerInfo == null ? null : mCallerInfo.cachedPhotoIcon;
     }
 
-    Drawable getPhoto() {
+    public Drawable getPhoto() {
         return mCallerInfo == null ? null : mCallerInfo.cachedPhoto;
     }
 
@@ -557,13 +678,13 @@
      * @param disconnectCause The reason for the disconnection, represented by
      *         {@link android.telecom.DisconnectCause}.
      */
-    void setDisconnectCause(DisconnectCause disconnectCause) {
+    public void setDisconnectCause(DisconnectCause disconnectCause) {
         // TODO: Consider combining this method with a setDisconnected() method that is totally
         // separate from setState.
         mDisconnectCause = disconnectCause;
     }
 
-    DisconnectCause getDisconnectCause() {
+    public DisconnectCause getDisconnectCause() {
         return mDisconnectCause;
     }
 
@@ -648,11 +769,11 @@
      * @return The time when this call object was created and added to the set of pending outgoing
      *     calls.
      */
-    long getCreationTimeMillis() {
+    public long getCreationTimeMillis() {
         return mCreationTimeMillis;
     }
 
-    void setCreationTimeMillis(long time) {
+    public void setCreationTimeMillis(long time) {
         mCreationTimeMillis = time;
     }
 
@@ -743,7 +864,7 @@
                 Log.i(this, "Directing call to voicemail: %s.", this);
                 // TODO: Once we move State handling from CallsManager to Call, we
                 // will not need to set STATE_RINGING state prior to calling reject.
-                setState(CallState.RINGING);
+                setState(CallState.RINGING, "directing to voicemail");
                 reject(false, null);
             } else {
                 // TODO: Make this class (not CallsManager) responsible for changing
@@ -787,6 +908,7 @@
         setRingbackRequested(connection.isRingbackRequested());
         setIsVoipAudioMode(connection.getIsVoipAudioMode());
         setStatusHints(connection.getStatusHints());
+        setExtras(connection.getExtras());
 
         mConferenceableCalls.clear();
         for (String id : connection.getConferenceableConnectionIds()) {
@@ -820,7 +942,7 @@
     public void handleCreateConnectionFailure(DisconnectCause disconnectCause) {
         clearConnectionService();
         setDisconnectCause(disconnectCause);
-        CallsManager.getInstance().markCallAsDisconnected(this, disconnectCause);
+        mCallsManager.markCallAsDisconnected(this, disconnectCause);
 
         if (mIsUnknown) {
             for (Listener listener : mListeners) {
@@ -846,6 +968,7 @@
         } else {
             Log.i(this, "Send playDtmfTone to connection service for call %s", this);
             mConnectionService.playDtmfTone(this, digit);
+            Log.event(this, Log.Events.START_DTMF, Log.pii(digit));
         }
     }
 
@@ -857,6 +980,7 @@
             Log.w(this, "stopDtmfTone() request on a call without a connection service.");
         } else {
             Log.i(this, "Send stopDtmfTone to connection service for call %s", this);
+            Log.event(this, Log.Events.STOP_DTMF);
             mConnectionService.stopDtmfTone(this);
         }
     }
@@ -869,10 +993,12 @@
      * Attempts to disconnect the call through the connection service.
      */
     void disconnect(boolean wasViaNewOutgoingCallBroadcaster) {
+        Log.event(this, Log.Events.REQUEST_DISCONNECT);
+
         // Track that the call is now locally disconnecting.
         setLocallyDisconnecting(true);
 
-        if (mState == CallState.NEW || mState == CallState.PRE_DIAL_WAIT ||
+        if (mState == CallState.NEW || mState == CallState.SELECT_PHONE_ACCOUNT ||
                 mState == CallState.CONNECTING) {
             Log.v(this, "Aborting call %s", this);
             abort(wasViaNewOutgoingCallBroadcaster);
@@ -895,7 +1021,7 @@
         if (mCreateConnectionProcessor != null &&
                 !mCreateConnectionProcessor.isProcessingComplete()) {
             mCreateConnectionProcessor.abort();
-        } else if (mState == CallState.NEW || mState == CallState.PRE_DIAL_WAIT
+        } else if (mState == CallState.NEW || mState == CallState.SELECT_PHONE_ACCOUNT
                 || mState == CallState.CONNECTING) {
             if (wasViaNewOutgoingCallBroadcaster) {
                 // If the cancelation was from NEW_OUTGOING_CALL, then we do not automatically
@@ -918,7 +1044,7 @@
 
             handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.CANCELED));
         } else {
-            Log.v(this, "Cannot abort a call which isn't either PRE_DIAL_WAIT or CONNECTING");
+            Log.v(this, "Cannot abort a call which is neither SELECT_PHONE_ACCOUNT or CONNECTING");
         }
     }
 
@@ -938,6 +1064,7 @@
             // 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);
+            Log.event(this, Log.Events.REQUEST_ACCEPT);
         }
     }
 
@@ -953,7 +1080,11 @@
         // 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);
+            Log.event(this, Log.Events.REQUEST_REJECT);
         }
     }
 
@@ -965,6 +1096,7 @@
 
         if (mState == CallState.ACTIVE) {
             mConnectionService.hold(this);
+            Log.event(this, Log.Events.REQUEST_HOLD);
         }
     }
 
@@ -976,6 +1108,7 @@
 
         if (mState == CallState.ON_HOLD) {
             mConnectionService.unhold(this);
+            Log.event(this, Log.Events.REQUEST_UNHOLD);
         }
     }
 
@@ -1002,6 +1135,17 @@
 
     void setExtras(Bundle extras) {
         mExtras = extras;
+        for (Listener l : mListeners) {
+            l.onExtrasChanged(this);
+        }
+    }
+
+    Bundle getIntentExtras() {
+        return mIntentExtras;
+    }
+
+    void setIntentExtras(Bundle extras) {
+        mIntentExtras = extras;
     }
 
     /**
@@ -1038,6 +1182,7 @@
         if (mConnectionService == null) {
             Log.w(this, "conference requested on a call without a connection service.");
         } else {
+            Log.event(this, Log.Events.CONFERENCE_WITH, otherCall);
             mConnectionService.conference(this, otherCall);
         }
     }
@@ -1046,6 +1191,7 @@
         if (mConnectionService == null) {
             Log.w(this, "splitting from conference call without a connection service");
         } else {
+            Log.event(this, Log.Events.SPLIT_CONFERENCE);
             mConnectionService.splitFromConference(this);
         }
     }
@@ -1054,6 +1200,7 @@
         if (mConnectionService == null) {
             Log.w(this, "merging conference calls without a connection service.");
         } else if (can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
+            Log.event(this, Log.Events.CONFERENCE_WITH);
             mConnectionService.mergeConference(this);
             mWasConferencePreviouslyMerged = true;
         }
@@ -1063,6 +1210,7 @@
         if (mConnectionService == null) {
             Log.w(this, "swapping conference calls without a connection service.");
         } else if (can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
+            Log.event(this, Log.Events.SWAP);
             mConnectionService.swapConference(this);
             switch (mChildCalls.size()) {
                 case 1:
@@ -1101,6 +1249,7 @@
             mParentCall.addChildCall(this);
         }
 
+        Log.event(this, Log.Events.SET_PARENT, mParentCall);
         for (Listener l : mListeners) {
             l.onParentChanged(this);
         }
@@ -1130,6 +1279,8 @@
             mConferenceLevelActiveCall = call;
             mChildCalls.add(call);
 
+            Log.event(this, Log.Events.ADD_CHILD, call);
+
             for (Listener l : mListeners) {
                 l.onChildrenChanged(this);
             }
@@ -1138,6 +1289,7 @@
 
     private void removeChildCall(Call call) {
         if (mChildCalls.remove(call)) {
+            Log.event(this, Log.Events.REMOVE_CHILD, call);
             for (Listener l : mListeners) {
                 l.onChildrenChanged(this);
             }
@@ -1237,18 +1389,23 @@
      * Looks up contact information based on the current handle.
      */
     private void startCallerInfoLookup() {
-        String number = mHandle == null ? null : mHandle.getSchemeSpecificPart();
+        final String number = mHandle == null ? null : mHandle.getSchemeSpecificPart();
 
         mQueryToken++;  // Updated so that previous queries can no longer set the information.
         mCallerInfo = null;
         if (!TextUtils.isEmpty(number)) {
             Log.v(this, "Looking up information for: %s.", Log.piiHandle(number));
-            CallerInfoAsyncQuery.startQuery(
-                    mQueryToken,
-                    mContext,
-                    number,
-                    sCallerInfoQueryListener,
-                    this);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallerInfoAsyncQueryFactory.startQuery(
+                            mQueryToken,
+                            mContext,
+                            number,
+                            mCallerInfoQueryListener,
+                            Call.this);
+                }
+            });
         }
     }
 
@@ -1270,11 +1427,11 @@
             if (mCallerInfo.contactDisplayPhotoUri != null) {
                 Log.d(this, "Searching person uri %s for call %s",
                         mCallerInfo.contactDisplayPhotoUri, this);
-                ContactsAsyncHelper.startObtainPhotoAsync(
+                mContactsAsyncHelper.startObtainPhotoAsync(
                         token,
                         mContext,
                         mCallerInfo.contactDisplayPhotoUri,
-                        sPhotoLoadListener,
+                        mPhotoLoadListener,
                         this);
                 // Do not call onCallerInfoChanged yet in this case.  We call it in setPhoto().
             } else {
@@ -1314,7 +1471,7 @@
         if (mIsIncoming && isRespondViaSmsCapable() && !mCannedSmsResponsesLoadingStarted) {
             Log.d(this, "maybeLoadCannedSmsResponses: starting task to load messages");
             mCannedSmsResponsesLoadingStarted = true;
-            RespondViaSmsManager.getInstance().loadCannedTextMessages(
+            mCallsManager.getRespondViaSmsManager().loadCannedTextMessages(
                     new Response<Void, List<String>>() {
                         @Override
                         public void onResult(Void request, List<String>... result) {
@@ -1360,22 +1517,46 @@
      * Sets a video call provider for the call.
      */
     public void setVideoProvider(IVideoProvider videoProvider) {
+        Log.v(this, "setVideoProvider");
+
+        if (videoProvider != null ) {
+            try {
+                mVideoProviderProxy = new VideoProviderProxy(mLock, videoProvider, this);
+            } catch (RemoteException ignored) {
+                // Ignore RemoteException.
+            }
+        } else {
+            mVideoProviderProxy = null;
+        }
+
         mVideoProvider = videoProvider;
+
         for (Listener l : mListeners) {
             l.onVideoCallProviderChanged(Call.this);
         }
     }
 
     /**
-     * @return Return the {@link Connection.VideoProvider} binder.
+     * @return The {@link Connection.VideoProvider} binder.
      */
     public IVideoProvider getVideoProvider() {
-        return mVideoProvider;
+        if (mVideoProviderProxy == null) {
+            return null;
+        }
+
+        return mVideoProviderProxy.getInterface();
+    }
+
+    /**
+     * @return The {@link VideoProviderProxy} for this call.
+     */
+    public VideoProviderProxy getVideoProviderProxy() {
+        return mVideoProviderProxy;
     }
 
     /**
      * The current video state for the call.
-     * Valid values: see {@link VideoProfile.VideoState}.
+     * See {@link VideoProfile} for a list of valid video states.
      */
     public int getVideoState() {
         return mVideoState;
@@ -1394,13 +1575,21 @@
     /**
      * Determines the current video state for the call.
      * For an outgoing call determines the desired video state for the call.
-     * Valid values: see {@link VideoProfile.VideoState}
+     * Valid values: see {@link VideoProfile}
      *
      * @param videoState The video state for the call.
      */
     public void setVideoState(int videoState) {
         // Track which video states were applicable over the duration of the call.
-        mVideoStateHistory = mVideoStateHistory | videoState;
+        // Only track the call state when the call is active or disconnected.  This ensures we do
+        // not include the video state when:
+        // - Call is incoming (but not answered).
+        // - Call it outgoing (but not answered).
+        // We include the video state when disconnected to ensure that rejected calls reflect the
+        // appropriate video state.
+        if (isActive() || getState() == CallState.DISCONNECTED) {
+            mVideoStateHistory = mVideoStateHistory | videoState;
+        }
 
         mVideoState = videoState;
         for (Listener l : mListeners) {
diff --git a/src/com/android/server/telecom/CallActivity.java b/src/com/android/server/telecom/CallActivity.java
deleted file mode 100644
index 37e24f6..0000000
--- a/src/com/android/server/telecom/CallActivity.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.telecom;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.DisconnectCause;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.widget.Toast;
-
-// TODO: Needed for move to system service: import com.android.internal.R;
-
-/**
- * Activity that handles system CALL actions and forwards them to {@link CallReceiver}.
- * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY.
- *
- * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the
- * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission).
- *
- * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency
- * calls via ACTION_CALL_PRIVILEGED.
- *
- * In addition, the default dialer (identified via
- * {@link android.telecom.TelecomManager#getDefaultPhoneApp()} will also be granted the ability to
- * make emergency outgoing calls using the CALL action. In order to do this, it must call
- * startActivityForResult on the CALL intent to allow its package name to be passed to
- * {@link CallActivity}. Calling startActivity will continue to work on all non-emergency numbers
- * just like it did pre-L.
- */
-public class CallActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle bundle) {
-        super.onCreate(bundle);
-
-        // TODO: Figure out if there is something to restore from bundle.
-        // See OutgoingCallBroadcaster in services/Telephony for more.
-
-        processIntent(getIntent());
-
-        // This activity does not have associated UI, so close.
-        finish();
-        Log.d(this, "onCreate: end");
-    }
-
-    /**
-     * Processes intents sent to the activity.
-     *
-     * @param intent The intent.
-     */
-    private void processIntent(Intent intent) {
-        // Ensure call intents are not processed on devices that are not capable of calling.
-        if (!isVoiceCapable()) {
-            return;
-        }
-
-        verifyCallAction(intent);
-        String action = intent.getAction();
-
-        if (Intent.ACTION_CALL.equals(action) ||
-                Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
-                Intent.ACTION_CALL_EMERGENCY.equals(action)) {
-            processOutgoingCallIntent(intent);
-        }
-    }
-
-    private void verifyCallAction(Intent intent) {
-        if (CallActivity.class.getName().equals(intent.getComponent().getClassName())) {
-            // If we were launched directly from the CallActivity, not one of its more privileged
-            // aliases, then make sure that only the non-privileged actions are allowed.
-            if (!Intent.ACTION_CALL.equals(intent.getAction())) {
-                Log.w(this, "Attempt to deliver non-CALL action; forcing to CALL");
-                intent.setAction(Intent.ACTION_CALL);
-            }
-        }
-    }
-
-    private void processOutgoingCallIntent(Intent intent) {
-        Uri handle = intent.getData();
-        String scheme = handle.getScheme();
-        String uriString = handle.getSchemeSpecificPart();
-
-        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
-            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
-                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
-        }
-
-        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
-        if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS)
-                && !TelephonyUtil.shouldProcessAsEmergency(this, handle)) {
-            // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS
-            // restriction.
-            Toast.makeText(this, getResources().getString(R.string.outgoing_call_not_allowed),
-                    Toast.LENGTH_SHORT).show();
-            Log.d(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS "
-                    + "restriction");
-            return;
-        }
-
-        intent.putExtra(CallReceiver.KEY_IS_DEFAULT_DIALER, isDefaultDialer());
-        sendBroadcastToReceiver(intent);
-    }
-
-    private boolean isDefaultDialer() {
-        final String packageName = getCallingPackage();
-        if (TextUtils.isEmpty(packageName)) {
-            return false;
-        }
-
-        final TelecomManager telecomManager =
-                (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
-        final ComponentName defaultPhoneApp = telecomManager.getDefaultPhoneApp();
-        return (defaultPhoneApp != null
-                && TextUtils.equals(defaultPhoneApp.getPackageName(), packageName));
-    }
-
-    /**
-     * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
-     *
-     * @return {@code True} if the device is voice-capable.
-     */
-    private boolean isVoiceCapable() {
-        return getApplicationContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
-    }
-
-    /**
-     * Trampolines the intent to the broadcast receiver that runs only as the primary user.
-     */
-    private boolean sendBroadcastToReceiver(Intent intent) {
-        intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, false);
-        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        intent.setClass(this, CallReceiver.class);
-        Log.d(this, "Sending broadcast as user to CallReceiver");
-        sendBroadcastAsUser(intent, UserHandle.OWNER);
-        return true;
-    }
-}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index b555f85..da3deb6 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -18,8 +18,10 @@
 
 import android.content.Context;
 import android.media.AudioManager;
-import android.telecom.AudioState;
-import android.telecom.CallState;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.telecom.CallAudioState;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -30,15 +32,107 @@
  * This class manages audio modes, streams and other properties.
  */
 final class CallAudioManager extends CallsManagerListenerBase
-        implements WiredHeadsetManager.Listener {
+        implements WiredHeadsetManager.Listener, DockManager.Listener {
     private static final int STREAM_NONE = -1;
 
+    private static final String STREAM_DESCRIPTION_NONE = "STEAM_NONE";
+    private static final String STREAM_DESCRIPTION_ALARM = "STEAM_ALARM";
+    private static final String STREAM_DESCRIPTION_BLUETOOTH_SCO = "STREAM_BLUETOOTH_SCO";
+    private static final String STREAM_DESCRIPTION_DTMF = "STREAM_DTMF";
+    private static final String STREAM_DESCRIPTION_MUSIC = "STREAM_MUSIC";
+    private static final String STREAM_DESCRIPTION_NOTIFICATION = "STREAM_NOTIFICATION";
+    private static final String STREAM_DESCRIPTION_RING = "STREAM_RING";
+    private static final String STREAM_DESCRIPTION_SYSTEM = "STREAM_SYSTEM";
+    private static final String STREAM_DESCRIPTION_VOICE_CALL = "STREAM_VOICE_CALL";
+
+    private static final String MODE_DESCRIPTION_INVALID = "MODE_INVALID";
+    private static final String MODE_DESCRIPTION_CURRENT = "MODE_CURRENT";
+    private static final String MODE_DESCRIPTION_NORMAL = "MODE_NORMAL";
+    private static final String MODE_DESCRIPTION_RINGTONE = "MODE_RINGTONE";
+    private static final String MODE_DESCRIPTION_IN_CALL = "MODE_IN_CALL";
+    private static final String MODE_DESCRIPTION_IN_COMMUNICATION = "MODE_IN_COMMUNICATION";
+
+    private static final int MSG_AUDIO_MANAGER_INITIALIZE = 0;
+    private static final int MSG_AUDIO_MANAGER_TURN_ON_SPEAKER = 1;
+    private static final int MSG_AUDIO_MANAGER_ABANDON_AUDIO_FOCUS_FOR_CALL = 2;
+    private static final int MSG_AUDIO_MANAGER_SET_MICROPHONE_MUTE = 3;
+    private static final int MSG_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS_FOR_CALL = 4;
+    private static final int MSG_AUDIO_MANAGER_SET_MODE = 5;
+
+    private final Handler mAudioManagerHandler = new Handler(Looper.getMainLooper()) {
+
+        private AudioManager mAudioManager;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_AUDIO_MANAGER_INITIALIZE: {
+                    mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+                    break;
+                }
+                case MSG_AUDIO_MANAGER_TURN_ON_SPEAKER: {
+                    boolean on = (msg.arg1 != 0);
+                    // Wired headset and earpiece work the same way
+                    if (mAudioManager.isSpeakerphoneOn() != on) {
+                        Log.i(this, "turning speaker phone %s", on);
+                        mAudioManager.setSpeakerphoneOn(on);
+                    }
+                    break;
+                }
+                case MSG_AUDIO_MANAGER_ABANDON_AUDIO_FOCUS_FOR_CALL: {
+                    mAudioManager.abandonAudioFocusForCall();
+                    break;
+                }
+                case MSG_AUDIO_MANAGER_SET_MICROPHONE_MUTE: {
+                    boolean mute = (msg.arg1 != 0);
+                    if (mute != mAudioManager.isMicrophoneMute()) {
+                        Log.i(this, "changing microphone mute state to: %b", mute);
+                        mAudioManager.setMicrophoneMute(mute);
+                    }
+                    break;
+                }
+                case MSG_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS_FOR_CALL: {
+                    int stream = msg.arg1;
+                    mAudioManager.requestAudioFocusForCall(
+                            stream,
+                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+                    break;
+                }
+                case MSG_AUDIO_MANAGER_SET_MODE: {
+                    int newMode = msg.arg1;
+                    int oldMode = mAudioManager.getMode();
+                    Log.v(this, "Request to change audio mode from %s to %s", modeToString(oldMode),
+                            modeToString(newMode));
+
+                    if (oldMode != newMode) {
+                        if (oldMode == AudioManager.MODE_IN_CALL &&
+                                newMode == AudioManager.MODE_RINGTONE) {
+                            Log.i(this, "Transition from IN_CALL -> RINGTONE."
+                                    + "  Resetting to NORMAL first.");
+                            mAudioManager.setMode(AudioManager.MODE_NORMAL);
+                        }
+                        mAudioManager.setMode(newMode);
+                        synchronized (mLock) {
+                            mMostRecentlyUsedMode = newMode;
+                        }
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    };
+
+    private final Context mContext;
+    private final TelecomSystem.SyncRoot mLock;
     private final StatusBarNotifier mStatusBarNotifier;
-    private final AudioManager mAudioManager;
     private final BluetoothManager mBluetoothManager;
     private final WiredHeadsetManager mWiredHeadsetManager;
+    private final DockManager mDockManager;
+    private final CallsManager mCallsManager;
 
-    private AudioState mAudioState;
+    private CallAudioState mCallAudioState;
     private int mAudioFocusStreamType;
     private boolean mIsRinging;
     private boolean mIsTonePlaying;
@@ -46,72 +140,87 @@
     private int mMostRecentlyUsedMode = AudioManager.MODE_IN_CALL;
     private Call mCallToSpeedUpMTAudio = null;
 
-    CallAudioManager(Context context, StatusBarNotifier statusBarNotifier,
-            WiredHeadsetManager wiredHeadsetManager) {
+    CallAudioManager(
+            Context context,
+            TelecomSystem.SyncRoot lock,
+            StatusBarNotifier statusBarNotifier,
+            WiredHeadsetManager wiredHeadsetManager,
+            DockManager dockManager,
+            CallsManager callsManager) {
+        mContext = context;
+        mLock = lock;
+        mAudioManagerHandler.obtainMessage(MSG_AUDIO_MANAGER_INITIALIZE, 0, 0).sendToTarget();
         mStatusBarNotifier = statusBarNotifier;
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mBluetoothManager = new BluetoothManager(context, this);
         mWiredHeadsetManager = wiredHeadsetManager;
+        mCallsManager = callsManager;
+
         mWiredHeadsetManager.addListener(this);
+        mDockManager = dockManager;
+        mDockManager.addListener(this);
 
         saveAudioState(getInitialAudioState(null));
         mAudioFocusStreamType = STREAM_NONE;
     }
 
-    AudioState getAudioState() {
-        return mAudioState;
+    CallAudioState getCallAudioState() {
+        return mCallAudioState;
     }
 
     @Override
     public void onCallAdded(Call call) {
+        Log.v(this, "onCallAdded");
         onCallUpdated(call);
 
         if (hasFocus() && getForegroundCall() == call) {
             if (!call.isIncoming()) {
                 // Unmute new outgoing call.
-                setSystemAudioState(false, mAudioState.getRoute(),
-                        mAudioState.getSupportedRouteMask());
+                setSystemAudioState(false, mCallAudioState.getRoute(),
+                        mCallAudioState.getSupportedRouteMask());
             }
         }
     }
 
     @Override
     public void onCallRemoved(Call call) {
+        Log.v(this, "onCallRemoved");
         // If we didn't already have focus, there's nothing to do.
         if (hasFocus()) {
-            if (CallsManager.getInstance().getCalls().isEmpty()) {
-                Log.v(this, "all calls removed, reseting system audio to default state");
+            if (mCallsManager.getCalls().isEmpty()) {
+                Log.v(this, "all calls removed, resetting system audio to default state");
                 setInitialAudioState(null, false /* force */);
                 mWasSpeakerOn = false;
             }
-            updateAudioStreamAndMode();
+            updateAudioStreamAndMode(call);
         }
     }
 
     @Override
     public void onCallStateChanged(Call call, int oldState, int newState) {
+        Log.v(this, "onCallStateChanged : oldState = %d, newState = %d", oldState, newState);
         onCallUpdated(call);
     }
 
     @Override
     public void onIncomingCallAnswered(Call call) {
-        int route = mAudioState.getRoute();
+        Log.v(this, "onIncomingCallAnswered");
+        int route = mCallAudioState.getRoute();
 
         // We do two things:
         // (1) If this is the first call, then we can to turn on bluetooth if available.
         // (2) Unmute the audio for the new incoming call.
-        boolean isOnlyCall = CallsManager.getInstance().getCalls().size() == 1;
+        boolean isOnlyCall = mCallsManager.getCalls().size() == 1;
         if (isOnlyCall && mBluetoothManager.isBluetoothAvailable()) {
             mBluetoothManager.connectBluetoothAudio();
-            route = AudioState.ROUTE_BLUETOOTH;
+            route = CallAudioState.ROUTE_BLUETOOTH;
         }
 
-        setSystemAudioState(false /* isMute */, route, mAudioState.getSupportedRouteMask());
+        setSystemAudioState(false /* isMute */, route, mCallAudioState.getSupportedRouteMask());
 
         if (call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) {
             Log.v(this, "Speed up audio setup for IMS MT call.");
             mCallToSpeedUpMTAudio = call;
-            updateAudioStreamAndMode();
+            updateAudioStreamAndMode(call);
         }
     }
 
@@ -124,7 +233,7 @@
 
     @Override
     public void onIsVoipAudioModeChanged(Call call) {
-        updateAudioStreamAndMode();
+        updateAudioStreamAndMode(call);
     }
 
     /**
@@ -138,11 +247,12 @@
             return;
         }
 
-        boolean isCurrentlyWiredHeadset = mAudioState.getRoute() == AudioState.ROUTE_WIRED_HEADSET;
+        boolean isCurrentlyWiredHeadset = mCallAudioState.getRoute()
+                == CallAudioState.ROUTE_WIRED_HEADSET;
 
-        int newRoute = mAudioState.getRoute();  // start out with existing route
+        int newRoute = mCallAudioState.getRoute();  // start out with existing route
         if (newIsPluggedIn) {
-            newRoute = AudioState.ROUTE_WIRED_HEADSET;
+            newRoute = CallAudioState.ROUTE_WIRED_HEADSET;
         } else if (isCurrentlyWiredHeadset) {
             Call call = getForegroundCall();
             boolean hasLiveCall = call != null && call.isAlive();
@@ -150,9 +260,9 @@
             if (hasLiveCall) {
                 // In order of preference when a wireless headset is unplugged.
                 if (mWasSpeakerOn) {
-                    newRoute = AudioState.ROUTE_SPEAKER;
+                    newRoute = CallAudioState.ROUTE_SPEAKER;
                 } else {
-                    newRoute = AudioState.ROUTE_EARPIECE;
+                    newRoute = CallAudioState.ROUTE_EARPIECE;
                 }
 
                 // We don't automatically connect to bluetooth when user unplugs their wired headset
@@ -167,11 +277,32 @@
 
         // We need to call this every time even if we do not change the route because the supported
         // routes changed either to include or not include WIRED_HEADSET.
-        setSystemAudioState(mAudioState.isMuted(), newRoute, calculateSupportedRoutes());
+        setSystemAudioState(mCallAudioState.isMuted(), newRoute, calculateSupportedRoutes());
+    }
+
+    @Override
+    public void onDockChanged(boolean isDocked) {
+        // This can happen even when there are no calls and we don't have focus.
+        if (!hasFocus()) {
+            return;
+        }
+
+        if (isDocked) {
+            // Device just docked, turn to speakerphone. Only do so if the route is currently
+            // earpiece so that we dont switch out of a BT headset or a wired headset.
+            if (mCallAudioState.getRoute() == CallAudioState.ROUTE_EARPIECE) {
+                setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+            }
+        } else {
+            // Device just undocked, remove from speakerphone if possible.
+            if (mCallAudioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
+                setAudioRoute(CallAudioState.ROUTE_WIRED_OR_EARPIECE);
+            }
+        }
     }
 
     void toggleMute() {
-        mute(!mAudioState.isMuted());
+        mute(!mCallAudioState.isMuted());
     }
 
     void mute(boolean shouldMute) {
@@ -182,21 +313,26 @@
         Log.v(this, "mute, shouldMute: %b", shouldMute);
 
         // Don't mute if there are any emergency calls.
-        if (CallsManager.getInstance().hasEmergencyCall()) {
+        if (mCallsManager.hasEmergencyCall()) {
             shouldMute = false;
             Log.v(this, "ignoring mute for emergency call");
         }
 
-        if (mAudioState.isMuted() != shouldMute) {
-            setSystemAudioState(shouldMute, mAudioState.getRoute(),
-                    mAudioState.getSupportedRouteMask());
+        if (mCallAudioState.isMuted() != shouldMute) {
+            // We user CallsManager's foreground call so that we dont ignore ringing calls
+            // for logging purposes
+            Log.event(mCallsManager.getForegroundCall(), Log.Events.MUTE,
+                    shouldMute ? "on" : "off");
+
+            setSystemAudioState(shouldMute, mCallAudioState.getRoute(),
+                    mCallAudioState.getSupportedRouteMask());
         }
     }
 
     /**
      * Changed the audio route, for example from earpiece to speaker phone.
      *
-     * @param route The new audio route to use. See {@link AudioState}.
+     * @param route The new audio route to use. See {@link CallAudioState}.
      */
     void setAudioRoute(int route) {
         // This can happen even when there are no calls and we don't have focus.
@@ -204,31 +340,37 @@
             return;
         }
 
-        Log.v(this, "setAudioRoute, route: %s", AudioState.audioRouteToString(route));
+        Log.v(this, "setAudioRoute, route: %s", CallAudioState.audioRouteToString(route));
 
         // Change ROUTE_WIRED_OR_EARPIECE to a single entry.
-        int newRoute = selectWiredOrEarpiece(route, mAudioState.getSupportedRouteMask());
+        int newRoute = selectWiredOrEarpiece(route, mCallAudioState.getSupportedRouteMask());
 
         // If route is unsupported, do nothing.
-        if ((mAudioState.getSupportedRouteMask() | newRoute) == 0) {
+        if ((mCallAudioState.getSupportedRouteMask() | newRoute) == 0) {
             Log.wtf(this, "Asking to set to a route that is unsupported: %d", newRoute);
             return;
         }
 
-        if (mAudioState.getRoute() != newRoute) {
+        if (mCallAudioState.getRoute() != newRoute) {
             // Remember the new speaker state so it can be restored when the user plugs and unplugs
             // a headset.
-            mWasSpeakerOn = newRoute == AudioState.ROUTE_SPEAKER;
-            setSystemAudioState(mAudioState.isMuted(), newRoute,
-                    mAudioState.getSupportedRouteMask());
+            mWasSpeakerOn = newRoute == CallAudioState.ROUTE_SPEAKER;
+            setSystemAudioState(mCallAudioState.isMuted(), newRoute,
+                    mCallAudioState.getSupportedRouteMask());
         }
     }
 
-    void setIsRinging(boolean isRinging) {
+    /**
+     * Sets the audio stream and mode based on whether a call is ringing.
+     *
+     * @param call The call which changed ringing state.
+     * @param isRinging {@code true} if the call is ringing, {@code false} otherwise.
+     */
+    void setIsRinging(Call call, boolean isRinging) {
         if (mIsRinging != isRinging) {
-            Log.v(this, "setIsRinging %b -> %b", mIsRinging, isRinging);
+            Log.i(this, "setIsRinging %b -> %b (call = %s)", mIsRinging, isRinging, call);
             mIsRinging = isRinging;
-            updateAudioStreamAndMode();
+            updateAudioStreamAndMode(call);
         }
     }
 
@@ -240,8 +382,6 @@
      * @param isPlayingNew The status to set.
      */
     void setIsTonePlaying(boolean isPlayingNew) {
-        ThreadUtil.checkOnMainThread();
-
         if (mIsTonePlaying != isPlayingNew) {
             Log.v(this, "mIsTonePlaying %b -> %b.", mIsTonePlaying, isPlayingNew);
             mIsTonePlaying = isPlayingNew;
@@ -259,16 +399,17 @@
         }
 
         int supportedRoutes = calculateSupportedRoutes();
-        int newRoute = mAudioState.getRoute();
+        int newRoute = mCallAudioState.getRoute();
         if (bluetoothManager.isBluetoothAudioConnectedOrPending()) {
-            newRoute = AudioState.ROUTE_BLUETOOTH;
-        } else if (mAudioState.getRoute() == AudioState.ROUTE_BLUETOOTH) {
-            newRoute = selectWiredOrEarpiece(AudioState.ROUTE_WIRED_OR_EARPIECE, supportedRoutes);
+            newRoute = CallAudioState.ROUTE_BLUETOOTH;
+        } else if (mCallAudioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH) {
+            newRoute = selectWiredOrEarpiece(CallAudioState.ROUTE_WIRED_OR_EARPIECE,
+                    supportedRoutes);
             // Do not switch to speaker when bluetooth disconnects.
             mWasSpeakerOn = false;
         }
 
-        setSystemAudioState(mAudioState.isMuted(), newRoute, supportedRoutes);
+        setSystemAudioState(mCallAudioState.isMuted(), newRoute, supportedRoutes);
     }
 
     boolean isBluetoothAudioOn() {
@@ -279,24 +420,19 @@
         return mBluetoothManager.isBluetoothAvailable();
     }
 
-    private void saveAudioState(AudioState audioState) {
-        mAudioState = audioState;
-        mStatusBarNotifier.notifyMute(mAudioState.isMuted());
-        mStatusBarNotifier.notifySpeakerphone(mAudioState.getRoute() == AudioState.ROUTE_SPEAKER);
+    private void saveAudioState(CallAudioState callAudioState) {
+        mCallAudioState = callAudioState;
+        mStatusBarNotifier.notifyMute(mCallAudioState.isMuted());
+        mStatusBarNotifier.notifySpeakerphone(mCallAudioState.getRoute()
+                == CallAudioState.ROUTE_SPEAKER);
     }
 
     private void onCallUpdated(Call call) {
-        boolean wasNotVoiceCall = mAudioFocusStreamType != AudioManager.STREAM_VOICE_CALL;
-        updateAudioStreamAndMode();
-
+        updateAudioStreamAndMode(call);
         if (call != null && call.getState() == CallState.ACTIVE &&
                             call == mCallToSpeedUpMTAudio) {
             mCallToSpeedUpMTAudio = null;
         }
-        // If we transition from not voice call to voice call, we need to set an initial state.
-        if (wasNotVoiceCall && mAudioFocusStreamType == AudioManager.STREAM_VOICE_CALL) {
-            setInitialAudioState(call, true /* force */);
-        }
     }
 
     private void setSystemAudioState(boolean isMuted, int route, int supportedRouteMask) {
@@ -309,44 +445,44 @@
             return;
         }
 
-        AudioState oldAudioState = mAudioState;
-        saveAudioState(new AudioState(isMuted, route, supportedRouteMask));
-        if (!force && Objects.equals(oldAudioState, mAudioState)) {
+        CallAudioState oldAudioState = mCallAudioState;
+        saveAudioState(new CallAudioState(isMuted, route, supportedRouteMask));
+        if (!force && Objects.equals(oldAudioState, mCallAudioState)) {
             return;
         }
-        Log.i(this, "changing audio state from %s to %s", oldAudioState, mAudioState);
 
-        // Mute.
-        if (mAudioState.isMuted() != mAudioManager.isMicrophoneMute()) {
-            Log.i(this, "changing microphone mute state to: %b", mAudioState.isMuted());
-            mAudioManager.setMicrophoneMute(mAudioState.isMuted());
-        }
+        Log.i(this, "setSystemAudioState: changing from %s to %s", oldAudioState, mCallAudioState);
+        Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
+                CallAudioState.audioRouteToString(mCallAudioState.getRoute()));
+
+        mAudioManagerHandler.obtainMessage(
+                MSG_AUDIO_MANAGER_SET_MICROPHONE_MUTE,
+                mCallAudioState.isMuted() ? 1 : 0,
+                0)
+                .sendToTarget();
 
         // Audio route.
-        if (mAudioState.getRoute() == AudioState.ROUTE_BLUETOOTH) {
+        if (mCallAudioState.getRoute() == CallAudioState.ROUTE_BLUETOOTH) {
             turnOnSpeaker(false);
             turnOnBluetooth(true);
-        } else if (mAudioState.getRoute() == AudioState.ROUTE_SPEAKER) {
+        } else if (mCallAudioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
             turnOnBluetooth(false);
             turnOnSpeaker(true);
-        } else if (mAudioState.getRoute() == AudioState.ROUTE_EARPIECE ||
-                mAudioState.getRoute() == AudioState.ROUTE_WIRED_HEADSET) {
+        } else if (mCallAudioState.getRoute() == CallAudioState.ROUTE_EARPIECE ||
+                mCallAudioState.getRoute() == CallAudioState.ROUTE_WIRED_HEADSET) {
             turnOnBluetooth(false);
             turnOnSpeaker(false);
         }
 
-        if (!oldAudioState.equals(mAudioState)) {
-            CallsManager.getInstance().onAudioStateChanged(oldAudioState, mAudioState);
+        if (!oldAudioState.equals(mCallAudioState)) {
+            mCallsManager.onCallAudioStateChanged(oldAudioState, mCallAudioState);
             updateAudioForForegroundCall();
         }
     }
 
     private void turnOnSpeaker(boolean on) {
-        // Wired headset and earpiece work the same way
-        if (mAudioManager.isSpeakerphoneOn() != on) {
-            Log.i(this, "turning speaker phone %s", on);
-            mAudioManager.setSpeakerphoneOn(on);
-        }
+        mAudioManagerHandler.obtainMessage(MSG_AUDIO_MANAGER_TURN_ON_SPEAKER, on ? 1 : 0, 0)
+                .sendToTarget();
     }
 
     private void turnOnBluetooth(boolean on) {
@@ -364,16 +500,24 @@
     }
 
     private void updateAudioStreamAndMode() {
-        Log.i(this, "updateAudioStreamAndMode, mIsRinging: %b, mIsTonePlaying: %b", mIsRinging,
-                mIsTonePlaying);
+        updateAudioStreamAndMode(null /* call */);
+    }
+
+    private void updateAudioStreamAndMode(Call callToUpdate) {
+        Log.i(this, "updateAudioStreamAndMode :  mIsRinging: %b, mIsTonePlaying: %b, call: %s",
+                mIsRinging, mIsTonePlaying, callToUpdate);
+
+        boolean wasVoiceCall = mAudioFocusStreamType == AudioManager.STREAM_VOICE_CALL;
         if (mIsRinging) {
+            Log.i(this, "updateAudioStreamAndMode : ringing");
             requestAudioFocusAndSetMode(AudioManager.STREAM_RING, AudioManager.MODE_RINGTONE);
         } else {
             Call foregroundCall = getForegroundCall();
-            Call waitingForAccountSelectionCall =
-                    CallsManager.getInstance().getFirstCallWithState(CallState.PRE_DIAL_WAIT);
-            Call call = CallsManager.getInstance().getForegroundCall();
+            Call waitingForAccountSelectionCall = mCallsManager
+                    .getFirstCallWithState(CallState.SELECT_PHONE_ACCOUNT);
+            Call call = mCallsManager.getForegroundCall();
             if (foregroundCall == null && call != null && call == mCallToSpeedUpMTAudio) {
+                Log.v(this, "updateAudioStreamAndMode : no foreground, speeding up MT audio.");
                 requestAudioFocusAndSetMode(AudioManager.STREAM_VOICE_CALL,
                                                          AudioManager.MODE_IN_CALL);
             } else if (foregroundCall != null && waitingForAccountSelectionCall == null) {
@@ -385,14 +529,17 @@
                 // audio mode when this method (updateAudioStreamAndMode) is called again.
                 int mode = foregroundCall.getIsVoipAudioMode() ?
                         AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_IN_CALL;
+                Log.v(this, "updateAudioStreamAndMode : foreground");
                 requestAudioFocusAndSetMode(AudioManager.STREAM_VOICE_CALL, mode);
             } else if (mIsTonePlaying) {
                 // There is no call, however, we are still playing a tone, so keep focus.
                 // Since there is no call from which to determine the mode, use the most
                 // recently used mode instead.
+                Log.v(this, "updateAudioStreamAndMode : tone playing");
                 requestAudioFocusAndSetMode(
                         AudioManager.STREAM_VOICE_CALL, mMostRecentlyUsedMode);
             } else if (!hasRingingForegroundCall()) {
+                Log.v(this, "updateAudioStreamAndMode : no ringing call");
                 abandonAudioFocus();
             } else {
                 // mIsRinging is false, but there is a foreground ringing call present. Don't
@@ -402,19 +549,32 @@
                 // focus will be correctly abandoned by the if clause above.
             }
         }
+
+        boolean isVoiceCall = mAudioFocusStreamType == AudioManager.STREAM_VOICE_CALL;
+
+        // If we transition from not a voice call to a voice call, we need to set an initial audio
+        // state for the call.
+        if (!wasVoiceCall && isVoiceCall) {
+            setInitialAudioState(callToUpdate, true /* force */);
+        }
     }
 
     private void requestAudioFocusAndSetMode(int stream, int mode) {
-        Log.i(this, "requestAudioFocusAndSetMode, stream: %d -> %d, mode: %d",
-                mAudioFocusStreamType, stream, mode);
+        Log.v(this, "requestAudioFocusAndSetMode : stream: %s -> %s, mode: %s",
+                streamTypeToString(mAudioFocusStreamType), streamTypeToString(stream),
+                modeToString(mode));
         Preconditions.checkState(stream != STREAM_NONE);
 
         // Even if we already have focus, if the stream is different we update audio manager to give
         // it a hint about the purpose of our focus.
         if (mAudioFocusStreamType != stream) {
-            Log.v(this, "requesting audio focus for stream: %d", stream);
-            mAudioManager.requestAudioFocusForCall(stream,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+            Log.i(this, "requestAudioFocusAndSetMode : requesting stream: %s -> %s",
+                    streamTypeToString(mAudioFocusStreamType), streamTypeToString(stream));
+            mAudioManagerHandler.obtainMessage(
+                    MSG_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS_FOR_CALL,
+                    stream,
+                    0)
+                    .sendToTarget();
         }
         mAudioFocusStreamType = stream;
 
@@ -425,7 +585,8 @@
         if (hasFocus()) {
             setMode(AudioManager.MODE_NORMAL);
             Log.v(this, "abandoning audio focus");
-            mAudioManager.abandonAudioFocusForCall();
+            mAudioManagerHandler.obtainMessage(MSG_AUDIO_MANAGER_ABANDON_AUDIO_FOCUS_FOR_CALL, 0, 0)
+                    .sendToTarget();
             mAudioFocusStreamType = STREAM_NONE;
             mCallToSpeedUpMTAudio = null;
         }
@@ -438,54 +599,44 @@
      */
     private void setMode(int newMode) {
         Preconditions.checkState(hasFocus());
-        int oldMode = mAudioManager.getMode();
-        Log.v(this, "Request to change audio mode from %d to %d", oldMode, newMode);
-
-        if (oldMode != newMode) {
-            if (oldMode == AudioManager.MODE_IN_CALL && newMode == AudioManager.MODE_RINGTONE) {
-                Log.i(this, "Transition from IN_CALL -> RINGTONE. Resetting to NORMAL first.");
-                mAudioManager.setMode(AudioManager.MODE_NORMAL);
-            }
-            mAudioManager.setMode(newMode);
-            mMostRecentlyUsedMode = newMode;
-        }
+        mAudioManagerHandler.obtainMessage(MSG_AUDIO_MANAGER_SET_MODE, newMode, 0).sendToTarget();
     }
 
     private int selectWiredOrEarpiece(int route, int supportedRouteMask) {
         // Since they are mutually exclusive and one is ALWAYS valid, we allow a special input of
         // ROUTE_WIRED_OR_EARPIECE so that callers dont have to make a call to check which is
         // supported before calling setAudioRoute.
-        if (route == AudioState.ROUTE_WIRED_OR_EARPIECE) {
-            route = AudioState.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
+        if (route == CallAudioState.ROUTE_WIRED_OR_EARPIECE) {
+            route = CallAudioState.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
             if (route == 0) {
                 Log.wtf(this, "One of wired headset or earpiece should always be valid.");
                 // assume earpiece in this case.
-                route = AudioState.ROUTE_EARPIECE;
+                route = CallAudioState.ROUTE_EARPIECE;
             }
         }
         return route;
     }
 
     private int calculateSupportedRoutes() {
-        int routeMask = AudioState.ROUTE_SPEAKER;
+        int routeMask = CallAudioState.ROUTE_SPEAKER;
 
         if (mWiredHeadsetManager.isPluggedIn()) {
-            routeMask |= AudioState.ROUTE_WIRED_HEADSET;
+            routeMask |= CallAudioState.ROUTE_WIRED_HEADSET;
         } else {
-            routeMask |= AudioState.ROUTE_EARPIECE;
+            routeMask |= CallAudioState.ROUTE_EARPIECE;
         }
 
         if (mBluetoothManager.isBluetoothAvailable()) {
-            routeMask |=  AudioState.ROUTE_BLUETOOTH;
+            routeMask |=  CallAudioState.ROUTE_BLUETOOTH;
         }
 
         return routeMask;
     }
 
-    private AudioState getInitialAudioState(Call call) {
+    private CallAudioState getInitialAudioState(Call call) {
         int supportedRouteMask = calculateSupportedRoutes();
         int route = selectWiredOrEarpiece(
-                AudioState.ROUTE_WIRED_OR_EARPIECE, supportedRouteMask);
+                CallAudioState.ROUTE_WIRED_OR_EARPIECE, supportedRouteMask);
 
         // We want the UI to indicate that "bluetooth is in use" in two slightly different cases:
         // (a) The obvious case: if a bluetooth headset is currently in use for an ongoing call.
@@ -500,28 +651,28 @@
                 case CallState.DIALING:
                 case CallState.CONNECTING:
                 case CallState.RINGING:
-                    route = AudioState.ROUTE_BLUETOOTH;
+                    route = CallAudioState.ROUTE_BLUETOOTH;
                     break;
                 default:
                     break;
             }
         }
 
-        return new AudioState(false, route, supportedRouteMask);
+        return new CallAudioState(false, route, supportedRouteMask);
     }
 
     private void setInitialAudioState(Call call, boolean force) {
-        AudioState audioState = getInitialAudioState(call);
-        Log.v(this, "setInitialAudioState %s, %s", audioState, call);
+        CallAudioState audioState = getInitialAudioState(call);
+        Log.i(this, "setInitialAudioState : audioState = %s, call = %s", audioState, call);
         setSystemAudioState(
                 force, audioState.isMuted(), audioState.getRoute(),
                 audioState.getSupportedRouteMask());
     }
 
     private void updateAudioForForegroundCall() {
-        Call call = CallsManager.getInstance().getForegroundCall();
+        Call call = mCallsManager.getForegroundCall();
         if (call != null && call.getConnectionService() != null) {
-            call.getConnectionService().onAudioStateChanged(call, mAudioState);
+            call.getConnectionService().onCallAudioStateChanged(call, mCallAudioState);
         }
     }
 
@@ -529,7 +680,7 @@
      * Returns the current foreground call in order to properly set the audio mode.
      */
     private Call getForegroundCall() {
-        Call call = CallsManager.getInstance().getForegroundCall();
+        Call call = mCallsManager.getForegroundCall();
 
         // We ignore any foreground call that is in the ringing state because we deal with ringing
         // calls exclusively through the mIsRinging variable set by {@link Ringer}.
@@ -541,7 +692,7 @@
     }
 
     private boolean hasRingingForegroundCall() {
-        Call call = CallsManager.getInstance().getForegroundCall();
+        Call call = mCallsManager.getForegroundCall();
         return call != null && call.getState() == CallState.RINGING;
     }
 
@@ -550,12 +701,68 @@
     }
 
     /**
+     * Translates an {@link AudioManager} stream type to a human-readable string description.
+     *
+     * @param streamType The stream type.
+     * @return Human readable description.
+     */
+    private String streamTypeToString(int streamType) {
+        switch (streamType) {
+            case STREAM_NONE:
+                return STREAM_DESCRIPTION_NONE;
+            case AudioManager.STREAM_ALARM:
+                return STREAM_DESCRIPTION_ALARM;
+            case AudioManager.STREAM_BLUETOOTH_SCO:
+                return STREAM_DESCRIPTION_BLUETOOTH_SCO;
+            case AudioManager.STREAM_DTMF:
+                return STREAM_DESCRIPTION_DTMF;
+            case AudioManager.STREAM_MUSIC:
+                return STREAM_DESCRIPTION_MUSIC;
+            case AudioManager.STREAM_NOTIFICATION:
+                return STREAM_DESCRIPTION_NOTIFICATION;
+            case AudioManager.STREAM_RING:
+                return STREAM_DESCRIPTION_RING;
+            case AudioManager.STREAM_SYSTEM:
+                return STREAM_DESCRIPTION_SYSTEM;
+            case AudioManager.STREAM_VOICE_CALL:
+                return STREAM_DESCRIPTION_VOICE_CALL;
+            default:
+                return "STEAM_OTHER_" + streamType;
+        }
+    }
+
+    /**
+     * Translates an {@link AudioManager} mode into a human readable string.
+     *
+     * @param mode The mode.
+     * @return The string.
+     */
+    private String modeToString(int mode) {
+        switch (mode) {
+            case AudioManager.MODE_INVALID:
+                return MODE_DESCRIPTION_INVALID;
+            case AudioManager.MODE_CURRENT:
+                return MODE_DESCRIPTION_CURRENT;
+            case AudioManager.MODE_NORMAL:
+                return MODE_DESCRIPTION_NORMAL;
+            case AudioManager.MODE_RINGTONE:
+                return MODE_DESCRIPTION_RINGTONE;
+            case AudioManager.MODE_IN_CALL:
+                return MODE_DESCRIPTION_IN_CALL;
+            case AudioManager.MODE_IN_COMMUNICATION:
+                return MODE_DESCRIPTION_IN_COMMUNICATION;
+            default:
+                return "MODE_OTHER_" + mode;
+        }
+    }
+
+    /**
      * Dumps the state of the {@link CallAudioManager}.
      *
      * @param pw The {@code IndentingPrintWriter} to write the state to.
      */
     public void dump(IndentingPrintWriter pw) {
-        pw.println("mAudioState: " + mAudioState);
+        pw.println("mAudioState: " + mCallAudioState);
         pw.println("mBluetoothManager:");
         pw.increaseIndent();
         mBluetoothManager.dump(pw);
@@ -568,10 +775,10 @@
         } else {
             pw.println("mWiredHeadsetManager: null");
         }
-        pw.println("mAudioFocusStreamType: " + mAudioFocusStreamType);
+        pw.println("mAudioFocusStreamType: " + streamTypeToString(mAudioFocusStreamType));
         pw.println("mIsRinging: " + mIsRinging);
         pw.println("mIsTonePlaying: " + mIsTonePlaying);
         pw.println("mWasSpeakerOn: " + mWasSpeakerOn);
-        pw.println("mMostRecentlyUsedMode: " + mMostRecentlyUsedMode);
+        pw.println("mMostRecentlyUsedMode: " + modeToString(mMostRecentlyUsedMode));
     }
 }
diff --git a/src/com/android/server/telecom/CallIdMapper.java b/src/com/android/server/telecom/CallIdMapper.java
index 729db0a..8199dfa 100644
--- a/src/com/android/server/telecom/CallIdMapper.java
+++ b/src/com/android/server/telecom/CallIdMapper.java
@@ -79,13 +79,10 @@
     private static int sIdCount;
 
     CallIdMapper(String callIdPrefix) {
-        ThreadUtil.checkOnMainThread();
         mCallIdPrefix = callIdPrefix + "@";
     }
 
     void replaceCall(Call newCall, Call callToReplace) {
-        ThreadUtil.checkOnMainThread();
-
         // Use the old call's ID for the new call.
         String callId = getCallId(callToReplace);
         mCalls.put(callId, newCall);
@@ -95,12 +92,10 @@
         if (call == null) {
             return;
         }
-        ThreadUtil.checkOnMainThread();
         mCalls.put(id, call);
     }
 
     void addCall(Call call) {
-        ThreadUtil.checkOnMainThread();
         addCall(call, getNewId());
     }
 
@@ -108,12 +103,10 @@
         if (call == null) {
             return;
         }
-        ThreadUtil.checkOnMainThread();
         mCalls.removeValue(call);
     }
 
     void removeCall(String callId) {
-        ThreadUtil.checkOnMainThread();
         mCalls.remove(callId);
     }
 
@@ -121,13 +114,10 @@
         if (call == null) {
             return null;
         }
-        ThreadUtil.checkOnMainThread();
         return mCalls.getKey(call);
     }
 
     Call getCall(Object objId) {
-        ThreadUtil.checkOnMainThread();
-
         String callId = null;
         if (objId instanceof String) {
             callId = (String) objId;
diff --git a/src/com/android/server/telecom/CallReceiver.java b/src/com/android/server/telecom/CallIntentProcessor.java
similarity index 62%
rename from src/com/android/server/telecom/CallReceiver.java
rename to src/com/android/server/telecom/CallIntentProcessor.java
index bdae582..cfec90c 100644
--- a/src/com/android/server/telecom/CallReceiver.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -1,6 +1,7 @@
 package com.android.server.telecom;
 
-import android.content.BroadcastReceiver;
+import com.android.server.telecom.components.ErrorDialogActivity;
+
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -16,40 +17,53 @@
 import android.widget.Toast;
 
 /**
- * Single point of entry for all outgoing and incoming calls. {@link CallActivity} serves as a
- * trampoline activity that captures call intents for individual users and forwards it to
- * the {@link CallReceiver} which interacts with the rest of Telecom, both of which run only as
- * the primary user.
+ * Single point of entry for all outgoing and incoming calls.
+ * {@link com.android.server.telecom.components.UserCallIntentProcessor} serves as a trampoline that
+ * captures call intents for individual users and forwards it to the {@link CallIntentProcessor}
+ * which interacts with the rest of Telecom, both of which run only as the primary user.
  */
-public class CallReceiver extends BroadcastReceiver {
-    private static final String TAG = CallReceiver.class.getName();
+public class CallIntentProcessor {
 
-    static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call";
-    static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
-    static final String KEY_IS_DEFAULT_DIALER =
-            "is_default_dialer";
+    public static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call";
+    public static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
+    /*
+     *  Whether or not the dialer initiating this outgoing call is the default dialer, or system
+     *  dialer and thus allowed to make emergency calls.
+     */
+    public static final String KEY_IS_PRIVILEGED_DIALER = "is_privileged_dialer";
 
-    @Override
-    public void onReceive(Context context, Intent intent) {
+    private final Context mContext;
+    private final CallsManager mCallsManager;
+
+    public CallIntentProcessor(Context context, CallsManager callsManager) {
+        this.mContext = context;
+        this.mCallsManager = callsManager;
+    }
+
+    public void processIntent(Intent intent) {
         final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
         Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
 
         Trace.beginSection("processNewCallCallIntent");
         if (isUnknownCall) {
-            processUnknownCallIntent(intent);
+            processUnknownCallIntent(mCallsManager, intent);
         } else {
-            processOutgoingCallIntent(context, intent);
+            processOutgoingCallIntent(mContext, mCallsManager, intent);
         }
         Trace.endSection();
     }
 
+
     /**
      * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
      *
      * @param intent Call intent containing data about the handle to call.
      */
-    static void processOutgoingCallIntent(Context context, Intent intent) {
-        if (shouldPreventDuplicateVideoCall(context, intent)) {
+    static void processOutgoingCallIntent(
+            Context context,
+            CallsManager callsManager,
+            Intent intent) {
+        if (shouldPreventDuplicateVideoCall(context, callsManager, intent)) {
             return;
         }
 
@@ -73,10 +87,10 @@
             clientExtras = new Bundle();
         }
 
-        final boolean isDefaultDialer = intent.getBooleanExtra(KEY_IS_DEFAULT_DIALER, false);
+        final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
 
         // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
-        Call call = getCallsManager().startOutgoingCall(handle, phoneAccountHandle, clientExtras);
+        Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);
 
         if (call != null) {
             // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
@@ -85,7 +99,7 @@
             // process will be running throughout the duration of the phone call and should never
             // be killed.
             NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
-                    context, getCallsManager(), call, intent, isDefaultDialer);
+                    context, callsManager, call, intent, isPrivilegedDialer);
             final int result = broadcaster.processIntent();
             final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
 
@@ -95,16 +109,18 @@
         }
     }
 
-    static void processIncomingCallIntent(Intent intent) {
+    static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
         PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
                 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
 
         if (phoneAccountHandle == null) {
-            Log.w(TAG, "Rejecting incoming call due to null phone account");
+            Log.w(CallIntentProcessor.class,
+                    "Rejecting incoming call due to null phone account");
             return;
         }
         if (phoneAccountHandle.getComponentName() == null) {
-            Log.w(TAG, "Rejecting incoming call due to null component name");
+            Log.w(CallIntentProcessor.class,
+                    "Rejecting incoming call due to null component name");
             return;
         }
 
@@ -116,29 +132,26 @@
             clientExtras = new Bundle();
         }
 
-        Log.d(TAG, "Processing incoming call from connection service [%s]",
+        Log.d(CallIntentProcessor.class,
+                "Processing incoming call from connection service [%s]",
                 phoneAccountHandle.getComponentName());
-        getCallsManager().processIncomingCallIntent(phoneAccountHandle, clientExtras);
+        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
     }
 
-    private void processUnknownCallIntent(Intent intent) {
+    static void processUnknownCallIntent(CallsManager callsManager, Intent intent) {
         PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
                 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
 
         if (phoneAccountHandle == null) {
-            Log.w(this, "Rejecting unknown call due to null phone account");
+            Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null phone account");
             return;
         }
         if (phoneAccountHandle.getComponentName() == null) {
-            Log.w(this, "Rejecting unknown call due to null component name");
+            Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null component name");
             return;
         }
 
-        getCallsManager().addNewUnknownCall(phoneAccountHandle, intent.getExtras());
-    }
-
-    static CallsManager getCallsManager() {
-        return CallsManager.getInstance();
+        callsManager.addNewUnknownCall(phoneAccountHandle, intent.getExtras());
     }
 
     private static void disconnectCallAndShowErrorDialog(
@@ -154,9 +167,9 @@
         }
         if (errorMessageId != -1) {
             errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId);
+            errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            context.startActivityAsUser(errorIntent, UserHandle.CURRENT);
         }
-        errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivityAsUser(errorIntent, UserHandle.CURRENT);
     }
 
     /**
@@ -167,11 +180,14 @@
      * @return {@code true} if the outgoing call is a video call and should be prevented from going
      *     out, {@code false} otherwise.
      */
-    private static boolean shouldPreventDuplicateVideoCall(Context context, Intent intent) {
+    private static boolean shouldPreventDuplicateVideoCall(
+            Context context,
+            CallsManager callsManager,
+            Intent intent) {
         int intentVideoState = intent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
-                VideoProfile.VideoState.AUDIO_ONLY);
-        if (intentVideoState == VideoProfile.VideoState.AUDIO_ONLY
-                || !getCallsManager().hasVideoCall()) {
+                VideoProfile.STATE_AUDIO_ONLY);
+        if (VideoProfile.isAudioOnly(intentVideoState)
+                || !callsManager.hasVideoCall()) {
             return false;
         } else {
             // Display an error toast to the user.
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 781f2b1..2007f6e 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -18,11 +18,9 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.Manifest.permission;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.provider.CallLog.Calls;
-import android.telecom.CallState;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.VideoProfile;
@@ -30,7 +28,6 @@
 
 // TODO: Needed for move to system service: import com.android.internal.R;
 import com.android.internal.telephony.CallerInfo;
-import com.android.internal.telephony.PhoneConstants;
 
 /**
  * Helper class that provides functionality to write information about calls and their associated
@@ -108,7 +105,7 @@
         // 2) It is a conference call
         // 3) Call was not explicitly canceled
         if (isNewlyDisconnected &&
-                (oldState != CallState.PRE_DIAL_WAIT &&
+                (oldState != CallState.SELECT_PHONE_ACCOUNT &&
                  !call.isConference() &&
                  !isCallCanceled)) {
             int type;
@@ -140,7 +137,13 @@
 
         Log.d(TAG, "logNumber set to: %s", Log.pii(logNumber));
 
-        final PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
+        final PhoneAccountHandle emergencyAccountHandle =
+                TelephonyUtil.getDefaultEmergencyPhoneAccount().getAccountHandle();
+
+        PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
+        if (emergencyAccountHandle.equals(accountHandle)) {
+            accountHandle = null;
+        }
 
         // TODO(vt): Once data usage is available, wire it up here.
         int callFeatures = getCallFeatures(call.getVideoStateHistory());
@@ -202,8 +205,7 @@
      * @return The call features.
      */
     private static int getCallFeatures(int videoState) {
-        if ((videoState & VideoProfile.VideoState.TX_ENABLED)
-                == VideoProfile.VideoState.TX_ENABLED) {
+        if (VideoProfile.isVideo(videoState)) {
             return Calls.FEATURES_VIDEO;
         }
         return 0;
diff --git a/src/com/android/server/telecom/CallState.java b/src/com/android/server/telecom/CallState.java
new file mode 100644
index 0000000..0d2ca48
--- /dev/null
+++ b/src/com/android/server/telecom/CallState.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014, 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 call-state constants of the different states in which a call can exist. Although states
+ * have the notion of normal transitions, due to the volatile nature of telephony systems, code
+ * that uses these states should be resilient to unexpected state changes outside of what is
+ * considered traditional.
+ */
+public final class CallState {
+
+    private CallState() {}
+
+    /**
+     * Indicates that a call is new and not connected. This is used as the default state internally
+     * within Telecom and should not be used between Telecom and call services. Call services are
+     * not expected to ever interact with NEW calls, but {@link android.telecom.InCallService}s will
+     * see calls in this state.
+     */
+    public static final int NEW = 0;
+
+    /**
+     * The initial state of an outgoing {@code Call}.
+     * Common transitions are to {@link #DIALING} state for a successful call or
+     * {@link #DISCONNECTED} if it failed.
+     */
+    public static final int CONNECTING = 1;
+
+    /**
+     * The state of an outgoing {@code Call} when waiting on user to select a
+     * {@link android.telecom.PhoneAccount} through which to place the call.
+     */
+    public static final int SELECT_PHONE_ACCOUNT = 2;
+
+    /**
+     * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+     * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+     * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+     * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+     */
+    public static final int DIALING = 3;
+
+    /**
+     * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+     * or doing nothing with the call. This state is usually associated with some type of audible
+     * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+     * otherwise.
+     */
+    public static final int RINGING = 4;
+
+    /**
+     * Indicates that a call is currently connected to another party and a communication channel is
+     * open between them. The normal transition to this state is by the user answering a
+     * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+     */
+    public static final int ACTIVE = 5;
+
+    /**
+     * Indicates that the call is currently on hold. In this state, the call is not terminated
+     * but no communication is allowed until the call is no longer on hold. The typical transition
+     * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+     * an action, such as clicking the hold button.
+     */
+    public static final int ON_HOLD = 6;
+
+    /**
+     * Indicates that a call is currently disconnected. All states can transition to this state
+     * by the call service giving notice that the connection has been severed. When the user
+     * explicitly ends a call, it will not transition to this state until the call service confirms
+     * the disconnection or communication was lost to the call service currently responsible for
+     * this call (e.g., call service crashes).
+     */
+    public static final int DISCONNECTED = 7;
+
+    /**
+     * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+     * time of writing) but cancelled before it was successfully connected.
+     */
+    public static final int ABORTED = 8;
+
+    /**
+     * Indicates that the call is in the process of being disconnected and will transition next
+     * to a {@link #DISCONNECTED} state.
+     * <p>
+     * This state is not expected to be communicated from the Telephony layer, but will be reported
+     * to the InCall UI for calls where disconnection has been initiated by the user but the
+     * ConnectionService has confirmed the call as disconnected.
+     */
+    public static final int DISCONNECTING = 9;
+
+    public static String toString(int callState) {
+        switch (callState) {
+            case NEW:
+                return "NEW";
+            case CONNECTING:
+                return "CONNECTING";
+            case SELECT_PHONE_ACCOUNT:
+                return "SELECT_PHONE_ACCOUNT";
+            case DIALING:
+                return "DIALING";
+            case RINGING:
+                return "RINGING";
+            case ACTIVE:
+                return "ACTIVE";
+            case ON_HOLD:
+                return "ON_HOLD";
+            case DISCONNECTED:
+                return "DISCONNECTED";
+            case ABORTED:
+                return "ABORTED";
+            case DISCONNECTING:
+                return "DISCONNECTING";
+            default:
+                return "UNKNOWN";
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/CallerInfoAsyncQueryFactory.java b/src/com/android/server/telecom/CallerInfoAsyncQueryFactory.java
new file mode 100644
index 0000000..149470f
--- /dev/null
+++ b/src/com/android/server/telecom/CallerInfoAsyncQueryFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */package com.android.server.telecom;
+
+import com.android.internal.telephony.CallerInfoAsyncQuery;
+
+import android.content.Context;
+
+public interface CallerInfoAsyncQueryFactory {
+    CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie);
+}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 71281b3..346fbea 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -20,11 +20,12 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.provider.CallLog.Calls;
 import android.provider.Settings;
-import android.telecom.AudioState;
-import android.telecom.CallState;
+import android.telecom.CallAudioState;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
@@ -37,7 +38,11 @@
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.util.Collection;
@@ -55,7 +60,8 @@
  * access from other packages specifically refraining from passing the CallsManager instance
  * beyond the com.android.server.telecom package boundary.
  */
-public final class CallsManager extends Call.ListenerBase {
+@VisibleForTesting
+public class CallsManager extends Call.ListenerBase implements VideoProviderProxy.Listener {
 
     // TODO: Consider renaming this CallsManagerPlugin.
     interface CallsManagerListener {
@@ -69,19 +75,15 @@
         void onIncomingCallAnswered(Call call);
         void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage);
         void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall);
-        void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState);
+        void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
         void onRingbackRequested(Call call, boolean ringback);
         void onIsConferencedChanged(Call call);
         void onIsVoipAudioModeChanged(Call call);
         void onVideoStateChanged(Call call);
         void onCanAddCallChanged(boolean canAddCall);
+        void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
     }
 
-    /**
-     * Singleton instance of the {@link CallsManager}, initialized from {@link TelecomService}.
-     */
-    private static CallsManager sInstance = null;
-
     private static final String TAG = "CallsManager";
 
     private static final int MAXIMUM_LIVE_CALLS = 1;
@@ -91,10 +93,10 @@
     private static final int MAXIMUM_TOP_LEVEL_CALLS = 2;
 
     private static final int[] OUTGOING_CALL_STATES =
-            {CallState.CONNECTING, CallState.PRE_DIAL_WAIT, CallState.DIALING};
+            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING};
 
     private static final int[] LIVE_CALL_STATES =
-            {CallState.CONNECTING, CallState.PRE_DIAL_WAIT, CallState.DIALING, CallState.ACTIVE};
+            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.ACTIVE};
 
     /**
      * The main call repository. Keeps an instance of all live calls. New incoming and outgoing
@@ -111,6 +113,7 @@
     private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
     private final InCallController mInCallController;
     private final CallAudioManager mCallAudioManager;
+    private RespondViaSmsManager mRespondViaSmsManager;
     private final Ringer mRinger;
     private final InCallWakeLockController mInCallWakeLockController;
     // For this set initial table size to 16 because we add 13 listeners in
@@ -119,17 +122,21 @@
             new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));
     private final HeadsetMediaButton mHeadsetMediaButton;
     private final WiredHeadsetManager mWiredHeadsetManager;
+    private final DockManager mDockManager;
     private final TtyManager mTtyManager;
     private final ProximitySensorManager mProximitySensorManager;
     private final PhoneStateBroadcaster mPhoneStateBroadcaster;
     private final CallLogManager mCallLogManager;
     private final Context mContext;
+    private final TelecomSystem.SyncRoot mLock;
+    private final ContactsAsyncHelper mContactsAsyncHelper;
+    private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final MissedCallNotifier mMissedCallNotifier;
     private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
     private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
     /* Handler tied to thread in which CallManager was initialized. */
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
 
     private boolean mCanAddCall = true;
 
@@ -141,43 +148,42 @@
 
     private Runnable mStopTone;
 
-    /** Singleton accessor. */
-    static CallsManager getInstance() {
-        return sInstance;
-    }
-
-    /**
-     * Sets the static singleton instance.
-     *
-     * @param instance The instance to set.
-     */
-    static void initialize(CallsManager instance) {
-        sInstance = instance;
-    }
-
     /**
      * Initializes the required Telecom components.
      */
-     CallsManager(Context context, MissedCallNotifier missedCallNotifier,
-             PhoneAccountRegistrar phoneAccountRegistrar) {
+    CallsManager(
+            Context context,
+            TelecomSystem.SyncRoot lock,
+            ContactsAsyncHelper contactsAsyncHelper,
+            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
+            MissedCallNotifier missedCallNotifier,
+            PhoneAccountRegistrar phoneAccountRegistrar,
+            HeadsetMediaButtonFactory headsetMediaButtonFactory,
+            ProximitySensorManagerFactory proximitySensorManagerFactory,
+            InCallWakeLockControllerFactory inCallWakeLockControllerFactory) {
         mContext = context;
+        mLock = lock;
+        mContactsAsyncHelper = contactsAsyncHelper;
+        mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mMissedCallNotifier = missedCallNotifier;
         StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
         mWiredHeadsetManager = new WiredHeadsetManager(context);
-        mCallAudioManager = new CallAudioManager(context, statusBarNotifier, mWiredHeadsetManager);
-        InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(mCallAudioManager);
+        mDockManager = new DockManager(context);
+        mCallAudioManager = new CallAudioManager(
+                context, mLock, statusBarNotifier, mWiredHeadsetManager, mDockManager, this);
+        InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(mCallAudioManager, lock);
         mRinger = new Ringer(mCallAudioManager, this, playerFactory, context);
-        mHeadsetMediaButton = new HeadsetMediaButton(context, this);
+        mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock);
         mTtyManager = new TtyManager(context, mWiredHeadsetManager);
-        mProximitySensorManager = new ProximitySensorManager(context);
-        mPhoneStateBroadcaster = new PhoneStateBroadcaster();
+        mProximitySensorManager = proximitySensorManagerFactory.create(context, this);
+        mPhoneStateBroadcaster = new PhoneStateBroadcaster(this);
         mCallLogManager = new CallLogManager(context);
-        mInCallController = new InCallController(context);
+        mInCallController = new InCallController(context, mLock, this);
         mDtmfLocalTonePlayer = new DtmfLocalTonePlayer(context);
-        mConnectionServiceRepository = new ConnectionServiceRepository(mPhoneAccountRegistrar,
-                context);
-        mInCallWakeLockController = new InCallWakeLockController(context, this);
+        mConnectionServiceRepository =
+                new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);
+        mInCallWakeLockController = inCallWakeLockControllerFactory.create(context, this);
 
         mListeners.add(statusBarNotifier);
         mListeners.add(mCallLogManager);
@@ -190,15 +196,29 @@
         mListeners.add(missedCallNotifier);
         mListeners.add(mDtmfLocalTonePlayer);
         mListeners.add(mHeadsetMediaButton);
-        mListeners.add(RespondViaSmsManager.getInstance());
         mListeners.add(mProximitySensorManager);
+
+        mMissedCallNotifier.updateOnStartup(
+                mLock, this, mContactsAsyncHelper, mCallerInfoAsyncQueryFactory);
+    }
+
+    public void setRespondViaSmsManager(RespondViaSmsManager respondViaSmsManager) {
+        if (mRespondViaSmsManager != null) {
+            mListeners.remove(mRespondViaSmsManager);
+        }
+        mRespondViaSmsManager = respondViaSmsManager;
+        mListeners.add(respondViaSmsManager);
+    }
+
+    public RespondViaSmsManager getRespondViaSmsManager() {
+        return mRespondViaSmsManager;
     }
 
     @Override
     public void onSuccessfulOutgoingCall(Call call, int callState) {
         Log.v(this, "onSuccessfulOutgoingCall, %s", call);
 
-        setCallState(call, callState);
+        setCallState(call, callState, "successful outgoing call");
         if (!mCalls.contains(call)) {
             // Call was not added previously in startOutgoingCall due to it being a potential MMI
             // code, so add it now.
@@ -223,7 +243,7 @@
     @Override
     public void onSuccessfulIncomingCall(Call incomingCall) {
         Log.d(this, "onSuccessfulIncomingCall");
-        setCallState(incomingCall, CallState.RINGING);
+        setCallState(incomingCall, CallState.RINGING, "successful incoming call");
 
         if (hasMaximumRingingCalls()) {
             incomingCall.reject(false, null);
@@ -238,13 +258,13 @@
 
     @Override
     public void onFailedIncomingCall(Call call) {
-        setCallState(call, CallState.DISCONNECTED);
+        setCallState(call, CallState.DISCONNECTED, "failed incoming call");
         call.removeListener(this);
     }
 
     @Override
     public void onSuccessfulUnknownCall(Call call, int callState) {
-        setCallState(call, callState);
+        setCallState(call, callState, "successful unknown call");
         Log.i(this, "onSuccessfulUnknownCall for call %s", call);
         addCall(call);
     }
@@ -252,7 +272,7 @@
     @Override
     public void onFailedUnknownCall(Call call) {
         Log.i(this, "onFailedUnknownCall for call %s", call);
-        setCallState(call, CallState.DISCONNECTED);
+        setCallState(call, CallState.DISCONNECTED, "failed unknown call");
         call.removeListener(this);
     }
 
@@ -279,11 +299,14 @@
 
             mDtmfLocalTonePlayer.playTone(call, nextChar);
 
+            // TODO: Create a LockedRunnable class that does the synchronization automatically.
             mStopTone = new Runnable() {
                 @Override
                 public void run() {
-                    // Set a timeout to stop the tone in case there isn't another tone to follow.
-                    mDtmfLocalTonePlayer.stopTone(call);
+                    synchronized (mLock) {
+                        // Set a timeout to stop the tone in case there isn't another tone to follow.
+                        mDtmfLocalTonePlayer.stopTone(call);
+                    }
                 }
             };
             mHandler.postDelayed(
@@ -340,9 +363,11 @@
         mHandler.postDelayed(new Runnable() {
             @Override
             public void run() {
-                if (mPendingCallsToDisconnect.remove(call)) {
-                    Log.i(this, "Delayed disconnection of call: %s", call);
-                    call.disconnect();
+                synchronized (mLock) {
+                    if (mPendingCallsToDisconnect.remove(call)) {
+                        Log.i(this, "Delayed disconnection of call: %s", call);
+                        call.disconnect();
+                    }
                 }
             }
         }, Timeouts.getNewOutgoingCallCancelMillis(mContext.getContentResolver()));
@@ -350,6 +375,45 @@
         return true;
     }
 
+    /**
+     * Handles changes to the {@link Connection.VideoProvider} for a call.  Adds the
+     * {@link CallsManager} as a listener for the {@link VideoProviderProxy} which is created
+     * in {@link Call#setVideoProvider(IVideoProvider)}.  This allows the {@link CallsManager} to
+     * respond to callbacks from the {@link VideoProviderProxy}.
+     *
+     * @param call The call.
+     */
+    @Override
+    public void onVideoCallProviderChanged(Call call) {
+        VideoProviderProxy videoProviderProxy = call.getVideoProviderProxy();
+
+        if (videoProviderProxy == null) {
+            return;
+        }
+
+        videoProviderProxy.addListener(this);
+    }
+
+    /**
+     * Handles session modification requests received via the {@link TelecomVideoCallCallback} for
+     * a call.  Notifies listeners of the {@link CallsManager.CallsManagerListener} of the session
+     * modification request.
+     *
+     * @param call The call.
+     * @param videoProfile The {@link VideoProfile}.
+     */
+    @Override
+    public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
+        int videoState = videoProfile != null ? videoProfile.getVideoState() :
+                VideoProfile.STATE_AUDIO_ONLY;
+        Log.v(TAG, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile
+                .videoStateToString(videoState));
+
+        for (CallsManagerListener listener : mListeners) {
+            listener.onSessionModifyRequestReceived(call, videoProfile);
+        }
+    }
+
     Collection<Call> getCalls() {
         return Collections.unmodifiableCollection(mCalls);
     }
@@ -377,15 +441,15 @@
 
     boolean hasVideoCall() {
         for (Call call : mCalls) {
-            if (call.getVideoState() != VideoProfile.VideoState.AUDIO_ONLY) {
+            if (VideoProfile.isVideo(call.getVideoState())) {
                 return true;
             }
         }
         return false;
     }
 
-    AudioState getAudioState() {
-        return mCallAudioManager.getAudioState();
+    CallAudioState getAudioState() {
+        return mCallAudioManager.getCallAudioState();
     }
 
     boolean isTtySupported() {
@@ -413,10 +477,18 @@
      */
     void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
         Log.d(this, "processIncomingCallIntent");
-        Uri handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
+        Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
+        if (handle == null) {
+            // Required for backwards compatibility
+            handle = extras.getParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER);
+        }
         Call call = new Call(
                 mContext,
+                this,
+                mLock,
                 mConnectionServiceRepository,
+                mContactsAsyncHelper,
+                mCallerInfoAsyncQueryFactory,
                 handle,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -424,7 +496,7 @@
                 true /* isIncoming */,
                 false /* isConference */);
 
-        call.setExtras(extras);
+        call.setIntentExtras(extras);
         // TODO: Move this to be a part of addCall()
         call.addListener(this);
         call.startCreateConnection(mPhoneAccountRegistrar);
@@ -435,7 +507,11 @@
         Log.i(this, "addNewUnknownCall with handle: %s", Log.pii(handle));
         Call call = new Call(
                 mContext,
+                this,
+                mLock,
                 mConnectionServiceRepository,
+                mContactsAsyncHelper,
+                mCallerInfoAsyncQueryFactory,
                 handle,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -445,21 +521,36 @@
                 true /* isIncoming */,
                 false /* isConference */);
         call.setIsUnknown(true);
-        call.setExtras(extras);
+        call.setIntentExtras(extras);
         call.addListener(this);
         call.startCreateConnection(mPhoneAccountRegistrar);
     }
 
+    private boolean areHandlesEqual(Uri handle1, Uri handle2) {
+        if (handle1 == null || handle2 == null) {
+            return handle1 == handle2;
+        }
+
+        if (!TextUtils.equals(handle1.getScheme(), handle2.getScheme())) {
+            return false;
+        }
+
+        final String number1 = PhoneNumberUtils.normalizeNumber(handle1.getSchemeSpecificPart());
+        final String number2 = PhoneNumberUtils.normalizeNumber(handle2.getSchemeSpecificPart());
+        return TextUtils.equals(number1, number2);
+    }
+
     private Call getNewOutgoingCall(Uri handle) {
         // First 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) {
-            if (reusedCall == null && Objects.equals(pendingCall.getHandle(), handle)) {
+            if (reusedCall == null && areHandlesEqual(pendingCall.getHandle(), handle)) {
                 mPendingCallsToDisconnect.remove(pendingCall);
                 Log.i(this, "Reusing disconnected call %s", pendingCall);
                 reusedCall = pendingCall;
             } else {
+                Log.i(this, "Not reusing disconnected call %s", pendingCall);
                 pendingCall.disconnect();
             }
         }
@@ -471,7 +562,11 @@
         // to a connection service, but in most cases will remain the same.
         return new Call(
                 mContext,
+                this,
+                mLock,
                 mConnectionServiceRepository,
+                mContactsAsyncHelper,
+                mCallerInfoAsyncQueryFactory,
                 handle,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -492,13 +587,23 @@
         Call call = getNewOutgoingCall(handle);
 
         List<PhoneAccountHandle> accounts =
-                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme());
+                mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false);
 
         Log.v(this, "startOutgoingCall found accounts = " + accounts);
 
-        if (mForegroundCall != null && mForegroundCall.getTargetPhoneAccount() != null) {
+        if (mForegroundCall != null) {
+            Call ongoingCall = mForegroundCall;
             // If there is an ongoing call, use the same phone account to place this new call.
-            phoneAccountHandle = mForegroundCall.getTargetPhoneAccount();
+            // If the ongoing call is a conference call, we fetch the phone account from the
+            // child calls because we don't have targetPhoneAccount set on Conference calls.
+            // TODO: Set targetPhoneAccount for all conference calls (b/23035408).
+            if (ongoingCall.getTargetPhoneAccount() == null &&
+                    !ongoingCall.getChildCalls().isEmpty()) {
+                ongoingCall = ongoingCall.getChildCalls().get(0);
+            }
+            if (ongoingCall.getTargetPhoneAccount() != null) {
+                phoneAccountHandle = ongoingCall.getTargetPhoneAccount();
+            }
         }
 
         // Only dial with the requested phoneAccount if it is still valid. Otherwise treat this call
@@ -513,12 +618,8 @@
         if (phoneAccountHandle == null) {
             // No preset account, check if default exists that supports the URI scheme for the
             // handle.
-            PhoneAccountHandle defaultAccountHandle =
-                    mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(
-                            handle.getScheme());
-            if (defaultAccountHandle != null) {
-                phoneAccountHandle = defaultAccountHandle;
-            }
+            phoneAccountHandle =
+                    mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme());
         }
 
         call.setTargetPhoneAccount(phoneAccountHandle);
@@ -545,15 +646,17 @@
 
         if (needsAccountSelection) {
             // This is the state where the user is expected to select an account
-            call.setState(CallState.PRE_DIAL_WAIT);
+            call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
             // Create our own instance to modify (since extras may be Bundle.EMPTY)
             extras = new Bundle(extras);
             extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
         } else {
-            call.setState(CallState.CONNECTING);
+            call.setState(
+                    CallState.CONNECTING,
+                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
         }
 
-        call.setExtras(extras);
+        call.setIntentExtras(extras);
 
         // Do not add the call if it is a potential MMI code.
         if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
@@ -595,9 +698,15 @@
 
         call.setHandle(uriHandle);
         call.setGatewayInfo(gatewayInfo);
-        call.setStartWithSpeakerphoneOn(speakerphoneOn);
         call.setVideoState(videoState);
 
+        if (speakerphoneOn) {
+            Log.i(this, "%s Starting with speakerphone as requested", call);
+        } else {
+            Log.i(this, "%s Starting with speakerphone because car is docked.", call);
+        }
+        call.setStartWithSpeakerphoneOn(speakerphoneOn || mDockManager.isDocked());
+
         boolean isEmergencyCall = TelephonyUtil.shouldProcessAsEmergency(mContext,
                 call.getHandle());
         if (isEmergencyCall) {
@@ -671,9 +780,21 @@
             // We do not update the UI until we get confirmation of the answer() through
             // {@link #markCallAsActive}.
             call.answer(videoState);
+            if (VideoProfile.isVideo(videoState) &&
+                !mWiredHeadsetManager.isPluggedIn() &&
+                !mCallAudioManager.isBluetoothDeviceAvailable() &&
+                isSpeakerEnabledForVideoCalls()) {
+                call.setStartWithSpeakerphoneOn(true);
+            }
         }
     }
 
+    private static boolean isSpeakerEnabledForVideoCalls() {
+        return (SystemProperties.getInt(TelephonyProperties.PROPERTY_VIDEOCALL_AUDIO_OUTPUT,
+                PhoneConstants.AUDIO_OUTPUT_DEFAULT) ==
+                PhoneConstants.AUDIO_OUTPUT_ENABLE_SPEAKER);
+    }
+
     /**
      * Instructs Telecom to reject the specified call. Intended to be invoked by the in-call
      * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
@@ -821,7 +942,7 @@
             Log.i(this, "Attempted to add account to unknown call %s", call);
         } else {
             // TODO: There is an odd race condition here. Since NewOutgoingCallIntentBroadcaster and
-            // the PRE_DIAL_WAIT sequence run in parallel, if the user selects an account before the
+            // the SELECT_PHONE_ACCOUNT sequence run in parallel, if the user selects an account before the
             // NEW_OUTGOING_CALL sequence finishes, we'll start the call immediately without
             // respecting a rewritten number or a canceled number. This is unlikely since
             // NEW_OUTGOING_CALL sequence, in practice, runs a lot faster than the user selecting
@@ -843,42 +964,40 @@
     }
 
     /** Called when the audio state changes. */
-    void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState) {
+    void onCallAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState) {
         Log.v(this, "onAudioStateChanged, audioState: %s -> %s", oldAudioState, newAudioState);
         for (CallsManagerListener listener : mListeners) {
-            listener.onAudioStateChanged(oldAudioState, newAudioState);
+            listener.onCallAudioStateChanged(oldAudioState, newAudioState);
         }
     }
 
     void markCallAsRinging(Call call) {
-        setCallState(call, CallState.RINGING);
+        setCallState(call, CallState.RINGING, "ringing set explicitly");
     }
 
     void markCallAsDialing(Call call) {
-        setCallState(call, CallState.DIALING);
+        setCallState(call, CallState.DIALING, "dialing set explicitly");
+        maybeMoveToSpeakerPhone(call);
     }
 
     void markCallAsActive(Call call) {
-        setCallState(call, CallState.ACTIVE);
-
-        if (call.getStartWithSpeakerphoneOn()) {
-            setAudioRoute(AudioState.ROUTE_SPEAKER);
-        }
+        setCallState(call, CallState.ACTIVE, "active set explicitly");
+        maybeMoveToSpeakerPhone(call);
     }
 
     void markCallAsOnHold(Call call) {
-        setCallState(call, CallState.ON_HOLD);
+        setCallState(call, CallState.ON_HOLD, "on-hold set explicitly");
     }
 
     /**
      * Marks the specified call as STATE_DISCONNECTED and notifies the in-call app. If this was the
      * last live call, then also disconnect from the in-call controller.
      *
-     * @param disconnectCause The disconnect cause, see {@link android.telecomm.DisconnectCause}.
+     * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
      */
     void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
         call.setDisconnectCause(disconnectCause);
-        setCallState(call, CallState.DISCONNECTED);
+        setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
     }
 
     /**
@@ -969,6 +1088,14 @@
             if (call.isEmergencyCall()) {
                 // We never support add call if one of the calls is an emergency call.
                 return false;
+            } else  if (!call.getChildCalls().isEmpty() && !call.can(Connection.CAPABILITY_HOLD)) {
+                // This is to deal with CDMA conference calls. CDMA conference calls do not
+                // allow the addition of another call when it is already in a 3 way conference.
+                // So, we detect that it is a CDMA conference call by checking if the call has
+                // some children and it does not support the CAPABILILTY_HOLD
+                // TODO: This maybe cleaner if the lower layers can explicitly signal to telecom
+                // about this limitation (b/22880180).
+                return false;
             } else if (call.getParentCall() == null) {
                 count++;
             }
@@ -985,7 +1112,8 @@
         return true;
     }
 
-    Call getRingingCall() {
+    @VisibleForTesting
+    public Call getRingingCall() {
         return getFirstCallWithState(CallState.RINGING);
     }
 
@@ -1011,6 +1139,10 @@
         return count;
     }
 
+    Call getOutgoingCall() {
+        return getFirstCallWithState(OUTGOING_CALL_STATES);
+    }
+
     Call getFirstCallWithState(int... states) {
         return getFirstCallWithState(null, states);
     }
@@ -1060,7 +1192,11 @@
 
         Call call = new Call(
                 mContext,
+                this,
+                mLock,
                 mConnectionServiceRepository,
+                mContactsAsyncHelper,
+                mCallerInfoAsyncQueryFactory,
                 null /* handle */,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
@@ -1069,8 +1205,13 @@
                 true /* isConference */,
                 connectTime);
 
-        setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()));
+        setCallState(call, Call.getStateFromConnectionState(parcelableConference.getState()),
+                "new conference call");
         call.setConnectionCapabilities(parcelableConference.getConnectionCapabilities());
+        call.setVideoState(parcelableConference.getVideoState());
+        call.setVideoProvider(parcelableConference.getVideoProvider());
+        call.setStatusHints(parcelableConference.getStatusHints());
+        call.setExtras(parcelableConference.getExtras());
 
         // TODO: Move this to be a part of addCall()
         call.addListener(this);
@@ -1142,6 +1283,8 @@
             shouldNotify = true;
         }
 
+        call.destroy();
+
         // Only broadcast changes for calls that are being tracked.
         if (shouldNotify) {
             for (CallsManagerListener listener : mListeners) {
@@ -1164,7 +1307,7 @@
      * @param call The call.
      * @param newState The new state of the call.
      */
-    private void setCallState(Call call, int newState) {
+    private void setCallState(Call call, int newState, String tag) {
         if (call == null) {
             return;
         }
@@ -1179,7 +1322,7 @@
             // into a well-defined state machine.
             // TODO: Define expected state transitions here, and log when an
             // unexpected transition occurs.
-            call.setState(newState);
+            call.setState(newState, tag);
 
             Trace.beginSection("onCallStateChanged");
             // Only broadcast state change for calls that are being tracked.
@@ -1337,21 +1480,25 @@
 
             if (call == liveCall) {
                 // If the call is already the foreground call, then we are golden.
-                // This can happen after the user selects an account in the PRE_DIAL_WAIT
+                // This can happen after the user selects an account in the SELECT_PHONE_ACCOUNT
                 // state since the call was already populated into the list.
                 return true;
             }
 
             if (hasMaximumOutgoingCalls()) {
-                // Disconnect the current outgoing call if it's not an emergency call. If the user
-                // tries to make two outgoing calls to different emergency call numbers, we will try
-                // to connect the first outgoing call.
-                if (isEmergency) {
-                    Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
-                    if (!outgoingCall.isEmergencyCall()) {
-                        outgoingCall.disconnect();
-                        return true;
-                    }
+                Call outgoingCall = getFirstCallWithState(OUTGOING_CALL_STATES);
+                if (isEmergency && !outgoingCall.isEmergencyCall()) {
+                    // Disconnect the current outgoing call if it's not an emergency call. If the
+                    // user tries to make two outgoing calls to different emergency call numbers,
+                    // we will try to connect the first outgoing call.
+                    outgoingCall.disconnect();
+                    return true;
+                }
+                if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
+                    // If there is an orphaned call in the {@link CallState#SELECT_PHONE_ACCOUNT}
+                    // state, just disconnect it since the user has explicitly started a new call.
+                    outgoingCall.disconnect();
+                    return true;
                 }
                 return false;
             }
@@ -1369,10 +1516,27 @@
 
             // We have room for at least one more holding call at this point.
 
+            // TODO: Remove once b/23035408 has been corrected.
+            // If the live call is a conference, it will not have a target phone account set.  This
+            // means the check to see if the live call has the same target phone account as the new
+            // call will not cause us to bail early.  As a result, we'll end up holding the
+            // ongoing conference call.  However, the ConnectionService is already doing that.  This
+            // has caused problems with some carriers.  As a workaround until b/23035408 is
+            // corrected, we will try and get the target phone account for one of the conference's
+            // children and use that instead.
+            PhoneAccountHandle liveCallPhoneAccount = liveCall.getTargetPhoneAccount();
+            if (liveCallPhoneAccount == null && liveCall.isConference() &&
+                    !liveCall.getChildCalls().isEmpty()) {
+                liveCallPhoneAccount = getFirstChildPhoneAccount(liveCall);
+                Log.i(this, "makeRoomForOutgoingCall: using child call PhoneAccount = " +
+                        liveCallPhoneAccount);
+            }
+
             // First thing, if we are trying to make a call with the same phone account as the live
             // call, then allow it so that the connection service can make its own decision about
             // how to handle the new call relative to the current one.
-            if (Objects.equals(liveCall.getTargetPhoneAccount(), call.getTargetPhoneAccount())) {
+            if (Objects.equals(liveCallPhoneAccount, call.getTargetPhoneAccount())) {
+                Log.i(this, "makeRoomForOutgoingCall: phoneAccount matches.");
                 return true;
             } else if (call.getTargetPhoneAccount() == null) {
                 // Without a phone account, we can't say reliably that the call will fail.
@@ -1386,6 +1550,7 @@
 
             // Try to hold the live call before attempting the new outgoing call.
             if (liveCall.can(Connection.CAPABILITY_HOLD)) {
+                Log.i(this, "makeRoomForOutgoingCall: holding live call.");
                 liveCall.hold();
                 return true;
             }
@@ -1397,6 +1562,32 @@
     }
 
     /**
+     * Given a call, find the first non-null phone account handle of its children.
+     *
+     * @param parentCall The parent call.
+     * @return The first non-null phone account handle of the children, or {@code null} if none.
+     */
+    private PhoneAccountHandle getFirstChildPhoneAccount(Call parentCall) {
+        for (Call childCall : parentCall.getChildCalls()) {
+            PhoneAccountHandle childPhoneAccount = childCall.getTargetPhoneAccount();
+            if (childPhoneAccount != null) {
+                return childPhoneAccount;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Checks to see if the call should be on speakerphone and if so, set it.
+     */
+    private void maybeMoveToSpeakerPhone(Call call) {
+        if (call.getStartWithSpeakerphoneOn()) {
+            setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+            call.setStartWithSpeakerphoneOn(false);
+        }
+    }
+
+    /**
      * Creates a new call for an existing connection.
      *
      * @param callId The id of the new call.
@@ -1406,15 +1597,21 @@
     Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
         Call call = new Call(
                 mContext,
+                this,
+                mLock,
                 mConnectionServiceRepository,
+                mContactsAsyncHelper,
+                mCallerInfoAsyncQueryFactory,
                 connection.getHandle() /* handle */,
                 null /* gatewayInfo */,
                 null /* connectionManagerPhoneAccount */,
                 connection.getPhoneAccount(), /* targetPhoneAccountHandle */
                 false /* isIncoming */,
-                false /* isConference */);
+                false /* isConference */,
+                connection.getConnectTimeMillis() /* connectTimeMillis */);
 
-        setCallState(call, Call.getStateFromConnectionState(connection.getState()));
+        setCallState(call, Call.getStateFromConnectionState(connection.getState()),
+                "existing connection");
         call.setConnectionCapabilities(connection.getConnectionCapabilities());
         call.setCallerDisplayName(connection.getCallerDisplayName(),
                 connection.getCallerDisplayNamePresentation());
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index ffc5947..58085a0 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -17,11 +17,13 @@
 package com.android.server.telecom;
 
 import android.telecom.AudioState;
+import android.telecom.CallAudioState;
+import android.telecom.VideoProfile;
 
 /**
  * Provides a default implementation for listeners of CallsManager.
  */
-class CallsManagerListenerBase implements CallsManager.CallsManagerListener {
+public class CallsManagerListenerBase implements CallsManager.CallsManagerListener {
     @Override
     public void onCallAdded(Call call) {
     }
@@ -54,7 +56,8 @@
     }
 
     @Override
-    public void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState) {
+    public void onCallAudioStateChanged(CallAudioState oldAudioState,
+            CallAudioState newAudioState) {
     }
 
     @Override
@@ -76,4 +79,9 @@
     @Override
     public void onCanAddCallChanged(boolean canAddCall) {
     }
+
+    @Override
+    public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
+
+    }
 }
diff --git a/src/com/android/server/telecom/ConnectionServiceRepository.java b/src/com/android/server/telecom/ConnectionServiceRepository.java
index 0d73371..a587b59 100644
--- a/src/com/android/server/telecom/ConnectionServiceRepository.java
+++ b/src/com/android/server/telecom/ConnectionServiceRepository.java
@@ -28,16 +28,33 @@
 /**
  * Searches for and returns connection services.
  */
-final class ConnectionServiceRepository
-        implements ServiceBinder.Listener<ConnectionServiceWrapper> {
+final class ConnectionServiceRepository {
     private final HashMap<Pair<ComponentName, UserHandle>, ConnectionServiceWrapper> mServiceCache =
             new HashMap<>();
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final Context mContext;
+    private final TelecomSystem.SyncRoot mLock;
+    private final CallsManager mCallsManager;
 
-    ConnectionServiceRepository(PhoneAccountRegistrar phoneAccountRegistrar, Context context) {
+    private final ServiceBinder.Listener<ConnectionServiceWrapper> mUnbindListener =
+            new ServiceBinder.Listener<ConnectionServiceWrapper>() {
+                @Override
+                public void onUnbind(ConnectionServiceWrapper service) {
+                    synchronized (mLock) {
+                        mServiceCache.remove(service.getComponentName());
+                    }
+                }
+            };
+
+    ConnectionServiceRepository(
+            PhoneAccountRegistrar phoneAccountRegistrar,
+            Context context,
+            TelecomSystem.SyncRoot lock,
+            CallsManager callsManager) {
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mContext = context;
+        mLock = lock;
+        mCallsManager = callsManager;
     }
 
     ConnectionServiceWrapper getService(ComponentName componentName, UserHandle userHandle) {
@@ -48,25 +65,17 @@
                     componentName,
                     this,
                     mPhoneAccountRegistrar,
+                    mCallsManager,
                     mContext,
+                    mLock,
                     userHandle);
-            service.addListener(this);
+            service.addListener(mUnbindListener);
             mServiceCache.put(cacheKey, service);
         }
         return service;
     }
 
     /**
-     * Removes the specified service from the cache when the service unbinds.
-     *
-     * {@inheritDoc}
-     */
-    @Override
-    public void onUnbind(ConnectionServiceWrapper service) {
-        mServiceCache.remove(service.getComponentName());
-    }
-
-    /**
      * Dumps the state of the {@link ConnectionServiceRepository}.
      *
      * @param pw The {@code IndentingPrintWriter} to write the state to.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index d470737..d5ab5cf 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -19,13 +19,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.telecom.AudioState;
+import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
 import android.telecom.ConnectionService;
@@ -33,13 +32,11 @@
 import android.telecom.GatewayInfo;
 import android.telecom.ParcelableConference;
 import android.telecom.ParcelableConnection;
-import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 
-import com.android.internal.os.SomeArgs;
 import com.android.internal.telecom.IConnectionService;
 import com.android.internal.telecom.IConnectionServiceAdapter;
 import com.android.internal.telecom.IVideoProvider;
@@ -60,337 +57,7 @@
  * {@link IConnectionService} directly and instead should use this class to invoke methods of
  * {@link IConnectionService}.
  */
-final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
-    private static final int MSG_HANDLE_CREATE_CONNECTION_COMPLETE = 1;
-    private static final int MSG_SET_ACTIVE = 2;
-    private static final int MSG_SET_RINGING = 3;
-    private static final int MSG_SET_DIALING = 4;
-    private static final int MSG_SET_DISCONNECTED = 5;
-    private static final int MSG_SET_ON_HOLD = 6;
-    private static final int MSG_SET_RINGBACK_REQUESTED = 7;
-    private static final int MSG_SET_CONNECTION_CAPABILITIES = 8;
-    private static final int MSG_SET_IS_CONFERENCED = 9;
-    private static final int MSG_ADD_CONFERENCE_CALL = 10;
-    private static final int MSG_REMOVE_CALL = 11;
-    private static final int MSG_ON_POST_DIAL_WAIT = 12;
-    private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 13;
-    private static final int MSG_SET_VIDEO_PROVIDER = 14;
-    private static final int MSG_SET_IS_VOIP_AUDIO_MODE = 15;
-    private static final int MSG_SET_STATUS_HINTS = 16;
-    private static final int MSG_SET_ADDRESS = 17;
-    private static final int MSG_SET_CALLER_DISPLAY_NAME = 18;
-    private static final int MSG_SET_VIDEO_STATE = 19;
-    private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 20;
-    private static final int MSG_ADD_EXISTING_CONNECTION = 21;
-    private static final int MSG_ON_POST_DIAL_CHAR = 22;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            Call call;
-            switch (msg.what) {
-                case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        String callId = (String) args.arg1;
-                        ConnectionRequest request = (ConnectionRequest) args.arg2;
-                        ParcelableConnection connection = (ParcelableConnection) args.arg3;
-                        handleCreateConnectionComplete(callId, request, connection);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_ACTIVE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.markCallAsActive(call);
-                    } else {
-                        //Log.w(this, "setActive, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_SET_RINGING:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.markCallAsRinging(call);
-                    } else {
-                        //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_SET_DIALING:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.markCallAsDialing(call);
-                    } else {
-                        //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_SET_DISCONNECTED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        DisconnectCause disconnectCause = (DisconnectCause) args.arg2;
-                        Log.d(this, "disconnect call %s %s", disconnectCause, call);
-                        if (call != null) {
-                            mCallsManager.markCallAsDisconnected(call, disconnectCause);
-                        } else {
-                            //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_ON_HOLD:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.markCallAsOnHold(call);
-                    } else {
-                        //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_SET_RINGBACK_REQUESTED: {
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.setRingbackRequested(msg.arg1 == 1);
-                    } else {
-                        //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
-                    }
-                    break;
-                }
-                case MSG_SET_CONNECTION_CAPABILITIES: {
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.setConnectionCapabilities(msg.arg1);
-                    } else {
-                        //Log.w(ConnectionServiceWrapper.this,
-                        //      "setConnectionCapabilities, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                }
-                case MSG_SET_IS_CONFERENCED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        Call childCall = mCallIdMapper.getCall(args.arg1);
-                        Log.d(this, "SET_IS_CONFERENCE: %s %s", args.arg1, args.arg2);
-                        if (childCall != null) {
-                            String conferenceCallId = (String) args.arg2;
-                            if (conferenceCallId == null) {
-                                Log.d(this, "unsetting parent: %s", args.arg1);
-                                childCall.setParentCall(null);
-                            } else {
-                                Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
-                                childCall.setParentCall(conferenceCall);
-                            }
-                        } else {
-                            //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_ADD_CONFERENCE_CALL: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        String id = (String) args.arg1;
-                        if (mCallIdMapper.getCall(id) != null) {
-                            Log.w(this, "Attempting to add a conference call using an existing " +
-                                    "call id %s", id);
-                            break;
-                        }
-                        ParcelableConference parcelableConference =
-                                (ParcelableConference) args.arg2;
-
-                        // 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
-                        // and from the real connection service.
-                        boolean hasValidCalls = false;
-                        for (String callId : parcelableConference.getConnectionIds()) {
-                            if (mCallIdMapper.getCall(callId) != null) {
-                                hasValidCalls = true;
-                            }
-                        }
-                        // But don't bail out if the connection count is 0, because that is a valid
-                        // IMS conference state.
-                        if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) {
-                            Log.d(this, "Attempting to add a conference with no valid calls");
-                            break;
-                        }
-
-                        // need to create a new Call
-                        PhoneAccountHandle phAcc = null;
-                        if (parcelableConference != null &&
-                                parcelableConference.getPhoneAccount() != null) {
-                            phAcc = parcelableConference.getPhoneAccount();
-                        }
-                        Call conferenceCall = mCallsManager.createConferenceCall(
-                                phAcc, parcelableConference);
-                        mCallIdMapper.addCall(conferenceCall, id);
-                        conferenceCall.setConnectionService(ConnectionServiceWrapper.this);
-
-                        Log.d(this, "adding children to conference %s phAcc %s",
-                                parcelableConference.getConnectionIds(), phAcc);
-                        for (String callId : parcelableConference.getConnectionIds()) {
-                            Call childCall = mCallIdMapper.getCall(callId);
-                            Log.d(this, "found child: %s", callId);
-                            if (childCall != null) {
-                                childCall.setParentCall(conferenceCall);
-                            }
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_REMOVE_CALL: {
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        if (call.isAlive()) {
-                            mCallsManager.markCallAsDisconnected(
-                                    call, new DisconnectCause(DisconnectCause.REMOTE));
-                        } else {
-                            mCallsManager.markCallAsRemoved(call);
-                        }
-                    }
-                    break;
-                }
-                case MSG_ON_POST_DIAL_WAIT: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null) {
-                            String remaining = (String) args.arg2;
-                            call.onPostDialWait(remaining);
-                        } else {
-                            //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_ON_POST_DIAL_CHAR: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null) {
-                            char nextChar = (char) args.argi1;
-                            call.onPostDialChar(nextChar);
-                        } else {
-                            //Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_QUERY_REMOTE_CALL_SERVICES: {
-                    queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
-                    break;
-                }
-                case MSG_SET_VIDEO_PROVIDER: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        IVideoProvider videoProvider = (IVideoProvider) args.arg2;
-                        if (call != null) {
-                            call.setVideoProvider(videoProvider);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_IS_VOIP_AUDIO_MODE: {
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.setIsVoipAudioMode(msg.arg1 == 1);
-                    }
-                    break;
-                }
-                case MSG_SET_STATUS_HINTS: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        StatusHints statusHints = (StatusHints) args.arg2;
-                        if (call != null) {
-                            call.setStatusHints(statusHints);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_ADDRESS: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null) {
-                            call.setHandle((Uri) args.arg2, args.argi1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_CALLER_DISPLAY_NAME: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null) {
-                            call.setCallerDisplayName((String) args.arg2, args.argi1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SET_VIDEO_STATE: {
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.setVideoState(msg.arg1);
-                    }
-                    break;
-                }
-                case MSG_SET_CONFERENCEABLE_CONNECTIONS: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null ){
-                            @SuppressWarnings("unchecked")
-                            List<String> conferenceableIds = (List<String>) args.arg2;
-                            List<Call> conferenceableCalls =
-                                    new ArrayList<>(conferenceableIds.size());
-                            for (String otherId : (List<String>) args.arg2) {
-                                Call otherCall = mCallIdMapper.getCall(otherId);
-                                if (otherCall != null && otherCall != call) {
-                                    conferenceableCalls.add(otherCall);
-                                }
-                            }
-                            call.setConferenceableCalls(conferenceableCalls);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_ADD_EXISTING_CONNECTION: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        String callId = (String)args.arg1;
-                        ParcelableConnection connection = (ParcelableConnection)args.arg2;
-                        Call existingCall = mCallsManager.createCallForExistingConnection(callId,
-                                connection);
-                        mCallIdMapper.addCall(existingCall, callId);
-                        existingCall.setConnectionService(ConnectionServiceWrapper.this);
-                    } finally {
-                        args.recycle();
-                    }
-                }
-            }
-        }
-    };
+final class ConnectionServiceWrapper extends ServiceBinder {
 
     private final class Adapter extends IConnectionServiceAdapter.Stub {
 
@@ -399,239 +66,539 @@
                 String callId,
                 ConnectionRequest request,
                 ParcelableConnection connection) {
-            logIncoming("handleCreateConnectionComplete %s", request);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = request;
-                args.arg3 = connection;
-                mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args)
-                        .sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("handleCreateConnectionComplete %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        ConnectionServiceWrapper.this
+                                .handleCreateConnectionComplete(callId, request, connection);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setActive(String callId) {
-            logIncoming("setActive %s", callId);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setActive %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper
+                            .isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            mCallsManager.markCallAsActive(call);
+                        } else {
+                            // Log.w(this, "setActive, unknown call id: %s", msg.obj);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setRinging(String callId) {
-            logIncoming("setRinging %s", callId);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setRinging %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            mCallsManager.markCallAsRinging(call);
+                        } else {
+                            // Log.w(this, "setRinging, unknown call id: %s", msg.obj);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setVideoProvider(String callId, IVideoProvider videoProvider) {
-            logIncoming("setVideoProvider %s", callId);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = videoProvider;
-                mHandler.obtainMessage(MSG_SET_VIDEO_PROVIDER, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setVideoProvider %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId)
+                            || mCallIdMapper.isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setVideoProvider(videoProvider);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setDialing(String callId) {
-            logIncoming("setDialing %s", callId);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setDialing %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            mCallsManager.markCallAsDialing(call);
+                        } else {
+                            // Log.w(this, "setDialing, unknown call id: %s", msg.obj);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setDisconnected(String callId, DisconnectCause disconnectCause) {
-            logIncoming("setDisconnected %s %s", callId, disconnectCause);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                Log.d(this, "disconnect call %s", callId);
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = disconnectCause;
-                mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setDisconnected %s %s", callId, disconnectCause);
+                    if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper
+                            .isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        Log.d(this, "disconnect call %s %s", disconnectCause, call);
+                        if (call != null) {
+                            mCallsManager.markCallAsDisconnected(call, disconnectCause);
+                        } else {
+                            // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setOnHold(String callId) {
-            logIncoming("setOnHold %s", callId);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setOnHold %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper
+                            .isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            mCallsManager.markCallAsOnHold(call);
+                        } else {
+                            // Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setRingbackRequested(String callId, boolean ringback) {
-            logIncoming("setRingbackRequested %s %b", callId, ringback);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                mHandler.obtainMessage(MSG_SET_RINGBACK_REQUESTED, ringback ? 1 : 0, 0, callId)
-                        .sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setRingbackRequested %s %b", callId, ringback);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setRingbackRequested(ringback);
+                        } else {
+                            // Log.w(this, "setRingback, unknown call id: %s", args.arg1);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void removeCall(String callId) {
-            logIncoming("removeCall %s", callId);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                mHandler.obtainMessage(MSG_REMOVE_CALL, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("removeCall %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper
+                            .isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            if (call.isAlive()) {
+                                mCallsManager.markCallAsDisconnected(
+                                        call, new DisconnectCause(DisconnectCause.REMOTE));
+                            } else {
+                                mCallsManager.markCallAsRemoved(call);
+                            }
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setConnectionCapabilities(String callId, int connectionCapabilities) {
-            logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                mHandler.obtainMessage(MSG_SET_CONNECTION_CAPABILITIES, connectionCapabilities, 0, callId)
-                        .sendToTarget();
-            } else {
-                Log.w(this, "ID not valid for setCallCapabilities");
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities);
+                    if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper
+                            .isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setConnectionCapabilities(connectionCapabilities);
+                        } else {
+                            // Log.w(ConnectionServiceWrapper.this,
+                            // "setConnectionCapabilities, unknown call id: %s", msg.obj);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setIsConferenced(String callId, String conferenceCallId) {
-            logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = conferenceCallId;
-            mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
+                    Call childCall = mCallIdMapper.getCall(callId);
+                    if (childCall != null) {
+                        if (conferenceCallId == null) {
+                            Log.d(this, "unsetting parent: %s", conferenceCallId);
+                            childCall.setParentCall(null);
+                        } else {
+                            Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
+                            childCall.setParentCall(conferenceCall);
+                        }
+                    } else {
+                        // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setConferenceMergeFailed(String callId) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setConferenceMergeFailed %s", callId);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        // TODO: we should move the UI for indication a merge failure here
+                        // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can
+                        // deliver the message anyway that they want. b/20530631.
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            // 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);
+                        } else {
+                            Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId);
+                        }
+                    }
+
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void addConferenceCall(String callId, ParcelableConference parcelableConference) {
-            logIncoming("addConferenceCall %s %s", callId, parcelableConference);
-            // We do not check call Ids here because we do not yet know the call ID for new
-            // conference calls.
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = parcelableConference;
-            mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (mCallIdMapper.getCall(callId) != null) {
+                        Log.w(this, "Attempting to add a conference call using an existing " +
+                                "call id %s", callId);
+                        return;
+                    }
+
+                    // 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
+                    // and from the real connection service.
+                    boolean hasValidCalls = false;
+                    for (String connId : parcelableConference.getConnectionIds()) {
+                        if (mCallIdMapper.getCall(connId) != null) {
+                            hasValidCalls = true;
+                        }
+                    }
+                    // But don't bail out if the connection count is 0, because that is a valid
+                    // IMS conference state.
+                    if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) {
+                        Log.d(this, "Attempting to add a conference with no valid calls");
+                        return;
+                    }
+
+                    // need to create a new Call
+                    PhoneAccountHandle phAcc = null;
+                    if (parcelableConference != null &&
+                            parcelableConference.getPhoneAccount() != null) {
+                        phAcc = parcelableConference.getPhoneAccount();
+                    }
+                    Call conferenceCall = mCallsManager.createConferenceCall(
+                            phAcc, parcelableConference);
+                    mCallIdMapper.addCall(conferenceCall, callId);
+                    conferenceCall.setConnectionService(ConnectionServiceWrapper.this);
+
+                    Log.d(this, "adding children to conference %s phAcc %s",
+                            parcelableConference.getConnectionIds(), phAcc);
+                    for (String connId : parcelableConference.getConnectionIds()) {
+                        Call childCall = mCallIdMapper.getCall(connId);
+                        Log.d(this, "found child: %s", connId);
+                        if (childCall != null) {
+                            childCall.setParentCall(conferenceCall);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void onPostDialWait(String callId, String remaining) throws RemoteException {
-            logIncoming("onPostDialWait %s %s", callId, remaining);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = remaining;
-                mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("onPostDialWait %s %s", callId, remaining);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.onPostDialWait(remaining);
+                        } else {
+                            // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void onPostDialChar(String callId, char nextChar) throws RemoteException {
-            logIncoming("onPostDialChar %s %s", callId, nextChar);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.argi1 = nextChar;
-                mHandler.obtainMessage(MSG_ON_POST_DIAL_CHAR, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("onPostDialChar %s %s", callId, nextChar);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.onPostDialChar(nextChar);
+                        } else {
+                            // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
-            logIncoming("queryRemoteCSs");
-            mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("queryRemoteConnectionServices %s", callback);
+                    ConnectionServiceWrapper.this.queryRemoteConnectionServices(callback);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public void setVideoState(String callId, int videoState) {
-            logIncoming("setVideoState %s %d", callId, videoState);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setVideoState %s %d", callId, videoState);
+                    if (mCallIdMapper.isValidCallId(callId)
+                            || mCallIdMapper.isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setVideoState(videoState);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setIsVoipAudioMode(String callId, boolean isVoip) {
-            logIncoming("setIsVoipAudioMode %s %b", callId, isVoip);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                mHandler.obtainMessage(MSG_SET_IS_VOIP_AUDIO_MODE, isVoip ? 1 : 0, 0,
-                        callId).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setIsVoipAudioMode %s %b", callId, isVoip);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setIsVoipAudioMode(isVoip);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setStatusHints(String callId, StatusHints statusHints) {
-            logIncoming("setStatusHints %s %s", callId, statusHints);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = statusHints;
-                mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setStatusHints %s %s", callId, statusHints);
+                    if (mCallIdMapper.isValidCallId(callId)
+                            || mCallIdMapper.isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setStatusHints(statusHints);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setExtras(String callId, Bundle extras) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized(mLock) {
+                    logIncoming("setExtras %s %s", callId, extras);
+                    if (mCallIdMapper.isValidCallId(callId)
+                            || mCallIdMapper.isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setExtras(extras);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setAddress(String callId, Uri address, int presentation) {
-            logIncoming("setAddress %s %s %d", callId, address, presentation);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = address;
-                args.argi1 = presentation;
-                mHandler.obtainMessage(MSG_SET_ADDRESS, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setAddress %s %s %d", callId, address, presentation);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setHandle(address, presentation);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setCallerDisplayName(
                 String callId, String callerDisplayName, int presentation) {
-            logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
-            if (mCallIdMapper.isValidCallId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = callerDisplayName;
-                args.argi1 = presentation;
-                mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName,
+                            presentation);
+                    if (mCallIdMapper.isValidCallId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            call.setCallerDisplayName(callerDisplayName, presentation);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void setConferenceableConnections(
                 String callId, List<String> conferenceableCallIds) {
-            logIncoming("setConferenceableConnections %s %s", callId, conferenceableCallIds);
-            if (mCallIdMapper.isValidCallId(callId) || mCallIdMapper.isValidConferenceId(callId)) {
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = callId;
-                args.arg2 = conferenceableCallIds;
-                mHandler.obtainMessage(MSG_SET_CONFERENCEABLE_CONNECTIONS, args).sendToTarget();
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    logIncoming("setConferenceableConnections %s %s", callId,
+                            conferenceableCallIds);
+                    if (mCallIdMapper.isValidCallId(callId) ||
+                            mCallIdMapper.isValidConferenceId(callId)) {
+                        Call call = mCallIdMapper.getCall(callId);
+                        if (call != null) {
+                            List<Call> conferenceableCalls =
+                                    new ArrayList<>(conferenceableCallIds.size());
+                            for (String otherId : conferenceableCallIds) {
+                                Call otherCall = mCallIdMapper.getCall(otherId);
+                                if (otherCall != null && otherCall != call) {
+                                    conferenceableCalls.add(otherCall);
+                                }
+                            }
+                            call.setConferenceableCalls(conferenceableCalls);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
         public void addExistingConnection(String callId, ParcelableConnection connection) {
-            logIncoming("addExistingConnection  %s %s", callId, connection);
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = connection;
-            mHandler.obtainMessage(MSG_ADD_EXISTING_CONNECTION, args).sendToTarget();
+            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);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
     }
 
     private final Adapter mAdapter = new Adapter();
-    private final CallsManager mCallsManager = CallsManager.getInstance();
-    /**
-     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
-     * load factor before resizing, 1 means we only expect a single thread to
-     * access the map so make only a single shard
-     */
-    private final Set<Call> mPendingConferenceCalls = Collections.newSetFromMap(
-            new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));
     private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
     private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
 
-    private Binder mBinder = new Binder();
+    private Binder2 mBinder = new Binder2();
     private IConnectionService mServiceInterface;
     private final ConnectionServiceRepository mConnectionServiceRepository;
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
+    private final CallsManager mCallsManager;
 
     /**
      * Creates a connection service.
@@ -639,6 +606,7 @@
      * @param componentName The component name of the service with which to bind.
      * @param connectionServiceRepository Connection service repository.
      * @param phoneAccountRegistrar Phone account registrar
+     * @param callsManager Calls manager
      * @param context The context.
      * @param userHandle The {@link UserHandle} to use when binding.
      */
@@ -646,15 +614,18 @@
             ComponentName componentName,
             ConnectionServiceRepository connectionServiceRepository,
             PhoneAccountRegistrar phoneAccountRegistrar,
+            CallsManager callsManager,
             Context context,
+            TelecomSystem.SyncRoot lock,
             UserHandle userHandle) {
-        super(ConnectionService.SERVICE_INTERFACE, componentName, context, userHandle);
+        super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);
         mConnectionServiceRepository = connectionServiceRepository;
         phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() {
             // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections
             // To do this, we must proxy remote ConnectionService objects
         });
         mPhoneAccountRegistrar = phoneAccountRegistrar;
+        mCallsManager = callsManager;
     }
 
     /** See {@link IConnectionService#addConnectionServiceAdapter}. */
@@ -680,7 +651,7 @@
                 mPendingResponses.put(callId, response);
 
                 GatewayInfo gatewayInfo = call.getGatewayInfo();
-                Bundle extras = call.getExtras();
+                Bundle extras = call.getIntentExtras();
                 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
                         gatewayInfo.getOriginalAddress() != null) {
                     extras = (Bundle) extras.clone();
@@ -692,6 +663,7 @@
                             gatewayInfo.getOriginalAddress());
                 }
 
+                Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));
                 try {
                     mServiceInterface.createConnection(
                             call.getConnectionManagerPhoneAccount(),
@@ -717,10 +689,10 @@
             }
         };
 
-        mBinder.bind(callback);
+        mBinder.bind(callback, call);
     }
 
-    /** @see ConnectionService#abort(String) */
+    /** @see IConnectionService#abort(String) */
     void abort(Call call) {
         // Clear out any pending outgoing call data
         final String callId = mCallIdMapper.getCallId(call);
@@ -737,7 +709,7 @@
         removeCall(call, new DisconnectCause(DisconnectCause.LOCAL));
     }
 
-    /** @see ConnectionService#hold(String) */
+    /** @see IConnectionService#hold(String) */
     void hold(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("hold")) {
@@ -749,7 +721,7 @@
         }
     }
 
-    /** @see ConnectionService#unhold(String) */
+    /** @see IConnectionService#unhold(String) */
     void unhold(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("unhold")) {
@@ -761,19 +733,19 @@
         }
     }
 
-    /** @see ConnectionService#onAudioStateChanged(String,AudioState) */
-    void onAudioStateChanged(Call activeCall, AudioState audioState) {
+    /** @see IConnectionService#onCallAudioStateChanged(String,CallAudioState) */
+    void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) {
         final String callId = mCallIdMapper.getCallId(activeCall);
-        if (callId != null && isServiceValid("onAudioStateChanged")) {
+        if (callId != null && isServiceValid("onCallAudioStateChanged")) {
             try {
-                logOutgoing("onAudioStateChanged %s %s", callId, audioState);
-                mServiceInterface.onAudioStateChanged(callId, audioState);
+                logOutgoing("onCallAudioStateChanged %s %s", callId, audioState);
+                mServiceInterface.onCallAudioStateChanged(callId, audioState);
             } catch (RemoteException e) {
             }
         }
     }
 
-    /** @see ConnectionService#disconnect(String) */
+    /** @see IConnectionService#disconnect(String) */
     void disconnect(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("disconnect")) {
@@ -785,13 +757,13 @@
         }
     }
 
-    /** @see ConnectionService#answer(String,int) */
+    /** @see IConnectionService#answer(String) */
     void answer(Call call, int videoState) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("answer")) {
             try {
                 logOutgoing("answer %s %d", callId, videoState);
-                if (videoState == VideoProfile.VideoState.AUDIO_ONLY) {
+                if (VideoProfile.isAudioOnly(videoState)) {
                     mServiceInterface.answer(callId);
                 } else {
                     mServiceInterface.answerVideo(callId, videoState);
@@ -801,7 +773,7 @@
         }
     }
 
-    /** @see ConnectionService#reject(String) */
+    /** @see IConnectionService#reject(String) */
     void reject(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("reject")) {
@@ -813,7 +785,7 @@
         }
     }
 
-    /** @see ConnectionService#playDtmfTone(String,char) */
+    /** @see IConnectionService#playDtmfTone(String,char) */
     void playDtmfTone(Call call, char digit) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("playDtmfTone")) {
@@ -825,7 +797,7 @@
         }
     }
 
-    /** @see ConnectionService#stopDtmfTone(String) */
+    /** @see IConnectionService#stopDtmfTone(String) */
     void stopDtmfTone(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("stopDtmfTone")) {
@@ -938,7 +910,7 @@
             // 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();
-            CallsManager.getInstance().handleConnectionServiceDeath(this);
+            mCallsManager.handleConnectionServiceDeath(this);
             mServiceInterface = null;
         } else {
             mServiceInterface = IConnectionService.Stub.asInterface(binder);
@@ -1004,15 +976,11 @@
         // Make a list of ConnectionServices that are listed as being associated with SIM accounts
         final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap(
                 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1));
-        for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getCallCapablePhoneAccounts()) {
-            PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount(handle);
-            if ((account.getCapabilities() & PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0) {
-                ConnectionServiceWrapper service =
-                        mConnectionServiceRepository.getService(handle.getComponentName(),
-                                handle.getUserHandle());
-                if (service != null) {
-                    simServices.add(service);
-                }
+        for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts()) {
+            ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
+                    handle.getComponentName(), handle.getUserHandle());
+            if (service != null) {
+                simServices.add(service);
             }
         }
 
@@ -1051,7 +1019,7 @@
                         setRemoteServices(callback, simServiceComponentNames, simServiceBinders);
                     }
                 }
-            });
+            }, null);
         }
     }
 
@@ -1068,10 +1036,6 @@
     }
 
     private void noRemoteServices(RemoteServiceCallback callback) {
-        try {
-            callback.onResult(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
-        } catch (RemoteException e) {
-            Log.e(this, e, "Contacting ConnectionService %s", this.getComponentName());
-        }
+        setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
     }
 }
diff --git a/src/com/android/server/telecom/ContactsAsyncHelper.java b/src/com/android/server/telecom/ContactsAsyncHelper.java
index 1fbf5ee..44fa654 100644
--- a/src/com/android/server/telecom/ContactsAsyncHelper.java
+++ b/src/com/android/server/telecom/ContactsAsyncHelper.java
@@ -60,36 +60,14 @@
     // constants
     private static final int EVENT_LOAD_IMAGE = 1;
 
-    private static final Handler sResultHandler = new Handler(Looper.getMainLooper()) {
-        /** Called when loading is done. */
-        @Override
-        public void handleMessage(Message msg) {
-            WorkerArgs args = (WorkerArgs) msg.obj;
-            switch (msg.arg1) {
-                case EVENT_LOAD_IMAGE:
-                    if (args.listener != null) {
-                        Log.d(this, "Notifying listener: " + args.listener.toString() +
-                                " image: " + args.displayPhotoUri + " completed");
-                        args.listener.onImageLoadComplete(msg.what, args.photo, args.photoIcon,
-                                args.cookie);
-                    }
-                    break;
-                default:
-            }
-        }
-    };
-
     /** Handler run on a worker thread to load photo asynchronously. */
-    private static final Handler sThreadHandler;
+    private Handler mThreadHandler;
+    private final TelecomSystem.SyncRoot mLock;
 
-    static {
-        HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
-        thread.start();
-        sThreadHandler = new WorkerHandler(thread.getLooper());
+    public ContactsAsyncHelper(TelecomSystem.SyncRoot lock) {
+        mLock = lock;
     }
 
-    private ContactsAsyncHelper() {}
-
     private static final class WorkerArgs {
         public Context context;
         public Uri displayPhotoUri;
@@ -103,7 +81,7 @@
      * Thread worker class that handles the task of opening the stream and loading
      * the images.
      */
-    private static class WorkerHandler extends Handler {
+    private class WorkerHandler extends Handler {
         public WorkerHandler(Looper looper) {
             super(looper);
         }
@@ -149,15 +127,16 @@
                             }
                         }
                     }
+
+                    // Listener will synchronize as needed
+                    Log.d(this, "Notifying listener: " + args.listener.toString() +
+                            " image: " + args.displayPhotoUri + " completed");
+                    args.listener.onImageLoadComplete(msg.what, args.photo, args.photoIcon,
+                                args.cookie);
                     break;
                 default:
+                    break;
             }
-
-            // send the reply to the enclosing class.
-            Message reply = sResultHandler.obtainMessage(msg.what);
-            reply.arg1 = msg.arg1;
-            reply.obj = msg.obj;
-            reply.sendToTarget();
         }
 
         /**
@@ -212,9 +191,9 @@
      * fourth argument of {@link OnImageLoadCompleteListener#onImageLoadComplete(int, Drawable,
      * Bitmap, Object)}. Can be null, at which the callback will also has null for the argument.
      */
-    public static final void startObtainPhotoAsync(int token, Context context, Uri displayPhotoUri,
+    public final void startObtainPhotoAsync(int token, Context context, Uri displayPhotoUri,
             OnImageLoadCompleteListener listener, Object cookie) {
-        ThreadUtil.checkOnMainThread();
+        ensureAsyncHandlerStarted();
 
         // in case the source caller info is null, the URI will be null as well.
         // just update using the placeholder image in this case.
@@ -234,7 +213,7 @@
         args.listener = listener;
 
         // setup message arguments
-        Message msg = sThreadHandler.obtainMessage(token);
+        Message msg = mThreadHandler.obtainMessage(token);
         msg.arg1 = EVENT_LOAD_IMAGE;
         msg.obj = args;
 
@@ -242,8 +221,14 @@
                 ", displaying default image for now.");
 
         // notify the thread to begin working
-        sThreadHandler.sendMessage(msg);
+        mThreadHandler.sendMessage(msg);
     }
 
-
+    private void ensureAsyncHandlerStarted() {
+        if (mThreadHandler == null) {
+            HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
+            thread.start();
+            mThreadHandler = new WorkerHandler(thread.getLooper());
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index eec1427..6126e66 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -17,7 +17,6 @@
 package com.android.server.telecom;
 
 import android.content.Context;
-import android.telecom.CallState;
 import android.telecom.DisconnectCause;
 import android.telecom.ParcelableConnection;
 import android.telecom.Phone;
@@ -102,6 +101,7 @@
     CreateConnectionProcessor(
             Call call, ConnectionServiceRepository repository, CreateConnectionResponse response,
             PhoneAccountRegistrar phoneAccountRegistrar, Context context) {
+        Log.v(this, "CreateConnectionProcessor created for Call = %s", call);
         mCall = call;
         mRepository = repository;
         mResponse = response;
@@ -168,22 +168,23 @@
         if (mAttemptRecordIterator.hasNext()) {
             attempt = mAttemptRecordIterator.next();
 
-            if (!mPhoneAccountRegistrar.phoneAccountHasPermission(
+            if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
                     attempt.connectionManagerPhoneAccount)) {
                 Log.w(this,
-                        "Connection mgr does not have BIND_CONNECTION_SERVICE for attempt: %s",
-                        attempt);
+                        "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for "
+                                + "attempt: %s", attempt);
                 attemptNextPhoneAccount();
                 return;
             }
 
             // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it
-            // also has BIND_CONNECTION_SERVICE permission.
+            // also requires the BIND_TELECOM_CONNECTION_SERVICE permission.
             if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) &&
-                    !mPhoneAccountRegistrar.phoneAccountHasPermission(attempt.targetPhoneAccount)) {
+                    !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
+                            attempt.targetPhoneAccount)) {
                 Log.w(this,
-                        "Target PhoneAccount does not have BIND_CONNECTION_SERVICE for attempt: %s",
-                        attempt);
+                        "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for "
+                                + "attempt: %s", attempt);
                 attemptNextPhoneAccount();
                 return;
             }
@@ -205,7 +206,6 @@
                 mCall.setConnectionService(service);
                 setTimeoutIfNeeded(service, attempt);
 
-                Log.i(this, "Attempting to call from %s", service.getComponentName());
                 service.createConnection(mCall, new Response(service));
             }
         } else {
@@ -265,8 +265,13 @@
         }
 
         // Connection managers are only allowed to manage SIM subscriptions.
-        PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccount(
+        // TODO: Should this really be checking the "calling user" test for phone account?
+        PhoneAccount targetPhoneAccount = mPhoneAccountRegistrar.getPhoneAccountCheckCallingUser(
                 targetPhoneAccountHandle);
+        if (targetPhoneAccount == null) {
+            Log.d(this, "shouldSetConnectionManager, phone account not found");
+            return false;
+        }
         boolean isSimSubscription = (targetPhoneAccount.getCapabilities() &
                 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) != 0;
         if (!isSimSubscription) {
@@ -324,12 +329,14 @@
             // Next, add the connection manager account as a backup if it can place emergency calls.
             PhoneAccountHandle callManagerHandle = mPhoneAccountRegistrar.getSimCallManager();
             if (mShouldUseConnectionManager && callManagerHandle != null) {
+                // TODO: Should this really be checking the "calling user" test for phone account?
                 PhoneAccount callManager = mPhoneAccountRegistrar
-                        .getPhoneAccount(callManagerHandle);
-                if (callManager.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
+                        .getPhoneAccountCheckCallingUser(callManagerHandle);
+                if (callManager != null && callManager.hasCapabilities(
+                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)) {
                     CallAttemptRecord callAttemptRecord = new CallAttemptRecord(callManagerHandle,
                             mPhoneAccountRegistrar.
-                                    getDefaultOutgoingPhoneAccount(mCall.getHandle().getScheme())
+                                    getOutgoingPhoneAccountForScheme(mCall.getHandle().getScheme())
                     );
 
                     if (!mAttemptRecords.contains(callAttemptRecord)) {
diff --git a/src/com/android/server/telecom/CreateConnectionTimeout.java b/src/com/android/server/telecom/CreateConnectionTimeout.java
index 3f308cc..45305d5 100644
--- a/src/com/android/server/telecom/CreateConnectionTimeout.java
+++ b/src/com/android/server/telecom/CreateConnectionTimeout.java
@@ -20,7 +20,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.os.Handler;
-import android.telecom.CallState;
+import android.os.Looper;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
 import android.telephony.PhoneStateListener;
@@ -37,12 +37,13 @@
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final ConnectionServiceWrapper mConnectionService;
     private final Call mCall;
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
     private boolean mIsRegistered;
     private boolean mIsCallTimedOut;
 
     CreateConnectionTimeout(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
             ConnectionServiceWrapper service, Call call) {
+        super(Looper.getMainLooper());
         mContext = context;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mConnectionService = service;
diff --git a/src/com/android/server/telecom/DockManager.java b/src/com/android/server/telecom/DockManager.java
new file mode 100644
index 0000000..e6ad446
--- /dev/null
+++ b/src/com/android/server/telecom/DockManager.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** Listens for and caches car dock state. */
+class DockManager {
+    interface Listener {
+        void onDockChanged(boolean isDocked);
+    }
+
+    /** Receiver for car dock plugged and unplugged events. */
+    private class DockBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
+                int dockState = intent.getIntExtra(
+                        Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                onDockChanged(dockState);
+            }
+        }
+    }
+
+    private final DockBroadcastReceiver mReceiver;
+
+    /**
+     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+     * load factor before resizing, 1 means we only expect a single thread to
+     * access the map so make only a single shard
+     */
+    private final Set<Listener> mListeners = Collections.newSetFromMap(
+            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
+
+    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+    DockManager(Context context) {
+        mReceiver = new DockBroadcastReceiver();
+
+        // Register for misc other intent broadcasts.
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+        context.registerReceiver(mReceiver, intentFilter);
+    }
+
+    void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    void removeListener(Listener listener) {
+        if (listener != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    boolean isDocked() {
+        switch (mDockState) {
+            case Intent.EXTRA_DOCK_STATE_DESK:
+            case Intent.EXTRA_DOCK_STATE_HE_DESK:
+            case Intent.EXTRA_DOCK_STATE_LE_DESK:
+            case Intent.EXTRA_DOCK_STATE_CAR:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private void onDockChanged(int dockState) {
+        if (mDockState != dockState) {
+            Log.v(this, "onDockChanged: is docked?%b", dockState == Intent.EXTRA_DOCK_STATE_CAR);
+            mDockState = dockState;
+            for (Listener listener : mListeners) {
+                listener.onDockChanged(isDocked());
+            }
+        }
+    }
+
+    /**
+     * Dumps the state of the {@link DockManager}.
+     *
+     * @param pw The {@code IndentingPrintWriter} to write the state to.
+     */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("mIsDocked: " + isDocked());
+    }
+}
diff --git a/src/com/android/server/telecom/DtmfLocalTonePlayer.java b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
index 562f8d3..a0d2862 100644
--- a/src/com/android/server/telecom/DtmfLocalTonePlayer.java
+++ b/src/com/android/server/telecom/DtmfLocalTonePlayer.java
@@ -19,8 +19,13 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.ToneGenerator;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.provider.Settings;
 
+import com.android.internal.util.Preconditions;
+
 // TODO: Needed for move to system service: import com.android.internal.R;
 
 /**
@@ -39,6 +44,17 @@
     /** The context. */
     private final Context mContext;
 
+    /**
+     * Message codes to be used for creating and deleting ToneGenerator object in the tonegenerator
+     * thread.
+     */
+    private static final int EVENT_CREATE_OBJECT = 1;
+    private static final int EVENT_DELETE_OBJECT = 2;
+
+    /** Handler running on the tonegenerator thread. */
+    private Handler mHandler;
+
+
     public DtmfLocalTonePlayer(Context context) {
         mContext = context;
     }
@@ -61,14 +77,15 @@
         if (mCall != call) {
             return;
         }
-
-        if (mToneGenerator == null) {
-            Log.d(this, "playTone: mToneGenerator == null, %c.", c);
-        } else {
-            Log.d(this, "starting local tone: %c.", c);
-            int tone = getMappedTone(c);
-            if (tone != ToneGenerator.TONE_UNKNOWN) {
-                mToneGenerator.startTone(tone, -1 /* toneDuration */);
+        synchronized(this) {
+            if (mToneGenerator == null) {
+                Log.d(this, "playTone: mToneGenerator == null, %c.", c);
+            } else {
+                Log.d(this, "starting local tone: %c.", c);
+                int tone = getMappedTone(c);
+                if (tone != ToneGenerator.TONE_UNKNOWN) {
+                    mToneGenerator.startTone(tone, -1 /* toneDuration */);
+                }
             }
         }
     }
@@ -83,12 +100,13 @@
         if (mCall != call) {
             return;
         }
-
-        if (mToneGenerator == null) {
-            Log.d(this, "stopTone: mToneGenerator == null.");
-        } else {
-            Log.d(this, "stopping local tone.");
-            mToneGenerator.stopTone();
+        synchronized(this) {
+            if (mToneGenerator == null) {
+                Log.d(this, "stopTone: mToneGenerator == null.");
+            } else {
+                Log.d(this, "stopping local tone.");
+                mToneGenerator.stopTone();
+            }
         }
     }
 
@@ -113,14 +131,8 @@
         mCall = call;
 
         if (areLocalTonesEnabled) {
-            if (mToneGenerator == null) {
-                try {
-                    mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF, 80);
-                } catch (RuntimeException e) {
-                    Log.e(this, e, "Error creating local tone generator.");
-                    mToneGenerator = null;
-                }
-            }
+            Log.d(this, "Posting create.");
+            postMessage(EVENT_CREATE_OBJECT);
         }
     }
 
@@ -135,14 +147,78 @@
             stopTone(call);
 
             mCall = null;
+            Log.d(this, "Posting delete.");
+            postMessage(EVENT_DELETE_OBJECT);
+        }
+    }
 
-            if (mToneGenerator != null) {
-                mToneGenerator.release();
-                mToneGenerator = null;
+    /**
+     * Posts a message to the tonegenerator-thread handler. Creates the handler if the handler
+     * has not been instantiated.
+     *
+     * @param messageCode The message to post.
+     */
+    private void postMessage(int messageCode) {
+        synchronized(this) {
+            if (mHandler == null) {
+                mHandler = getNewHandler();
+            }
+
+            if (mHandler == null) {
+                Log.d(this, "Message %d skipped because there is no handler.", messageCode);
+            } else {
+                mHandler.obtainMessage(messageCode, null).sendToTarget();
             }
         }
     }
 
+    /**
+     * Creates a new tonegenerator Handler running in its own thread.
+     */
+    private Handler getNewHandler() {
+        Preconditions.checkState(mHandler == null);
+
+        HandlerThread thread = new HandlerThread("tonegenerator-dtmf");
+        thread.start();
+
+        return new Handler(thread.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                switch(msg.what) {
+                    case EVENT_CREATE_OBJECT:
+                        synchronized(DtmfLocalTonePlayer.this) {
+                            if (mToneGenerator == null) {
+                                try {
+                                    mToneGenerator = new ToneGenerator(
+                                            AudioManager.STREAM_DTMF, 80);
+                                } catch (RuntimeException e) {
+                                    Log.e(this, e, "Error creating local tone generator.");
+                                    mToneGenerator = null;
+                                }
+                            }
+                        }
+                        break;
+                    case EVENT_DELETE_OBJECT:
+                        synchronized(DtmfLocalTonePlayer.this) {
+                            if (mToneGenerator != null) {
+                                mToneGenerator.release();
+                                mToneGenerator = null;
+                            }
+                            // Delete the handler after the tone generator object is deleted by
+                            // the tonegenerator thread.
+                            if (mHandler != null && !mHandler.hasMessages(EVENT_CREATE_OBJECT)) {
+                                // Stop the handler only if there are no pending CREATE messages.
+                                mHandler.removeMessages(EVENT_DELETE_OBJECT);
+                                mHandler.getLooper().quitSafely();
+                                mHandler = null;
+                            }
+                        }
+                        break;
+                }
+            }
+        };
+    }
+
     private static final int getMappedTone(char digit) {
         if (digit >= '0' && digit <= '9') {
             return ToneGenerator.TONE_DTMF_0 + digit - '0';
diff --git a/src/com/android/server/telecom/HeadsetMediaButton.java b/src/com/android/server/telecom/HeadsetMediaButton.java
index f0ea1e9..93dc6de 100644
--- a/src/com/android/server/telecom/HeadsetMediaButton.java
+++ b/src/com/android/server/telecom/HeadsetMediaButton.java
@@ -20,12 +20,15 @@
 import android.content.Intent;
 import android.media.AudioAttributes;
 import android.media.session.MediaSession;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.view.KeyEvent;
 
 /**
  * Static class to handle listening to the headset media buttons.
  */
-final class HeadsetMediaButton extends CallsManagerListenerBase {
+public class HeadsetMediaButton extends CallsManagerListenerBase {
 
     // Types of media button presses
     static final int SHORT_PRESS = 1;
@@ -35,35 +38,72 @@
             .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
             .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).build();
 
+    private static final int MSG_MEDIA_SESSION_INITIALIZE = 0;
+    private static final int MSG_MEDIA_SESSION_SET_ACTIVE = 1;
+
     private final MediaSession.Callback mSessionCallback = new MediaSession.Callback() {
         @Override
         public boolean onMediaButtonEvent(Intent intent) {
             KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
             Log.v(this, "SessionCallback.onMediaButton()...  event = %s.", event);
             if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
-                Log.v(this, "SessionCallback: HEADSETHOOK");
-                boolean consumed = handleHeadsetHook(event);
-                Log.v(this, "==> handleHeadsetHook(): consumed = %b.", consumed);
-                return consumed;
+                synchronized (mLock) {
+                    Log.v(this, "SessionCallback: HEADSETHOOK");
+                    boolean consumed = handleHeadsetHook(event);
+                    Log.v(this, "==> handleHeadsetHook(): consumed = %b.", consumed);
+                    return consumed;
+                }
             }
             return true;
         }
     };
 
+    private final Handler mMediaSessionHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_MEDIA_SESSION_INITIALIZE: {
+                    MediaSession session = new MediaSession(
+                            mContext,
+                            HeadsetMediaButton.class.getSimpleName());
+                    session.setCallback(mSessionCallback);
+                    session.setFlags(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY
+                            | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
+                    session.setPlaybackToLocal(AUDIO_ATTRIBUTES);
+                    mSession = session;
+                    break;
+                }
+                case MSG_MEDIA_SESSION_SET_ACTIVE: {
+                    if (mSession != null) {
+                        boolean activate = msg.arg1 != 0;
+                        if (activate != mSession.isActive()) {
+                            mSession.setActive(activate);
+                        }
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    };
+
+    private final Context mContext;
     private final CallsManager mCallsManager;
+    private final TelecomSystem.SyncRoot mLock;
+    private MediaSession mSession;
 
-    private final MediaSession mSession;
-
-    HeadsetMediaButton(Context context, CallsManager callsManager) {
+    public HeadsetMediaButton(
+            Context context,
+            CallsManager callsManager,
+            TelecomSystem.SyncRoot lock) {
+        mContext = context;
         mCallsManager = callsManager;
+        mLock = lock;
 
         // Create a MediaSession but don't enable it yet. This is a
         // replacement for MediaButtonReceiver
-        mSession = new MediaSession(context, HeadsetMediaButton.class.getSimpleName());
-        mSession.setCallback(mSessionCallback);
-        mSession.setFlags(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY
-                | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
-        mSession.setPlaybackToLocal(AUDIO_ATTRIBUTES);
+        mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_INITIALIZE).sendToTarget();
     }
 
     /**
@@ -86,18 +126,14 @@
     /** ${inheritDoc} */
     @Override
     public void onCallAdded(Call call) {
-        if (!mSession.isActive()) {
-            mSession.setActive(true);
-        }
+        mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 1, 0).sendToTarget();
     }
 
     /** ${inheritDoc} */
     @Override
     public void onCallRemoved(Call call) {
         if (!mCallsManager.hasAnyCalls()) {
-            if (mSession.isActive()) {
-                mSession.setActive(false);
-            }
+            mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget();
         }
     }
 }
diff --git a/src/com/android/server/telecom/HeadsetMediaButtonFactory.java b/src/com/android/server/telecom/HeadsetMediaButtonFactory.java
new file mode 100644
index 0000000..13d5e4f
--- /dev/null
+++ b/src/com/android/server/telecom/HeadsetMediaButtonFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import com.android.server.telecom.components.TelecomService;
+
+import android.content.Context;
+
+/**
+ * This is a TEMPORARY fix to make the {@link HeadsetMediaButton} object injectable for testing.
+ * Class {@link HeadsetMediaButton} itself is not testable because it grabs lots of special stuff
+ * from its {@code Context} that cannot be conveniently mocked.
+ *
+ * TODO: Replace with a better design.
+ */
+public interface HeadsetMediaButtonFactory {
+
+    HeadsetMediaButton create(
+            Context context,
+            CallsManager callsManager,
+            TelecomSystem.SyncRoot lock);
+}
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index e39b5a5..9239288 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -16,11 +16,9 @@
 
 package com.android.server.telecom;
 
-import android.os.Handler;
-import android.os.Message;
+import android.os.Binder;
 import android.telecom.PhoneAccountHandle;
 
-import com.android.internal.os.SomeArgs;
 import com.android.internal.telecom.IInCallAdapter;
 
 /**
@@ -29,320 +27,320 @@
  * binding to it. This adapter can receive commands and updates until the in-call app is unbound.
  */
 class InCallAdapter extends IInCallAdapter.Stub {
-    private static final int MSG_ANSWER_CALL = 0;
-    private static final int MSG_REJECT_CALL = 1;
-    private static final int MSG_PLAY_DTMF_TONE = 2;
-    private static final int MSG_STOP_DTMF_TONE = 3;
-    private static final int MSG_POST_DIAL_CONTINUE = 4;
-    private static final int MSG_DISCONNECT_CALL = 5;
-    private static final int MSG_HOLD_CALL = 6;
-    private static final int MSG_UNHOLD_CALL = 7;
-    private static final int MSG_MUTE = 8;
-    private static final int MSG_SET_AUDIO_ROUTE = 9;
-    private static final int MSG_CONFERENCE = 10;
-    private static final int MSG_SPLIT_FROM_CONFERENCE = 11;
-    private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 12;
-    private static final int MSG_PHONE_ACCOUNT_SELECTED = 13;
-    private static final int MSG_TURN_ON_PROXIMITY_SENSOR = 14;
-    private static final int MSG_TURN_OFF_PROXIMITY_SENSOR = 15;
-    private static final int MSG_MERGE_CONFERENCE = 16;
-    private static final int MSG_SWAP_CONFERENCE = 17;
-
-    private final class InCallAdapterHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            Call call;
-            switch (msg.what) {
-                case MSG_ANSWER_CALL: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        int videoState = (int) args.arg2;
-                        if (call != null) {
-                            mCallsManager.answerCall(call, videoState);
-                        } else {
-                            Log.w(this, "answerCall, unknown call id: %s", msg.obj);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_REJECT_CALL: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        boolean rejectWithMessage = args.argi1 == 1;
-                        String textMessage = (String) args.arg2;
-                        if (call != null) {
-                            mCallsManager.rejectCall(call, rejectWithMessage, textMessage);
-                        } else {
-                            Log.w(this, "setRingback, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_PLAY_DTMF_TONE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.playDtmfTone(call, (char) msg.arg1);
-                    } else {
-                        Log.w(this, "playDtmfTone, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_STOP_DTMF_TONE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.stopDtmfTone(call);
-                    } else {
-                        Log.w(this, "stopDtmfTone, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_POST_DIAL_CONTINUE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.postDialContinue(call, msg.arg1 == 1);
-                    } else {
-                        Log.w(this, "postDialContinue, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_DISCONNECT_CALL:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.disconnectCall(call);
-                    } else {
-                        Log.w(this, "disconnectCall, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_HOLD_CALL:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.holdCall(call);
-                    } else {
-                        Log.w(this, "holdCall, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_UNHOLD_CALL:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        mCallsManager.unholdCall(call);
-                    } else {
-                        Log.w(this, "unholdCall, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_PHONE_ACCOUNT_SELECTED: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        if (call != null) {
-                            mCallsManager.phoneAccountSelected(call,
-                                    (PhoneAccountHandle) args.arg2, args.argi1 == 1);
-                        } else {
-                            Log.w(this, "phoneAccountSelected, unknown call id: %s", args.arg1);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_MUTE:
-                    mCallsManager.mute(msg.arg1 == 1);
-                    break;
-                case MSG_SET_AUDIO_ROUTE:
-                    mCallsManager.setAudioRoute(msg.arg1);
-                    break;
-                case MSG_CONFERENCE: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        call = mCallIdMapper.getCall(args.arg1);
-                        Call otherCall = mCallIdMapper.getCall(args.arg2);
-                        if (call != null && otherCall != null) {
-                            mCallsManager.conference(call, otherCall);
-                        } else {
-                            Log.w(this, "conference, unknown call id: %s", msg.obj);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SPLIT_FROM_CONFERENCE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.splitFromConference();
-                    } else {
-                        Log.w(this, "splitFromConference, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_TURN_ON_PROXIMITY_SENSOR:
-                    mCallsManager.turnOnProximitySensor();
-                    break;
-                case MSG_TURN_OFF_PROXIMITY_SENSOR:
-                    mCallsManager.turnOffProximitySensor((boolean) msg.obj);
-                    break;
-                case MSG_MERGE_CONFERENCE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.mergeConference();
-                    } else {
-                        Log.w(this, "mergeConference, unknown call id: %s", msg.obj);
-                    }
-                    break;
-                case MSG_SWAP_CONFERENCE:
-                    call = mCallIdMapper.getCall(msg.obj);
-                    if (call != null) {
-                        call.swapConference();
-                    } else {
-                        Log.w(this, "swapConference, unknown call id: %s", msg.obj);
-                    }
-                    break;
-            }
-        }
-    }
-
     private final CallsManager mCallsManager;
-    private final Handler mHandler = new InCallAdapterHandler();
     private final CallIdMapper mCallIdMapper;
+    private final TelecomSystem.SyncRoot mLock;
 
     /** Persists the specified parameters. */
-    public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper) {
-        ThreadUtil.checkOnMainThread();
+    public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper,
+            TelecomSystem.SyncRoot lock) {
         mCallsManager = callsManager;
         mCallIdMapper = callIdMapper;
+        mLock = lock;
     }
 
     @Override
     public void answerCall(String callId, int videoState) {
-        Log.d(this, "answerCall(%s,%d)", callId, videoState);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = videoState;
-            mHandler.obtainMessage(MSG_ANSWER_CALL, args).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.d(this, "answerCall(%s,%d)", callId, videoState);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.answerCall(call, videoState);
+                    } else {
+                        Log.w(this, "answerCall, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
-        Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.argi1 = rejectWithMessage ? 1 : 0;
-            args.arg2 = textMessage;
-            mHandler.obtainMessage(MSG_REJECT_CALL, args).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.rejectCall(call, rejectWithMessage, textMessage);
+                    } else {
+                        Log.w(this, "setRingback, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void playDtmfTone(String callId, char digit) {
-        Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, (int) digit, 0, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.playDtmfTone(call, digit);
+                    } else {
+                        Log.w(this, "playDtmfTone, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void stopDtmfTone(String callId) {
-        Log.d(this, "stopDtmfTone(%s)", callId);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.d(this, "stopDtmfTone(%s)", callId);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.stopDtmfTone(call);
+                    } else {
+                        Log.w(this, "stopDtmfTone, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void postDialContinue(String callId, boolean proceed) {
-        Log.d(this, "postDialContinue(%s)", callId);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_POST_DIAL_CONTINUE, proceed ? 1 : 0, 0, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.d(this, "postDialContinue(%s)", callId);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.postDialContinue(call, proceed);
+                    } else {
+                        Log.w(this, "postDialContinue, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void disconnectCall(String callId) {
-        Log.v(this, "disconnectCall: %s", callId);
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_DISCONNECT_CALL, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                Log.v(this, "disconnectCall: %s", callId);
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.disconnectCall(call);
+                    } else {
+                        Log.w(this, "disconnectCall, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void holdCall(String callId) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_HOLD_CALL, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.holdCall(call);
+                    } else {
+                        Log.w(this, "holdCall, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void unholdCall(String callId) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_UNHOLD_CALL, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.unholdCall(call);
+                    } else {
+                        Log.w(this, "unholdCall, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
             boolean setDefault) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = accountHandle;
-            args.argi1 = setDefault? 1 : 0;
-            mHandler.obtainMessage(MSG_PHONE_ACCOUNT_SELECTED, args).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        mCallsManager.phoneAccountSelected(call, accountHandle, setDefault);
+                    } else {
+                        Log.w(this, "phoneAccountSelected, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void mute(boolean shouldMute) {
-        mHandler.obtainMessage(MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mCallsManager.mute(shouldMute);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void setAudioRoute(int route) {
-        mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mCallsManager.setAudioRoute(route);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void conference(String callId, String otherCallId) {
-        if (mCallIdMapper.isValidCallId(callId) &&
-                mCallIdMapper.isValidCallId(otherCallId)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = callId;
-            args.arg2 = otherCallId;
-            mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId) &&
+                        mCallIdMapper.isValidCallId(otherCallId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    Call otherCall = mCallIdMapper.getCall(otherCallId);
+                    if (call != null && otherCall != null) {
+                        mCallsManager.conference(call, otherCall);
+                    } else {
+                        Log.w(this, "conference, unknown call id: %s or %s", callId, otherCallId);
+                    }
+
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void splitFromConference(String callId) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        call.splitFromConference();
+                    } else {
+                        Log.w(this, "splitFromConference, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void mergeConference(String callId) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        call.mergeConference();
+                    } else {
+                        Log.w(this, "mergeConference, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void swapConference(String callId) {
-        if (mCallIdMapper.isValidCallId(callId)) {
-            mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                if (mCallIdMapper.isValidCallId(callId)) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        call.swapConference();
+                    } else {
+                        Log.w(this, "swapConference, unknown call id: %s", callId);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
     @Override
     public void turnOnProximitySensor() {
-        mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mCallsManager.turnOnProximitySensor();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void turnOffProximitySensor(boolean screenOnImmediately) {
-        mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget();
+        long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mCallsManager.turnOffProximitySensor(screenOnImmediately);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 }
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index eef75e3..8a8e4f4 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -26,17 +26,20 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.telecom.AudioState;
-import android.telecom.CallProperties;
-import android.telecom.CallState;
+import android.telecom.CallAudioState;
 import android.telecom.Connection;
+import android.telecom.DefaultDialerManager;
 import android.telecom.InCallService;
 import android.telecom.ParcelableCall;
 import android.telecom.TelecomManager;
+import android.telecom.VideoCallImpl;
 import android.util.ArrayMap;
 
 // TODO: Needed for move to system service: import com.android.internal.R;
@@ -48,6 +51,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -87,7 +91,7 @@
 
         @Override
         public void onVideoCallProviderChanged(Call call) {
-            updateCall(call);
+            updateCall(call, true /* videoProviderChanged */);
         }
 
         @Override
@@ -96,6 +100,11 @@
         }
 
         @Override
+        public void onExtrasChanged(Call call) {
+            updateCall(call);
+        }
+
+        @Override
         public void onHandleChanged(Call call) {
             updateCall(call);
         }
@@ -133,27 +142,39 @@
     /** The in-call app implementations, see {@link IInCallService}. */
     private final Map<ComponentName, IInCallService> mInCallServices = new ArrayMap<>();
 
+    /**
+     * The {@link ComponentName} of the bound In-Call UI Service.
+     */
+    private ComponentName mInCallUIComponentName;
+
     private final CallIdMapper mCallIdMapper = new CallIdMapper("InCall");
 
     /** The {@link ComponentName} of the default InCall UI. */
-    private final ComponentName mInCallComponentName;
+    private final ComponentName mSystemInCallComponentName;
 
     private final Context mContext;
+    private final TelecomSystem.SyncRoot mLock;
+    private final CallsManager mCallsManager;
 
-    public InCallController(Context context) {
+    public InCallController(
+            Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager) {
         mContext = context;
+        mLock = lock;
+        mCallsManager = callsManager;
         Resources resources = mContext.getResources();
 
-        mInCallComponentName = new ComponentName(
+        mSystemInCallComponentName = new ComponentName(
                 resources.getString(R.string.ui_default_package),
                 resources.getString(R.string.incall_default_class));
     }
 
     @Override
     public void onCallAdded(Call call) {
-        if (mInCallServices.isEmpty()) {
-            bind(call);
+        if (!isBoundToServices()) {
+            bindToServices(call);
         } else {
+            adjustServiceBindingsForEmergency();
+
             Log.i(this, "onCallAdded: %s", call);
             // Track the call if we don't already know about it.
             addCall(call);
@@ -161,9 +182,8 @@
             for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                 ComponentName componentName = entry.getKey();
                 IInCallService inCallService = entry.getValue();
-
                 ParcelableCall parcelableCall = toParcelableCall(call,
-                        componentName.equals(mInCallComponentName) /* includeVideoProvider */);
+                        true /* includeVideoProvider */);
                 try {
                     inCallService.addCall(parcelableCall);
                 } catch (RemoteException ignored) {
@@ -175,9 +195,26 @@
     @Override
     public void onCallRemoved(Call call) {
         Log.i(this, "onCallRemoved: %s", call);
-        if (CallsManager.getInstance().getCalls().isEmpty()) {
-            // TODO: Wait for all messages to be delivered to the service before unbinding.
-            unbind();
+        if (mCallsManager.getCalls().isEmpty()) {
+            /** Let's add a 2 second delay before we send unbind to the services to hopefully
+             *  give them enough time to process all the pending messages.
+             */
+            Handler handler = new Handler(Looper.getMainLooper());
+            final Runnable runnableUnbind = new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (mLock) {
+                        // Check again to make sure there are no active calls.
+                        if (mCallsManager.getCalls().isEmpty()) {
+                            unbindFromServices();
+                        }
+                    }
+                }
+            };
+            handler.postDelayed(
+                    runnableUnbind,
+                    Timeouts.getCallRemoveUnbindInCallServicesDelay(
+                            mContext.getContentResolver()));
         }
         call.removeListener(mCallListener);
         mCallIdMapper.removeCall(call);
@@ -197,13 +234,14 @@
     }
 
     @Override
-    public void onAudioStateChanged(AudioState oldAudioState, AudioState newAudioState) {
+    public void onCallAudioStateChanged(CallAudioState oldCallAudioState,
+            CallAudioState newCallAudioState) {
         if (!mInCallServices.isEmpty()) {
-            Log.i(this, "Calling onAudioStateChanged, audioState: %s -> %s", oldAudioState,
-                    newAudioState);
+            Log.i(this, "Calling onAudioStateChanged, audioState: %s -> %s", oldCallAudioState,
+                    newCallAudioState);
             for (IInCallService inCallService : mInCallServices.values()) {
                 try {
-                    inCallService.onAudioStateChanged(newAudioState);
+                    inCallService.onCallAudioStateChanged(newCallAudioState);
                 } catch (RemoteException ignored) {
                 }
             }
@@ -257,84 +295,151 @@
     /**
      * Unbinds an existing bound connection to the in-call app.
      */
-    private void unbind() {
-        ThreadUtil.checkOnMainThread();
+    private void unbindFromServices() {
         Iterator<Map.Entry<ComponentName, InCallServiceConnection>> iterator =
             mServiceConnections.entrySet().iterator();
         while (iterator.hasNext()) {
-            Log.i(this, "Unbinding from InCallService %s");
-            mContext.unbindService(iterator.next().getValue());
+            final Map.Entry<ComponentName, InCallServiceConnection> entry = iterator.next();
+            Log.i(this, "Unbinding from InCallService %s", entry.getKey());
+            try {
+                mContext.unbindService(entry.getValue());
+            } catch (Exception e) {
+                Log.e(this, e, "Exception while unbinding from InCallService");
+            }
             iterator.remove();
         }
         mInCallServices.clear();
     }
 
     /**
-     * Binds to the in-call app if not already connected by binding directly to the saved
-     * component name of the {@link IInCallService} implementation.
+     * Binds to all the UI-providing InCallService as well as system-implemented non-UI
+     * InCallServices. Method-invoker must check {@link #isBoundToServices()} before invoking.
      *
      * @param call The newly added call that triggered the binding to the in-call services.
      */
-    private void bind(Call call) {
-        ThreadUtil.checkOnMainThread();
-        if (mInCallServices.isEmpty()) {
-            PackageManager packageManager = mContext.getPackageManager();
-            Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
+    private void bindToServices(Call call) {
+        PackageManager packageManager = mContext.getPackageManager();
+        Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
 
-            for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) {
-                ServiceInfo serviceInfo = entry.serviceInfo;
-                if (serviceInfo != null) {
-                    boolean hasServiceBindPermission = serviceInfo.permission != null &&
-                            serviceInfo.permission.equals(
-                                    Manifest.permission.BIND_INCALL_SERVICE);
-                    boolean hasControlInCallPermission = packageManager.checkPermission(
-                            Manifest.permission.CONTROL_INCALL_EXPERIENCE,
-                            serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED;
+        List<ComponentName> inCallControlServices = new ArrayList<>();
+        ComponentName inCallUIService = null;
 
-                    if (!hasServiceBindPermission) {
-                        Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " +
-                                serviceInfo.packageName);
-                        continue;
-                    }
-
-                    if (!hasControlInCallPermission) {
-                        Log.w(this,
-                                "InCall UI does not have CONTROL_INCALL_EXPERIENCE permission: " +
-                                        serviceInfo.packageName);
-                        continue;
-                    }
-
-                    InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
-                    ComponentName componentName = new ComponentName(serviceInfo.packageName,
-                            serviceInfo.name);
-
-                    Log.i(this, "Attempting to bind to InCall %s, is dupe? %b ",
-                            serviceInfo.packageName,
-                            mServiceConnections.containsKey(componentName));
-
-                    if (!mServiceConnections.containsKey(componentName)) {
-                        Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
-                        intent.setComponent(componentName);
-
-                        final int bindFlags;
-                        if (mInCallComponentName.equals(componentName)) {
-                            bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT;
-                            if (!call.isIncoming()) {
-                                intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
-                                        call.getExtras());
-                                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
-                                        call.getTargetPhoneAccount());
-                            }
-                        } else {
-                            bindFlags = Context.BIND_AUTO_CREATE;
-                        }
-
-                        if (mContext.bindServiceAsUser(intent, inCallServiceConnection, bindFlags,
-                                UserHandle.CURRENT)) {
-                            mServiceConnections.put(componentName, inCallServiceConnection);
-                        }
-                    }
+        for (ResolveInfo entry :
+                packageManager.queryIntentServices(serviceIntent, PackageManager.GET_META_DATA)) {
+            ServiceInfo serviceInfo = entry.serviceInfo;
+            if (serviceInfo != null) {
+                boolean hasServiceBindPermission = serviceInfo.permission != null &&
+                        serviceInfo.permission.equals(
+                                Manifest.permission.BIND_INCALL_SERVICE);
+                if (!hasServiceBindPermission) {
+                    Log.w(this, "InCallService does not have BIND_INCALL_SERVICE permission: " +
+                            serviceInfo.packageName);
+                    continue;
                 }
+
+                boolean hasControlInCallPermission = packageManager.checkPermission(
+                        Manifest.permission.CONTROL_INCALL_EXPERIENCE,
+                        serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED;
+                boolean isDefaultDialerPackage = Objects.equals(serviceInfo.packageName,
+                        DefaultDialerManager.getDefaultDialerApplication(mContext));
+                if (!hasControlInCallPermission && !isDefaultDialerPackage) {
+                    Log.w(this, "Service does not have CONTROL_INCALL_EXPERIENCE permission: %s"
+                            + " and is not system or default dialer.", serviceInfo.packageName);
+                    continue;
+                }
+
+                boolean isUIService = serviceInfo.metaData != null &&
+                        serviceInfo.metaData.getBoolean(
+                                TelecomManager.METADATA_IN_CALL_SERVICE_UI, false);
+                ComponentName componentName = new ComponentName(serviceInfo.packageName,
+                        serviceInfo.name);
+                if (isUIService) {
+                    // For the main UI service, we always prefer the default dialer.
+                    if (isDefaultDialerPackage) {
+                        inCallUIService = componentName;
+                        Log.i(this, "Found default-dialer's In-Call UI: %s", componentName);
+                    }
+                } else {
+                    // for non-UI services that have passed our checks, add them to the list of
+                    // service to bind to.
+                    inCallControlServices.add(componentName);
+                }
+
+            }
+        }
+
+        // Attempt to bind to the default-dialer InCallService first.
+        if (inCallUIService != null) {
+            // skip default dialer if we have an emergency call or if it failed binding.
+            if (mCallsManager.hasEmergencyCall()) {
+                Log.i(this, "Skipping default-dialer because of emergency call");
+                inCallUIService = null;
+            } else if (!bindToInCallService(inCallUIService, call, "def-dialer")) {
+                Log.event(call, Log.Events.ERROR_LOG,
+                        "InCallService UI failed binding: " + inCallUIService);
+                inCallUIService = null;
+            }
+        }
+
+        if (inCallUIService == null) {
+            // We failed to connect to the default-dialer service, or none was provided. Switch to
+            // the system built-in InCallService UI.
+            inCallUIService = mSystemInCallComponentName;
+            if (!bindToInCallService(inCallUIService, call, "system")) {
+                Log.event(call, Log.Events.ERROR_LOG,
+                        "InCallService system UI failed binding: " + inCallUIService);
+            }
+        }
+        mInCallUIComponentName = inCallUIService;
+
+        // Bind to the control InCallServices
+        for (ComponentName componentName : inCallControlServices) {
+            bindToInCallService(componentName, call, "control");
+        }
+    }
+
+    /**
+     * Binds to the specified InCallService.
+     */
+    private boolean bindToInCallService(ComponentName componentName, Call call, String tag) {
+        if (mInCallServices.containsKey(componentName)) {
+            Log.i(this, "An InCallService already exists: %s", componentName);
+            return true;
+        }
+
+        if (mServiceConnections.containsKey(componentName)) {
+            Log.w(this, "The service is already bound for this component %s", componentName);
+            return true;
+        }
+
+        Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
+        intent.setComponent(componentName);
+        if (call != null && !call.isIncoming()){
+            intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
+                    call.getIntentExtras());
+            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                    call.getTargetPhoneAccount());
+        }
+
+        Log.i(this, "Attempting to bind to [%s] InCall %s, with %s", tag, componentName, intent);
+        InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
+        if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                    UserHandle.CURRENT)) {
+            mServiceConnections.put(componentName, inCallServiceConnection);
+            return true;
+        }
+
+        return false;
+    }
+
+    private void adjustServiceBindingsForEmergency() {
+        if (!Objects.equals(mInCallUIComponentName, mSystemInCallComponentName)) {
+            // The connected UI is not the system UI, so lets check if we should switch them
+            // if there exists an emergency number.
+            if (mCallsManager.hasEmergencyCall()) {
+                // Lets fake a failure here in order to trigger the switch to the system UI.
+                onInCallServiceFailure(mInCallUIComponentName, "emergency adjust");
             }
         }
     }
@@ -348,42 +453,44 @@
      * @param service The {@link IInCallService} implementation.
      */
     private void onConnected(ComponentName componentName, IBinder service) {
-        ThreadUtil.checkOnMainThread();
         Trace.beginSection("onConnected: " + componentName);
         Log.i(this, "onConnected to %s", componentName);
 
         IInCallService inCallService = IInCallService.Stub.asInterface(service);
+        mInCallServices.put(componentName, inCallService);
 
         try {
-            inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),
-                    mCallIdMapper));
-            mInCallServices.put(componentName, inCallService);
+            inCallService.setInCallAdapter(
+                    new InCallAdapter(
+                            mCallsManager,
+                            mCallIdMapper,
+                            mLock));
         } catch (RemoteException e) {
             Log.e(this, e, "Failed to set the in-call adapter.");
             Trace.endSection();
+            onInCallServiceFailure(componentName, "setInCallAdapter");
             return;
         }
 
         // Upon successful connection, send the state of the world to the service.
-        Collection<Call> calls = CallsManager.getInstance().getCalls();
+        Collection<Call> calls = 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.
-                    Log.i(this, "addCall after binding: %s", call);
                     addCall(call);
-
-                    inCallService.addCall(toParcelableCall(call,
-                            componentName.equals(mInCallComponentName) /* includeVideoProvider */));
+                    inCallService.addCall(toParcelableCall(call, true /* includeVideoProvider */));
                 } catch (RemoteException ignored) {
                 }
             }
-            onAudioStateChanged(null, CallsManager.getInstance().getAudioState());
-            onCanAddCallChanged(CallsManager.getInstance().canAddCall());
+            onCallAudioStateChanged(
+                    null,
+                    mCallsManager.getAudioState());
+            onCanAddCallChanged(mCallsManager.canAddCall());
         } else {
-            unbind();
+            unbindFromServices();
         }
         Trace.endSection();
     }
@@ -395,56 +502,76 @@
      */
     private void onDisconnected(ComponentName disconnectedComponent) {
         Log.i(this, "onDisconnected from %s", disconnectedComponent);
-        ThreadUtil.checkOnMainThread();
 
-        if (mInCallServices.containsKey(disconnectedComponent)) {
-            mInCallServices.remove(disconnectedComponent);
-        }
-
+        mInCallServices.remove(disconnectedComponent);
         if (mServiceConnections.containsKey(disconnectedComponent)) {
-            // One of the services that we were bound to has disconnected. If the default in-call UI
-            // has disconnected, disconnect all calls and un-bind all other InCallService
-            // implementations.
-            if (disconnectedComponent.equals(mInCallComponentName)) {
-                Log.i(this, "In-call UI %s disconnected.", disconnectedComponent);
-                CallsManager.getInstance().disconnectAllCalls();
-                unbind();
-            } else {
-                Log.i(this, "In-Call Service %s suddenly disconnected", disconnectedComponent);
-                // Else, if it wasn't the default in-call UI, then one of the other in-call services
-                // disconnected and, well, that's probably their fault.  Clear their state and
-                // ignore.
-                InCallServiceConnection serviceConnection =
-                        mServiceConnections.get(disconnectedComponent);
-
-                // We still need to call unbind even though it disconnected.
-                mContext.unbindService(serviceConnection);
-
-                mServiceConnections.remove(disconnectedComponent);
-                mInCallServices.remove(disconnectedComponent);
-            }
+            // One of the services that we were bound to has unexpectedly disconnected.
+            onInCallServiceFailure(disconnectedComponent, "onDisconnect");
         }
     }
 
     /**
-     * Informs all {@link InCallService} instances of the updated call information.  Changes to the
-     * video provider are only communicated to the default in-call UI.
+     * Handles non-recoverable failures by the InCallService. This method performs cleanup and
+     * special handling when the failure is to the UI InCallService.
+     */
+    private void onInCallServiceFailure(ComponentName componentName, String tag) {
+        Log.i(this, "Cleaning up a failed InCallService [%s]: %s", tag, componentName);
+
+        // We always clean up the connections here. Even in the case where we rebind to the UI
+        // because binding is count based and we could end up double-bound.
+        mInCallServices.remove(componentName);
+        InCallServiceConnection serviceConnection = mServiceConnections.remove(componentName);
+        if (serviceConnection != null) {
+            // We still need to call unbind even though it disconnected.
+            mContext.unbindService(serviceConnection);
+        }
+
+        if (Objects.equals(mInCallUIComponentName, componentName)) {
+            if (!mCallsManager.hasAnyCalls()) {
+                // No calls are left anyway. Lets just disconnect all of them.
+                unbindFromServices();
+                return;
+            }
+
+            // Whenever the UI crashes, we automatically revert to the System UI for the
+            // remainder of the active calls.
+            mInCallUIComponentName = mSystemInCallComponentName;
+            bindToInCallService(mInCallUIComponentName, null, "reconnecting");
+        }
+    }
+
+    /**
+     * Informs all {@link InCallService} instances of the updated call information.
      *
      * @param call The {@link Call}.
      */
     private void updateCall(Call call) {
+        updateCall(call, false /* videoProviderChanged */);
+    }
+
+    /**
+     * Informs all {@link InCallService} instances of the updated call information.
+     *
+     * @param call The {@link Call}.
+     * @param videoProviderChanged {@code true} if the video provider changed, {@code false}
+     *      otherwise.
+     */
+    private void updateCall(Call call, boolean videoProviderChanged) {
         if (!mInCallServices.isEmpty()) {
+            ParcelableCall parcelableCall = toParcelableCall(call,
+                    videoProviderChanged /* includeVideoProvider */);
+            Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall);
+            List<ComponentName> componentsUpdated = new ArrayList<>();
             for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                 ComponentName componentName = entry.getKey();
                 IInCallService inCallService = entry.getValue();
-                ParcelableCall parcelableCall = toParcelableCall(call,
-                        componentName.equals(mInCallComponentName) /* includeVideoProvider */);
-                Log.v(this, "updateCall %s ==> %s", call, parcelableCall);
+                componentsUpdated.add(componentName);
                 try {
                     inCallService.updateCall(parcelableCall);
                 } catch (RemoteException ignored) {
                 }
             }
+            Log.i(this, "Components updated: %s", componentsUpdated);
         }
     }
 
@@ -452,20 +579,26 @@
      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
      *
      * @param call The {@link Call} to parcel.
-     * @param includeVideoProvider When {@code true}, the {@link IVideoProvider} is included in the
-     *      parceled call.  When {@code false}, the {@link IVideoProvider} is not included.
+     * @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.
      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
      */
     private ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider) {
         String callId = mCallIdMapper.getCallId(call);
 
-        int state = call.getState();
+        int state = getParcelableState(call);
         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
+        int properties = convertConnectionToCallProperties(call.getConnectionCapabilities());
+        if (call.isConference()) {
+            properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
+        }
 
         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
         boolean isDefaultSmsAccount =
-                CallsManager.getInstance().getPhoneAccountRegistrar().isUserSelectedSmsPhoneAccount(
-                        call.getTargetPhoneAccount());
+                mCallsManager.getPhoneAccountRegistrar()
+                        .isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
         if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
             capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
         }
@@ -475,19 +608,11 @@
                     capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
         }
 
-        if (state == CallState.DIALING) {
-            capabilities = removeCapability(
-                    capabilities, android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL);
-            capabilities = removeCapability(
-                    capabilities, android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE);
-        }
-
-        if (state == CallState.ABORTED) {
-            state = CallState.DISCONNECTED;
-        }
-
-        if (call.isLocallyDisconnecting() && state != CallState.DISCONNECTED) {
-            state = CallState.DISCONNECTING;
+        if (state == android.telecom.Call.STATE_DIALING) {
+            capabilities = removeCapability(capabilities,
+                    android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+            capabilities = removeCapability(capabilities,
+                    android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
         }
 
         String parentCallId = null;
@@ -528,7 +653,6 @@
             }
         }
 
-        int properties = call.isConference() ? CallProperties.CONFERENCE : 0;
         return new ParcelableCall(
                 callId,
                 state,
@@ -543,15 +667,59 @@
                 call.getCallerDisplayNamePresentation(),
                 call.getGatewayInfo(),
                 call.getTargetPhoneAccount(),
+                includeVideoProvider,
                 includeVideoProvider ? call.getVideoProvider() : null,
                 parentCallId,
                 childCallIds,
                 call.getStatusHints(),
                 call.getVideoState(),
                 conferenceableCallIds,
+                call.getIntentExtras(),
                 call.getExtras());
     }
 
+    private static int getParcelableState(Call call) {
+        int state = CallState.NEW;
+        switch (call.getState()) {
+            case CallState.ABORTED:
+            case CallState.DISCONNECTED:
+                state = android.telecom.Call.STATE_DISCONNECTED;
+                break;
+            case CallState.ACTIVE:
+                state = android.telecom.Call.STATE_ACTIVE;
+                break;
+            case CallState.CONNECTING:
+                state = android.telecom.Call.STATE_CONNECTING;
+                break;
+            case CallState.DIALING:
+                state = android.telecom.Call.STATE_DIALING;
+                break;
+            case CallState.DISCONNECTING:
+                state = android.telecom.Call.STATE_DISCONNECTING;
+                break;
+            case CallState.NEW:
+                state = android.telecom.Call.STATE_NEW;
+                break;
+            case CallState.ON_HOLD:
+                state = android.telecom.Call.STATE_HOLDING;
+                break;
+            case CallState.RINGING:
+                state = android.telecom.Call.STATE_RINGING;
+                break;
+            case CallState.SELECT_PHONE_ACCOUNT:
+                state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
+                break;
+        }
+
+        // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
+        // Unless we're disconnect*ED*, in which case leave it at that.
+        if (call.isLocallyDisconnecting() &&
+                (state != android.telecom.Call.STATE_DISCONNECTED)) {
+            state = android.telecom.Call.STATE_DISCONNECTING;
+        }
+        return state;
+    }
+
     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
         Connection.CAPABILITY_HOLD,
         android.telecom.Call.Details.CAPABILITY_HOLD,
@@ -565,9 +733,6 @@
         Connection.CAPABILITY_SWAP_CONFERENCE,
         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
 
-        Connection.CAPABILITY_UNUSED,
-        android.telecom.Call.Details.CAPABILITY_UNUSED,
-
         Connection.CAPABILITY_RESPOND_VIA_TEXT,
         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
 
@@ -577,17 +742,23 @@
         Connection.CAPABILITY_MANAGE_CONFERENCE,
         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
 
-        Connection.CAPABILITY_SUPPORTS_VT_LOCAL,
-        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL,
+        Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
 
-        Connection.CAPABILITY_SUPPORTS_VT_REMOTE,
-        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE,
+        Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
 
-        Connection.CAPABILITY_HIGH_DEF_AUDIO,
-        android.telecom.Call.Details.CAPABILITY_HIGH_DEF_AUDIO,
+        Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
 
-        Connection.CAPABILITY_VoWIFI,
-        android.telecom.Call.Details.CAPABILITY_VoWIFI,
+        Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
+
+        Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
+
+        Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
+        android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
 
         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
@@ -595,8 +766,11 @@
         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
 
-        Connection.CAPABILITY_GENERIC_CONFERENCE,
-        android.telecom.Call.Details.CAPABILITY_GENERIC_CONFERENCE
+        Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
+        android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
+
+        Connection.CAPABILITY_CAN_PAUSE_VIDEO,
+        android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO
     };
 
     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
@@ -609,6 +783,30 @@
         return callCapabilities;
     }
 
+    private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
+        Connection.CAPABILITY_HIGH_DEF_AUDIO,
+        android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
+
+        Connection.CAPABILITY_WIFI,
+        android.telecom.Call.Details.PROPERTY_WIFI,
+
+        Connection.CAPABILITY_GENERIC_CONFERENCE,
+        android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
+
+        Connection.CAPABILITY_SHOW_CALLBACK_NUMBER,
+        android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
+    };
+
+    private static int convertConnectionToCallProperties(int connectionCapabilities) {
+        int callProperties = 0;
+        for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
+            if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionCapabilities) != 0) {
+                callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
+            }
+        }
+        return callProperties;
+    }
+
     /**
      * Adds the call to the list of calls tracked by the {@link InCallController}.
      * @param call The call to add.
@@ -620,6 +818,10 @@
         }
     }
 
+    private boolean isBoundToServices() {
+        return !mInCallServices.isEmpty();
+    }
+
     /**
      * Removes the specified capability from the set of capabilities bits and returns the new set.
      */
diff --git a/src/com/android/server/telecom/InCallToneMonitor.java b/src/com/android/server/telecom/InCallToneMonitor.java
index 32d0924..afe0f06 100644
--- a/src/com/android/server/telecom/InCallToneMonitor.java
+++ b/src/com/android/server/telecom/InCallToneMonitor.java
@@ -17,7 +17,8 @@
 package com.android.server.telecom;
 
 import android.media.ToneGenerator;
-import android.telecom.CallState;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
 
 import java.util.Collection;
 
@@ -78,4 +79,36 @@
             }
         }
     }
+
+    /**
+     * Handles requests received via the {@link VideoProviderProxy} requesting a change in the video
+     * state of the call by the peer.  If the request involves the peer turning their camera on,
+     * the call waiting tone is played to inform the user of the incoming request.
+     *
+     * @param call The call.
+     * @param videoProfile The requested video profile.
+     */
+    @Override
+    public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
+        if (videoProfile == null) {
+            return;
+        }
+
+        if (mCallsManager.getForegroundCall() != call) {
+            // We only play tones for foreground calls.
+            return;
+        }
+
+        int previousVideoState = call.getVideoState();
+        int newVideoState = videoProfile.getVideoState();
+        Log.v(this, "onSessionModifyRequestReceived : videoProfile = " + VideoProfile
+                .videoStateToString(newVideoState));
+
+        boolean isUpgradeRequest = !VideoProfile.isReceptionEnabled(previousVideoState) &&
+                VideoProfile.isReceptionEnabled(newVideoState);
+
+        if (isUpgradeRequest) {
+            mPlayerFactory.createPlayer(InCallTonePlayer.TONE_VIDEO_UPGRADE).startTone();
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index 5afc67f..0d2e3c4 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -33,13 +33,15 @@
      */
     public static class Factory {
         private final CallAudioManager mCallAudioManager;
+        private final TelecomSystem.SyncRoot mLock;
 
-        Factory(CallAudioManager callAudioManager) {
+        Factory(CallAudioManager callAudioManager, TelecomSystem.SyncRoot lock) {
             mCallAudioManager = callAudioManager;
+            mLock = lock;
         }
 
         InCallTonePlayer createPlayer(int tone) {
-            return new InCallTonePlayer(tone, mCallAudioManager);
+            return new InCallTonePlayer(tone, mCallAudioManager, mLock);
         }
     }
 
@@ -58,6 +60,7 @@
     public static final int TONE_RING_BACK = 11;
     public static final int TONE_UNOBTAINABLE_NUMBER = 12;
     public static final int TONE_VOICE_PRIVACY = 13;
+    public static final int TONE_VIDEO_UPGRADE = 14;
 
     private static final int RELATIVE_VOLUME_EMERGENCY = 100;
     private static final int RELATIVE_VOLUME_HIPRI = 80;
@@ -89,15 +92,22 @@
     /** Current state of the tone player. */
     private int mState;
 
+    /** Telecom lock object. */
+    private final TelecomSystem.SyncRoot mLock;
+
     /**
      * Initializes the tone player. Private; use the {@link Factory} to create tone players.
      *
      * @param toneId ID of the tone to play, see TONE_* constants.
      */
-    private InCallTonePlayer(int toneId, CallAudioManager callAudioManager) {
+    private InCallTonePlayer(
+            int toneId,
+            CallAudioManager callAudioManager,
+            TelecomSystem.SyncRoot lock) {
         mState = STATE_OFF;
         mToneId = toneId;
         mCallAudioManager = callAudioManager;
+        mLock = lock;
     }
 
     /** {@inheritDoc} */
@@ -174,6 +184,12 @@
                 case TONE_VOICE_PRIVACY:
                     // TODO: fill in.
                     throw new IllegalStateException("Voice privacy tone NYI.");
+                case TONE_VIDEO_UPGRADE:
+                    // Similar to the call waiting tone, but does not repeat.
+                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMillis = 4000;
+                    break;
                 default:
                     throw new IllegalStateException("Bad toneId: " + mToneId);
             }
@@ -222,8 +238,6 @@
     }
 
     void startTone() {
-        ThreadUtil.checkOnMainThread();
-
         sTonesPlaying++;
         if (sTonesPlaying == 1) {
             mCallAudioManager.setIsTonePlaying(true);
@@ -249,10 +263,12 @@
         // Release focus on the main thread.
         mMainThreadHandler.post(new Runnable() {
             @Override public void run() {
-                if (sTonesPlaying == 0) {
-                    Log.wtf(this, "Over-releasing focus for tone player.");
-                } else if (--sTonesPlaying == 0) {
-                    mCallAudioManager.setIsTonePlaying(false);
+                synchronized (mLock) {
+                    if (sTonesPlaying == 0) {
+                        Log.wtf(this, "Over-releasing focus for tone player.");
+                    } else if (--sTonesPlaying == 0) {
+                        mCallAudioManager.setIsTonePlaying(false);
+                    }
                 }
             }
         });
diff --git a/src/com/android/server/telecom/InCallWakeLockController.java b/src/com/android/server/telecom/InCallWakeLockController.java
index d97e171..a6c63c3 100644
--- a/src/com/android/server/telecom/InCallWakeLockController.java
+++ b/src/com/android/server/telecom/InCallWakeLockController.java
@@ -16,14 +16,16 @@
 
 package com.android.server.telecom;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import android.content.Context;
 import android.os.PowerManager;
-import android.telecom.CallState;
 
 /**
  * Handles acquisition and release of wake locks relating to call state.
  */
-class InCallWakeLockController extends CallsManagerListenerBase {
+@VisibleForTesting
+public class InCallWakeLockController extends CallsManagerListenerBase {
 
     private static final String TAG = "InCallWakeLockContoller";
 
@@ -31,12 +33,14 @@
     private final PowerManager.WakeLock mFullWakeLock;
     private final CallsManager mCallsManager;
 
-    InCallWakeLockController(Context context, CallsManager callsManager) {
+    @VisibleForTesting
+    public InCallWakeLockController(Context context, CallsManager callsManager) {
         mContext = context;
         mCallsManager = callsManager;
 
         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mFullWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+        mFullWakeLock.setReferenceCounted(false);
 
         callsManager.addListener(this);
     }
diff --git a/src/com/android/server/telecom/InCallWakeLockControllerFactory.java b/src/com/android/server/telecom/InCallWakeLockControllerFactory.java
new file mode 100644
index 0000000..86335ba
--- /dev/null
+++ b/src/com/android/server/telecom/InCallWakeLockControllerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.Context;
+
+/**
+ * This is a TEMPORARY fix to make the {@link InCallWakeLockController} object injectable for
+ * testing. Class {@link InCallWakeLockController} itself is not testable because it grabs lots of
+ * special stuff from its {@code Context} that cannot be conveniently mocked.
+ *
+ * TODO: Replace with a better design.
+ */
+public interface InCallWakeLockControllerFactory {
+
+    InCallWakeLockController create(Context context, CallsManager callsManager);
+}
diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java
index 3ec8267..f0ee3fe 100644
--- a/src/com/android/server/telecom/Log.java
+++ b/src/com/android/server/telecom/Log.java
@@ -19,19 +19,190 @@
 import android.net.Uri;
 import android.telecom.PhoneAccount;
 import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.IllegalFormatException;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
 
 /**
  * Manages logging for the entire module.
  */
+@VisibleForTesting
 public class Log {
 
+    /**
+     * 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 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_ACTIVE = "SET_ACTIVE";
+        public static final String SET_HOLD = "SET_HOLD";
+        public static final String SET_RINGING = "SET_RINGING";
+        public static final String SET_DISCONNECTED = "SET_DISCONNECTED";
+        public static final String SET_DISCONNECTING = "SET_DISCONNECTING";
+        public static final String SET_SELECT_PHONE_ACCOUNT = "SET_SELECT_PHONE_ACCOUNT";
+        public static final String REQUEST_HOLD = "REQUEST_HOLD";
+        public static final String REQUEST_UNHOLD = "REQUEST_UNHOLD";
+        public static final String REQUEST_DISCONNECT = "REQUEST_DISCONNECT";
+        public static final String REQUEST_ACCEPT = "REQUEST_ACCEPT";
+        public static final String REQUEST_REJECT = "REQUEST_REJECT";
+        public static final String START_DTMF = "START_DTMF";
+        public static final String STOP_DTMF = "STOP_DTMF";
+        public static final String START_RINGER = "START_RINGER";
+        public static final String STOP_RINGER = "STOP_RINGER";
+        public static final String START_CALL_WAITING_TONE = "START_CALL_WAITING_TONE";
+        public static final String STOP_CALL_WAITING_TONE = "STOP_CALL_WAITING_TONE";
+        public static final String START_CONNECTION = "START_CONNECTION";
+        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 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 AUDIO_ROUTE = "AUDIO_ROUTE";
+        public static final String ERROR_LOG = "ERROR";
+
+        /**
+         * 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.
+         */
+        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);
+                }};
+    }
+
+    public static class CallEvent {
+        public String eventId;
+        public long time;
+        public Object data;
+
+        public CallEvent(String eventId, long time, Object data) {
+            this.eventId = eventId;
+            this.time = time;
+            this.data = data;
+        }
+    }
+
+    public static class CallEventRecord {
+        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;
+        private final int mId;
+
+        public CallEventRecord(Call call) {
+            mCall = call;
+            mId = ++sNextId;
+        }
+
+        public Call getCall() {
+            return mCall;
+        }
+
+        public void addEvent(String event, Object data) {
+            mEvents.add(new CallEvent(event, System.currentTimeMillis(), data));
+            Log.i("Event", "Call %d: %s, %s", mId, event, data);
+        }
+
+        public void dump(IndentingPrintWriter pw) {
+            Map<String, CallEvent> pendingResponses = new HashMap<>();
+
+            pw.print("Call ");
+            pw.print(mId);
+            pw.print(" [");
+            pw.print(sDateFormat.format(new Date(mCall.getCreationTimeMillis())));
+            pw.print("]");
+            pw.println(mCall.isIncoming() ? "(MT - incoming)" : "(MO - outgoing)");
+
+            pw.increaseIndent();
+            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);
+                if (event.data != null) {
+                    pw.print(" (");
+                    Object data = event.data;
+
+                    if (data instanceof Call) {
+                        // If the data is another call, then change the data to the call's CallEvent
+                        // ID instead.
+                        CallEventRecord record = mCallEventRecordMap.get(data);
+                        if (record != null) {
+                            data = "Call " + record.mId;
+                        }
+                    }
+
+                    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.println();
+            }
+            pw.decreaseIndent();
+        }
+    }
+
+    public static final int MAX_CALLS_TO_CACHE = 5;  // Arbitrarily chosen.
+
     // Generic tag for all In Call logging
-    private static final String TAG = "Telecom";
+    @VisibleForTesting
+    public static String TAG = "Telecom";
 
     public static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
     public static final boolean SYSTRACE_DEBUG = false; /* STOP SHIP if true */
@@ -41,8 +212,47 @@
     public static final boolean WARN = isLoggable(android.util.Log.WARN);
     public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
 
+    private static final Map<Call, CallEventRecord> mCallEventRecordMap = new HashMap<>();
+    private static final LinkedBlockingQueue<CallEventRecord> mCallEventRecords =
+            new LinkedBlockingQueue<CallEventRecord>(MAX_CALLS_TO_CACHE);
+
     private Log() {}
 
+    @VisibleForTesting
+    public static void setTag(String tag) {
+        TAG = tag;
+    }
+
+    public static void event(Call call, String event) {
+        event(call, event, null);
+    }
+
+    public static void event(Call call, String event, Object data) {
+        if (call == null) {
+            Log.i(TAG, "Non-call EVENT: %s, %s", event, data);
+            return;
+        }
+        synchronized (mCallEventRecords) {
+            if (!mCallEventRecordMap.containsKey(call)) {
+                // First remove the oldest entry if no new ones exist.
+                if (mCallEventRecords.remainingCapacity() == 0) {
+                    CallEventRecord record = mCallEventRecords.poll();
+                    if (record != null) {
+                        mCallEventRecordMap.remove(record.getCall());
+                    }
+                }
+
+                // Now add a new entry
+                CallEventRecord newRecord = new CallEventRecord(call);
+                mCallEventRecords.add(newRecord);
+                mCallEventRecordMap.put(call, newRecord);
+            }
+
+            CallEventRecord record = mCallEventRecordMap.get(call);
+            record.addEvent(event, data);
+        }
+    }
+
     public static boolean isLoggable(int level) {
         return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
     }
@@ -132,27 +342,35 @@
             return String.valueOf(pii);
         }
 
+        StringBuilder sb = new StringBuilder();
         if (pii instanceof Uri) {
             Uri uri = (Uri) pii;
+            String scheme = uri.getScheme();
 
-            // All Uri's which are not "tel" go through normal pii() method.
-            if (!PhoneAccount.SCHEME_TEL.equals(uri.getScheme())) {
-                return pii(pii);
+            if (!TextUtils.isEmpty(scheme)) {
+                sb.append(scheme).append(":");
+            }
+
+            String textToObfuscate = uri.getSchemeSpecificPart();
+            if (PhoneAccount.SCHEME_TEL.equals(scheme)) {
+                for (int i = 0; i < textToObfuscate.length(); i++) {
+                    char c = textToObfuscate.charAt(i);
+                    sb.append(PhoneNumberUtils.isDialable(c) ? "*" : c);
+                }
+            } else if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
+                for (int i = 0; i < textToObfuscate.length(); i++) {
+                    char c = textToObfuscate.charAt(i);
+                    if (c != '@' && c != '.') {
+                        c = '*';
+                    }
+                    sb.append(c);
+                }
             } else {
-                pii = uri.getSchemeSpecificPart();
+                sb.append(pii(pii));
             }
         }
 
-        String originalString = String.valueOf(pii);
-        StringBuilder stringBuilder = new StringBuilder(originalString.length());
-        for (char c : originalString.toCharArray()) {
-            if (PhoneNumberUtils.isDialable(c)) {
-                stringBuilder.append('*');
-            } else {
-                stringBuilder.append(c);
-            }
-        }
-        return stringBuilder.toString();
+        return sb.toString();
     }
 
     /**
@@ -167,6 +385,15 @@
         return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
     }
 
+    public static void dumpCallEvents(IndentingPrintWriter pw) {
+        pw.println("Historical Calls:");
+        pw.increaseIndent();
+        for (CallEventRecord callEventRecord : mCallEventRecords) {
+            callEventRecord.dump(pw);
+        }
+        pw.decreaseIndent();
+    }
+
     private static String secureHash(byte[] input) {
         MessageDigest messageDigest;
         try {
diff --git a/src/com/android/server/telecom/MissedCallNotifier.java b/src/com/android/server/telecom/MissedCallNotifier.java
index 2c1e78b..5a88c34 100644
--- a/src/com/android/server/telecom/MissedCallNotifier.java
+++ b/src/com/android/server/telecom/MissedCallNotifier.java
@@ -16,333 +16,18 @@
 
 package com.android.server.telecom;
 
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.TaskStackBuilder;
-import android.content.AsyncQueryHandler;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.UserHandle;
-import android.provider.CallLog;
-import android.provider.CallLog.Calls;
-import android.telecom.CallState;
-import android.telecom.DisconnectCause;
-import android.telecom.PhoneAccount;
-import android.telephony.PhoneNumberUtils;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
-
-// TODO: Needed for move to system service: import com.android.internal.R;
-
 /**
  * Creates a notification for calls that the user missed (neither answered nor rejected).
- * TODO: Make TelephonyManager.clearMissedCalls call into this class.
  */
-class MissedCallNotifier extends CallsManagerListenerBase {
+public interface MissedCallNotifier extends CallsManager.CallsManagerListener {
 
-    private static final String[] CALL_LOG_PROJECTION = new String[] {
-        Calls._ID,
-        Calls.NUMBER,
-        Calls.NUMBER_PRESENTATION,
-        Calls.DATE,
-        Calls.DURATION,
-        Calls.TYPE,
-    };
+    void clearMissedCalls();
 
-    private static final int CALL_LOG_COLUMN_ID = 0;
-    private static final int CALL_LOG_COLUMN_NUMBER = 1;
-    private static final int CALL_LOG_COLUMN_NUMBER_PRESENTATION = 2;
-    private static final int CALL_LOG_COLUMN_DATE = 3;
-    private static final int CALL_LOG_COLUMN_DURATION = 4;
-    private static final int CALL_LOG_COLUMN_TYPE = 5;
+    void showMissedCallNotification(Call call);
 
-    private static final int MISSED_CALL_NOTIFICATION_ID = 1;
-
-    private final Context mContext;
-    private final NotificationManager mNotificationManager;
-
-    // Used to track the number of missed calls.
-    private int mMissedCallCount = 0;
-
-    MissedCallNotifier(Context context) {
-        mContext = context;
-        mNotificationManager =
-                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-
-        updateOnStartup();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onCallStateChanged(Call call, int oldState, int newState) {
-        if (oldState == CallState.RINGING && newState == CallState.DISCONNECTED &&
-                call.getDisconnectCause().getCode() == DisconnectCause.MISSED) {
-            showMissedCallNotification(call);
-        }
-    }
-
-    /** Clears missed call notification and marks the call log's missed calls as read. */
-    void clearMissedCalls() {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                // Clear the list of new missed calls from the call log.
-                ContentValues values = new ContentValues();
-                values.put(Calls.NEW, 0);
-                values.put(Calls.IS_READ, 1);
-                StringBuilder where = new StringBuilder();
-                where.append(Calls.NEW);
-                where.append(" = 1 AND ");
-                where.append(Calls.TYPE);
-                where.append(" = ?");
-                mContext.getContentResolver().update(Calls.CONTENT_URI, values, where.toString(),
-                        new String[]{ Integer.toString(Calls.MISSED_TYPE) });
-            }
-        });
-        cancelMissedCallNotification();
-    }
-
-    /**
-     * Create a system notification for the missed call.
-     *
-     * @param call The missed call.
-     */
-    void showMissedCallNotification(Call call) {
-        mMissedCallCount++;
-
-        final int titleResId;
-        final String expandedText;  // The text in the notification's line 1 and 2.
-
-        // Display the first line of the notification:
-        // 1 missed call: <caller name || handle>
-        // More than 1 missed call: <number of calls> + "missed calls"
-        if (mMissedCallCount == 1) {
-            titleResId = R.string.notification_missedCallTitle;
-            expandedText = getNameForCall(call);
-        } else {
-            titleResId = R.string.notification_missedCallsTitle;
-            expandedText =
-                    mContext.getString(R.string.notification_missedCallsMsg, mMissedCallCount);
-        }
-
-        // Create the notification.
-        Notification.Builder builder = new Notification.Builder(mContext);
-        builder.setSmallIcon(android.R.drawable.stat_notify_missed_call)
-                .setColor(mContext.getResources().getColor(R.color.theme_color))
-                .setWhen(call.getCreationTimeMillis())
-                .setContentTitle(mContext.getText(titleResId))
-                .setContentText(expandedText)
-                .setContentIntent(createCallLogPendingIntent())
-                .setAutoCancel(true)
-                .setDeleteIntent(createClearMissedCallsPendingIntent());
-
-        Uri handleUri = call.getHandle();
-        String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart();
-
-        // Add additional actions when there is only 1 missed call, like call-back and SMS.
-        if (mMissedCallCount == 1) {
-            Log.d(this, "Add actions with number %s.", Log.piiHandle(handle));
-
-            if (!TextUtils.isEmpty(handle)
-                    && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))) {
-                builder.addAction(R.drawable.stat_sys_phone_call,
-                        mContext.getString(R.string.notification_missedCall_call_back),
-                        createCallBackPendingIntent(handleUri));
-
-                builder.addAction(R.drawable.ic_text_holo_dark,
-                        mContext.getString(R.string.notification_missedCall_message),
-                        createSendSmsFromNotificationPendingIntent(handleUri));
-            }
-
-            Bitmap photoIcon = call.getPhotoIcon();
-            if (photoIcon != null) {
-                builder.setLargeIcon(photoIcon);
-            } else {
-                Drawable photo = call.getPhoto();
-                if (photo != null && photo instanceof BitmapDrawable) {
-                    builder.setLargeIcon(((BitmapDrawable) photo).getBitmap());
-                }
-            }
-        } else {
-            Log.d(this, "Suppress actions. handle: %s, missedCalls: %d.", Log.piiHandle(handle),
-                    mMissedCallCount);
-        }
-
-        Notification notification = builder.build();
-        configureLedOnNotification(notification);
-
-        Log.i(this, "Adding missed call notification for %s.", call);
-        mNotificationManager.notifyAsUser(
-                null /* tag */ , MISSED_CALL_NOTIFICATION_ID, notification, UserHandle.CURRENT);
-    }
-
-    /** Cancels the "missed call" notification. */
-    private void cancelMissedCallNotification() {
-        // Reset the number of missed calls to 0.
-        mMissedCallCount = 0;
-        mNotificationManager.cancel(MISSED_CALL_NOTIFICATION_ID);
-    }
-
-    /**
-     * Returns the name to use in the missed call notification.
-     */
-    private String getNameForCall(Call call) {
-        String handle = call.getHandle() == null ? null : call.getHandle().getSchemeSpecificPart();
-        String name = call.getName();
-
-        if (!TextUtils.isEmpty(name) && TextUtils.isGraphic(name)) {
-            return name;
-        } else if (!TextUtils.isEmpty(handle)) {
-            // A handle should always be displayed LTR using {@link BidiFormatter} regardless of the
-            // content of the rest of the notification.
-            // TODO: Does this apply to SIP addresses?
-            BidiFormatter bidiFormatter = BidiFormatter.getInstance();
-            return bidiFormatter.unicodeWrap(handle, TextDirectionHeuristics.LTR);
-        } else {
-            // Use "unknown" if the call is unidentifiable.
-            return mContext.getString(R.string.unknown);
-        }
-    }
-
-    /**
-     * Creates a new pending intent that sends the user to the call log.
-     *
-     * @return The pending intent.
-     */
-    private PendingIntent createCallLogPendingIntent() {
-        Intent intent = new Intent(Intent.ACTION_VIEW, null);
-        intent.setType(CallLog.Calls.CONTENT_TYPE);
-
-        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext);
-        taskStackBuilder.addNextIntent(intent);
-
-        return taskStackBuilder.getPendingIntent(0, 0);
-    }
-
-    /**
-     * Creates an intent to be invoked when the missed call notification is cleared.
-     */
-    private PendingIntent createClearMissedCallsPendingIntent() {
-        return createTelecomPendingIntent(
-                TelecomBroadcastReceiver.ACTION_CLEAR_MISSED_CALLS, null);
-    }
-
-    /**
-     * Creates an intent to be invoked when the user opts to "call back" from the missed call
-     * notification.
-     *
-     * @param handle The handle to call back.
-     */
-    private PendingIntent createCallBackPendingIntent(Uri handle) {
-        return createTelecomPendingIntent(
-                TelecomBroadcastReceiver.ACTION_CALL_BACK_FROM_NOTIFICATION, handle);
-    }
-
-    /**
-     * Creates an intent to be invoked when the user opts to "send sms" from the missed call
-     * notification.
-     */
-    private PendingIntent createSendSmsFromNotificationPendingIntent(Uri handle) {
-        return createTelecomPendingIntent(
-                TelecomBroadcastReceiver.ACTION_SEND_SMS_FROM_NOTIFICATION,
-                Uri.fromParts(Constants.SCHEME_SMSTO, handle.getSchemeSpecificPart(), null));
-    }
-
-    /**
-     * Creates generic pending intent from the specified parameters to be received by
-     * {@link TelecomBroadcastReceiver}.
-     *
-     * @param action The intent action.
-     * @param data The intent data.
-     */
-    private PendingIntent createTelecomPendingIntent(String action, Uri data) {
-        Intent intent = new Intent(action, data, mContext, TelecomBroadcastReceiver.class);
-        return PendingIntent.getBroadcast(mContext, 0, intent, 0);
-    }
-
-    /**
-     * Configures a notification to emit the blinky notification light.
-     */
-    private void configureLedOnNotification(Notification notification) {
-        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
-        notification.defaults |= Notification.DEFAULT_LIGHTS;
-    }
-
-    /**
-     * Adds the missed call notification on startup if there are unread missed calls.
-     */
-    private void updateOnStartup() {
-        Log.d(this, "updateOnStartup()...");
-
-        // instantiate query handler
-        AsyncQueryHandler queryHandler = new AsyncQueryHandler(mContext.getContentResolver()) {
-            @Override
-            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-                Log.d(MissedCallNotifier.this, "onQueryComplete()...");
-                if (cursor != null) {
-                    try {
-                        while (cursor.moveToNext()) {
-                            // Get data about the missed call from the cursor
-                            final String handleString = cursor.getString(CALL_LOG_COLUMN_NUMBER);
-                            final int presentation =
-                                    cursor.getInt(CALL_LOG_COLUMN_NUMBER_PRESENTATION);
-                            final long date = cursor.getLong(CALL_LOG_COLUMN_DATE);
-
-                            final Uri handle;
-                            if (presentation != Calls.PRESENTATION_ALLOWED
-                                    || TextUtils.isEmpty(handleString)) {
-                                handle = null;
-                            } else {
-                                handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(handleString) ?
-                                        PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
-                                                handleString, null);
-                            }
-
-                            // Convert the data to a call object
-                            Call call = new Call(mContext, null, null, null, null, null, true,
-                                    false);
-                            call.setDisconnectCause(new DisconnectCause(DisconnectCause.MISSED));
-                            call.setState(CallState.DISCONNECTED);
-                            call.setCreationTimeMillis(date);
-
-                            // Listen for the update to the caller information before posting the
-                            // notification so that we have the contact info and photo.
-                            call.addListener(new Call.ListenerBase() {
-                                @Override
-                                public void onCallerInfoChanged(Call call) {
-                                    call.removeListener(this);  // No longer need to listen to call
-                                                                // changes after the contact info
-                                                                // is retrieved.
-                                    showMissedCallNotification(call);
-                                }
-                            });
-                            // Set the handle here because that is what triggers the contact info
-                            // query.
-                            call.setHandle(handle, presentation);
-                        }
-                    } finally {
-                        cursor.close();
-                    }
-                }
-            }
-        };
-
-        // setup query spec, look for all Missed calls that are new.
-        StringBuilder where = new StringBuilder("type=");
-        where.append(Calls.MISSED_TYPE);
-        where.append(" AND new=1");
-
-        // start the query
-        queryHandler.startQuery(0, null, Calls.CONTENT_URI, CALL_LOG_PROJECTION,
-                where.toString(), null, Calls.DEFAULT_SORT_ORDER);
-    }
+    void updateOnStartup(
+            TelecomSystem.SyncRoot lock,
+            CallsManager callsManager,
+            ContactsAsyncHelper contactsAsyncHelper,
+            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory);
 }
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index c52f2bb..17ccdb1 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom;
 
+import android.app.AppOpsManager;
+
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -51,9 +53,6 @@
  * prior to sending ACTION_NEW_OUTGOING_CALL and cannot be redirected nor prevented.
  */
 class NewOutgoingCallIntentBroadcaster {
-    /** Required permission for any app that wants to consume ACTION_NEW_OUTGOING_CALL. */
-    private static final String PERMISSION = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
-
     private static final String EXTRA_ACTUAL_NUMBER_TO_DIAL =
             "android.telecom.extra.ACTUAL_NUMBER_TO_DIAL";
 
@@ -103,7 +102,8 @@
             // 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.v(this, "- got number from resultData: %s", Log.pii(resultNumber));
+            Log.i(this, "Received new-outgoing-call-broadcast for %s with data %s", mCall,
+                    Log.pii(resultNumber));
 
             boolean endEarly = false;
             if (resultNumber == null) {
@@ -141,7 +141,7 @@
                     mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,
                             false),
                     mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
-                            VideoProfile.VideoState.AUDIO_ONLY));
+                            VideoProfile.STATE_AUDIO_ONLY));
             Trace.endSection();
         }
     }
@@ -156,8 +156,8 @@
      * - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer)
      * - CALL_EMERGENCY (intent launched by lock screen emergency dialer)
      *
-     * @return {@link CallActivity#OUTGOING_CALL_SUCCEEDED} if the call succeeded, and an
-     *         appropriate {@link DisconnectCause} if the call did not, describing why it failed.
+     * @return {@link DisconnectCause#NOT_DISCONNECTED} if the call succeeded, and an appropriate
+     *         {@link DisconnectCause} if the call did not, describing why it failed.
      */
     int processIntent() {
         Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");
@@ -182,7 +182,7 @@
                 boolean speakerphoneOn = mIntent.getBooleanExtra(
                         TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
                 mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,
-                        VideoProfile.VideoState.AUDIO_ONLY);
+                        VideoProfile.STATE_AUDIO_ONLY);
 
                 return DisconnectCause.NOT_DISCONNECTED;
             } else {
@@ -243,7 +243,7 @@
                     TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
             int videoState = mIntent.getIntExtra(
                     TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
-                    VideoProfile.VideoState.AUDIO_ONLY);
+                    VideoProfile.STATE_AUDIO_ONLY);
             mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
                     speakerphoneOn, videoState);
 
@@ -253,6 +253,7 @@
             // initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
         }
 
+        Log.i(this, "Sending NewOutgoingCallBroadcast for %s", mCall);
         broadcastIntent(intent, number, !callImmediately);
         return DisconnectCause.NOT_DISCONNECTED;
     }
@@ -285,7 +286,8 @@
         mContext.sendOrderedBroadcastAsUser(
                 broadcastIntent,
                 UserHandle.CURRENT,
-                PERMISSION,
+                android.Manifest.permission.PROCESS_OUTGOING_CALLS,
+                AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
                 receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
                 null,  // scheduler
                 Activity.RESULT_OK,  // initialCode
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index eb3248e..65847b8 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.app.ActivityManager;
 import android.Manifest;
 import android.content.ComponentName;
 import android.content.Context;
@@ -26,16 +27,22 @@
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.os.Binder;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.telecom.ConnectionService;
+import android.telecom.DefaultDialerManager;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AtomicFile;
 import android.util.Base64;
@@ -53,6 +60,7 @@
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -63,6 +71,7 @@
 import java.lang.SecurityException;
 import java.lang.String;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -70,10 +79,34 @@
 
 /**
  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
- * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as implemented in
- * {@link TelecomServiceImpl}, with the notable exception that {@link TelecomServiceImpl} is
- * responsible for security checking to make sure that the caller has proper authority over
- * the {@code ComponentName}s they are declaring in their {@code PhoneAccountHandle}s.
+ * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as
+ * implemented in {@link TelecomServiceImpl}, with the notable exception that
+ * {@link TelecomServiceImpl} is responsible for security checking to make sure that the caller has
+ * proper authority over the {@code ComponentName}s they are declaring in their
+ * {@code PhoneAccountHandle}s.
+ *
+ *
+ *  -- About Users and Phone Accounts --
+ *
+ * We store all phone accounts for all users in a single place, which means that there are three
+ * users that we have to deal with in code:
+ * 1) The Android User that is currently active on the device.
+ * 2) The user which owns/registers the phone account.
+ * 3) The user running the app that is requesting the phone account information.
+ *
+ * For example, I have a device with 2 users, primary (A) and secondary (B), and the secondary user
+ * has a work profile running as another user (B2). Lets say that user B opens the phone settings
+ * (not currently supported, but theoretically speaking), and phone settings queries for a phone
+ * account list. Lets also say that an app running in the work profile has registered a phone
+ * account. This means that:
+ *
+ * Since phone settings always runs as the primary user, We have the following situation:
+ * User A (settings) is requesting a list of phone accounts while the active user is User B, and
+ * that list contains a phone account for profile User B2.
+ *
+ * In practice, (2) is stored with the phone account handle and is part of the handle's ID. (1) is
+ * saved in {@link #mCurrentUserHandle} and (3) we get from Binder.getCallingUser(). We check these
+ * users for visibility before returning any phone accounts.
  */
 public final class PhoneAccountRegistrar {
 
@@ -88,7 +121,7 @@
 
     private static final String FILE_NAME = "phone-account-registrar-state.xml";
     @VisibleForTesting
-    public static final int EXPECTED_STATE_VERSION = 5;
+    public static final int EXPECTED_STATE_VERSION = 8;
 
     /** Keep in sync with the same in SipSettings.java */
     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
@@ -135,16 +168,14 @@
      * @return The value of the subscription id or -1 if it does not exist or is not valid.
      */
     public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) {
-        PhoneAccount account = getPhoneAccountInternal(accountHandle);
-        if (account == null
-                || !account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
-                || !TextUtils.isDigitsOnly(accountHandle.getId())
-                || !isVisibleForUser(accountHandle)) {
-            // Since no decimals or negative numbers can be valid subscription ids, only a string of
-            // numbers can be subscription id
-            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        PhoneAccount account = getPhoneAccountCheckCallingUser(accountHandle);
+
+        if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            TelephonyManager tm =
+                    (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+            return tm.getSubIdForPhoneAccount(account);
         }
-        return Integer.parseInt(accountHandle.getId());
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
 
     /**
@@ -155,31 +186,26 @@
      * @param uriScheme The URI scheme for the outgoing call.
      * @return The {@link PhoneAccountHandle} to use.
      */
-    public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
+    public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme) {
         final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount();
 
         if (userSelected != null) {
             // If there is a default PhoneAccount, ensure it supports calls to handles with the
             // specified uriScheme.
-            final PhoneAccount userSelectedAccount = getPhoneAccountInternal(userSelected);
-            if (userSelectedAccount.supportsUriScheme(uriScheme)
-                    && isVisibleForUser(userSelected)) {
+            final PhoneAccount userSelectedAccount = getPhoneAccountCheckCallingUser(userSelected);
+            if (userSelectedAccount.supportsUriScheme(uriScheme)) {
                 return userSelected;
             }
         }
 
-        List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme);
+        List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false);
         switch (outgoing.size()) {
             case 0:
                 // There are no accounts, so there can be no default
                 return null;
             case 1:
                 // There is only one account, which is by definition the default.
-                PhoneAccountHandle onlyHandle = outgoing.get(0);
-                if (isVisibleForUser(onlyHandle)) {
-                    return outgoing.get(0);
-                }
-                return null;
+                return outgoing.get(0);
             default:
                 // There are multiple accounts with no selected default
                 return null;
@@ -191,49 +217,37 @@
      *      if it was set by another user).
      */
     PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
-        if (mState.defaultOutgoing != null) {
-            // Return the registered outgoing default iff it still exists (we keep a sticky
-            // default to survive account deletion and re-addition)
-            for (int i = 0; i < mState.accounts.size(); i++) {
-                if (mState.accounts.get(i).getAccountHandle().equals(mState.defaultOutgoing)
-                        && isVisibleForUser(mState.defaultOutgoing)) {
-                    return mState.defaultOutgoing;
-                }
-            }
-            // At this point, there was a registered default but it has been deleted; proceed
-            // as though there were no default
+        PhoneAccount account = getPhoneAccountCheckCallingUser(mState.defaultOutgoing);
+        if (account != null) {
+            return mState.defaultOutgoing;
         }
         return null;
     }
 
+    /**
+     * Sets the phone account with which to place all calls by default. Set by the user
+     * within phone settings.
+     */
     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
         if (accountHandle == null) {
             // Asking to clear the default outgoing is a valid request
             mState.defaultOutgoing = null;
         } else {
-            boolean found = false;
-            for (PhoneAccount m : mState.accounts) {
-                if (Objects.equals(accountHandle, m.getAccountHandle())) {
-                    found = true;
-                    break;
-                }
-            }
-
-            if (!found) {
+            // TODO: Do we really want to return for *any* user?
+            PhoneAccount account = getPhoneAccount(accountHandle);
+            if (account == null) {
                 Log.w(this, "Trying to set nonexistent default outgoing %s",
                         accountHandle);
                 return;
             }
 
-            if (!getPhoneAccountInternal(accountHandle).hasCapabilities(
-                    PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
+            if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
                         accountHandle);
                 return;
             }
 
-            if (getPhoneAccountInternal(accountHandle).hasCapabilities(
-                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
                 // If the account selected is a SIM account, propagate down to the subscription
                 // record.
                 int subId = getSubscriptionIdForPhoneAccount(accountHandle);
@@ -252,91 +266,92 @@
                 SubscriptionManager.getDefaultSmsSubId();
     }
 
-    public void setSimCallManager(PhoneAccountHandle callManager) {
-        if (callManager != null) {
-            PhoneAccount callManagerAccount = getPhoneAccountInternal(callManager);
-            if (callManagerAccount == null) {
-                Log.d(this, "setSimCallManager: Nonexistent call manager: %s", callManager);
-                return;
-            } else if (!callManagerAccount.hasCapabilities(
-                    PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
-                Log.d(this, "setSimCallManager: Not a call manager: %s", callManagerAccount);
-                return;
-            }
-        } else {
-            callManager = NO_ACCOUNT_SELECTED;
-        }
-        mState.simCallManager = callManager;
-
-        write();
-        fireSimCallManagerChanged();
-    }
-
     /**
-     * @return The {@link PhoneAccount}s which are visible to {@link #mCurrentUserHandle}.
+     * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
+     * Manager. SIM Call Manager returned corresponds to the following priority order:
+     * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
+     * default dialer, then that one is returned.
+     * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
+     * carrier configuration's default, then that one is returned.
+     * 3. Otherwise, we return null.
      */
     public PhoneAccountHandle getSimCallManager() {
-        if (mState.simCallManager != null) {
-            if (NO_ACCOUNT_SELECTED.equals(mState.simCallManager)) {
-                return null;
-            }
-            // Return the registered sim call manager iff it still exists (we keep a sticky
-            // setting to survive account deletion and re-addition)
-            for (int i = 0; i < mState.accounts.size(); i++) {
-                if (mState.accounts.get(i).getAccountHandle().equals(mState.simCallManager)
-                        && !resolveComponent(mState.simCallManager).isEmpty()
-                        && isVisibleForUser(mState.simCallManager)) {
-                    return mState.simCallManager;
-                }
-            }
+        long token = Binder.clearCallingIdentity();
+        int user;
+        try {
+            user = ActivityManager.getCurrentUser();
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-
-        // See if the OEM has specified a default one.
-        String defaultConnectionMgr =
-                mContext.getResources().getString(R.string.default_connection_manager_component);
-        if (!TextUtils.isEmpty(defaultConnectionMgr)) {
-            ComponentName componentName = ComponentName.unflattenFromString(defaultConnectionMgr);
-            // Make sure that the component can be resolved.
-            List<ResolveInfo> resolveInfos = resolveComponent(componentName, null);
-            if (!resolveInfos.isEmpty()) {
-                // See if there is registered PhoneAccount by this component.
-                List<PhoneAccountHandle> handles = getAllPhoneAccountHandles();
-                for (PhoneAccountHandle handle : handles) {
-                    if (componentName.equals(handle.getComponentName())
-                            && isVisibleForUser(handle)) {
-                        return handle;
-                    }
-                }
-                Log.d(this, "%s does not have a PhoneAccount; not using as default", componentName);
-            } else {
-                Log.d(this, "%s could not be resolved; not using as default", componentName);
-            }
-        } else {
-            Log.v(this, "No default connection manager specified");
-        }
-
-        return null;
+        return getSimCallManager(user);
     }
 
     /**
-     * A version of {@link #getPhoneAccount} which does not guard for the current user.
-     *
-     * @param handle
-     * @return
+     * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
+     * Manager. SIM Call Manager returned corresponds to the following priority order:
+     * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
+     * default dialer, then that one is returned.
+     * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
+     * carrier configuration's default, then that one is returned.
+     * 3. Otherwise, we return null.
      */
-    PhoneAccount getPhoneAccountInternal(PhoneAccountHandle handle) {
-        for (PhoneAccount m : mState.accounts) {
-            if (Objects.equals(handle, m.getAccountHandle())) {
-                return m;
+    public PhoneAccountHandle getSimCallManager(int user) {
+        // Get the default dialer in case it has a connection manager associated with it.
+        String dialerPackage = DefaultDialerManager.getDefaultDialerApplication(mContext, user);
+
+        // Check carrier config.
+        String defaultSimCallManager = null;
+        CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle configBundle = configManager.getConfig();
+        if (configBundle != null) {
+            defaultSimCallManager = configBundle.getString(
+                    CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
+        }
+
+        ComponentName systemSimCallManagerComponent = TextUtils.isEmpty(defaultSimCallManager) ?
+                null : ComponentName.unflattenFromString(defaultSimCallManager);
+
+        PhoneAccountHandle dialerSimCallManager = null;
+        PhoneAccountHandle systemSimCallManager = null;
+
+        if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) {
+            // loop through and look for any connection manager in the same package.
+            List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles(
+                    PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null,
+                    true /* includeDisabledAccounts */);
+            for (PhoneAccountHandle accountHandle : allSimCallManagers) {
+                ComponentName component = accountHandle.getComponentName();
+
+                // Store the system connection manager if found
+                if (systemSimCallManager == null
+                        && Objects.equals(component, systemSimCallManagerComponent)
+                        && !resolveComponent(accountHandle).isEmpty()) {
+                    systemSimCallManager = accountHandle;
+
+                // Store the dialer connection manager if found
+                } else if (dialerSimCallManager == null
+                        && Objects.equals(component.getPackageName(), dialerPackage)
+                        && !resolveComponent(accountHandle).isEmpty()) {
+                    dialerSimCallManager = accountHandle;
+                }
             }
         }
-        return null;
+
+        PhoneAccountHandle retval = dialerSimCallManager != null ?
+                dialerSimCallManager : systemSimCallManager;
+
+        Log.i(this, "SimCallManager queried, returning: %s", retval);
+
+        return retval;
     }
 
     /**
      * Update the current UserHandle to track when users are switched. This will allow the
      * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything
      * across users.
+     * We cannot simply check the calling user because that would always return the primary user for
+     * all invocations originating with the system process.
      *
      * @param userHandle The {@link UserHandle}, as delivered by
      *          {@link Intent#ACTION_USER_SWITCHED}.
@@ -350,12 +365,27 @@
         mCurrentUserHandle = userHandle;
     }
 
-    private boolean isVisibleForUser(PhoneAccountHandle accountHandle) {
-        if (accountHandle == null) {
+    /**
+     * @return {@code true} if the phone account was successfully enabled/disabled, {@code false}
+     *         otherwise.
+     */
+    public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
+        PhoneAccount account = getPhoneAccount(accountHandle);
+        if (account == null) {
+            Log.w(this, "Could not find account to enable: " + accountHandle);
+            return false;
+        } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            // We never change the enabled state of SIM-based accounts.
+            Log.w(this, "Could not change enable state of SIM account: " + accountHandle);
             return false;
         }
 
-        return isVisibleForUser(getPhoneAccountInternal(accountHandle));
+        if (account.isEnabled() != isEnabled) {
+            account.setIsEnabled(isEnabled);
+            write();
+            fireAccountsChanged();
+        }
+        return true;
     }
 
     private boolean isVisibleForUser(PhoneAccount account) {
@@ -379,16 +409,24 @@
             return true;
         }
 
+        if (phoneAccountUserHandle.equals(Binder.getCallingUserHandle())) {
+            return true;
+        }
+
+        // Special check for work profiles.
         // Unlike in TelecomServiceImpl, we only care about *profiles* here. We want to make sure
         // that we don't resolve PhoneAccount across *users*, but resolving across *profiles* is
         // fine.
-        List<UserInfo> profileUsers = mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
-
-        for (UserInfo profileInfo : profileUsers) {
-            if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
-                return true;
+        if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
+            List<UserInfo> profileUsers =
+                    mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
+            for (UserInfo profileInfo : profileUsers) {
+                if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
+                    return true;
+                }
             }
         }
+
         return false;
     }
 
@@ -402,45 +440,30 @@
         PackageManager pm = mContext.getPackageManager();
         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
         intent.setComponent(componentName);
-        if (userHandle != null) {
-            return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
-        } else {
-            return pm.queryIntentServices(intent, 0);
+        try {
+            if (userHandle != null) {
+                return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
+            } else {
+                return pm.queryIntentServices(intent, 0);
+            }
+        } catch (SecurityException e) {
+            Log.e(this, e, "%s is not visible for the calling user", componentName);
+            return Collections.EMPTY_LIST;
         }
     }
 
     /**
      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
+     * Only returns accounts which are enabled.
      *
      * @return The list of {@link PhoneAccountHandle}s.
      */
     public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
-        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
-        for (PhoneAccount m : mState.accounts) {
-            if (isVisibleForUser(m)) {
-                accountHandles.add(m.getAccountHandle());
-            }
-        }
-        return accountHandles;
+        return getPhoneAccountHandles(0, null, null, false);
     }
 
     public List<PhoneAccount> getAllPhoneAccounts() {
-        List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
-        for (PhoneAccount account : mState.accounts) {
-            if (isVisibleForUser(account)) {
-                accounts.add(account);
-            }
-        }
-        return accounts;
-    }
-
-    /**
-     * Retrieves a list of all call provider phone accounts.
-     *
-     * @return The phone account handles.
-     */
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER);
+        return getPhoneAccounts(0, null, null, false);
     }
 
     /**
@@ -450,8 +473,19 @@
      * @param uriScheme The URI scheme.
      * @return The phone account handles.
      */
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(String uriScheme) {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme);
+    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            String uriScheme, boolean includeDisabledAccounts) {
+        return getPhoneAccountHandles(
+                PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme, null, includeDisabledAccounts);
+    }
+
+    /**
+     * Retrieves a list of all the SIM-based phone accounts.
+     */
+    public List<PhoneAccountHandle> getSimPhoneAccounts() {
+        return getPhoneAccountHandles(
+                PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
+                null, null, false);
     }
 
     /**
@@ -461,36 +495,7 @@
      * @return The phone account handles.
      */
     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
-        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
-        for (PhoneAccount m : mState.accounts) {
-            if (Objects.equals(
-                    packageName,
-                    m.getAccountHandle().getComponentName().getPackageName())
-                    && isVisibleForUser(m)) {
-                accountHandles.add(m.getAccountHandle());
-            }
-        }
-        return accountHandles;
-    }
-
-    /**
-     * Retrieves a list of all phone account handles with the connection manager capability.
-     *
-     * @return The phone account handles.
-     */
-    public List<PhoneAccountHandle> getConnectionManagerPhoneAccounts() {
-        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
-                null /* supportedUriScheme */);
-    }
-
-    public PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
-        for (PhoneAccount m : mState.accounts) {
-            if (Objects.equals(handle, m.getAccountHandle())
-                    && isVisibleForUser(m)) {
-                return m;
-            }
-        }
-        return null;
+        return getPhoneAccountHandles(0, null, packageName, false);
     }
 
     // TODO: Should we implement an artificial limit for # of accounts associated with a single
@@ -498,11 +503,12 @@
     public void registerPhoneAccount(PhoneAccount account) {
         // Enforce the requirement that a connection service for a phone account has the correct
         // permission.
-        if (!phoneAccountHasPermission(account.getAccountHandle())) {
-            Log.w(this, "Phone account %s does not have BIND_CONNECTION_SERVICE permission.",
+        if (!phoneAccountRequiresBindPermission(account.getAccountHandle())) {
+            Log.w(this,
+                    "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.",
                     account.getAccountHandle());
-            throw new SecurityException(
-                    "PhoneAccount connection service requires BIND_CONNECTION_SERVICE permission.");
+            throw new SecurityException("PhoneAccount connection service requires "
+                    + "BIND_TELECOM_CONNECTION_SERVICE permission.");
         }
 
         addOrReplacePhoneAccount(account);
@@ -517,32 +523,38 @@
         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
                 account.getAccountHandle(), account);
 
-        mState.accounts.add(account);
-        // Search for duplicates and remove any that are found.
-        for (int i = 0; i < mState.accounts.size() - 1; i++) {
-            if (Objects.equals(
-                    account.getAccountHandle(), mState.accounts.get(i).getAccountHandle())) {
-                // replace existing entry.
-                mState.accounts.remove(i);
-                break;
-            }
+        // Start _enabled_ property as false.
+        // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
+        // source app provides or else an third party app could enable itself.
+        boolean isEnabled = false;
+
+        PhoneAccount oldAccount = getPhoneAccount(account.getAccountHandle());
+        if (oldAccount != null) {
+            mState.accounts.remove(oldAccount);
+            isEnabled = oldAccount.isEnabled();
+            Log.i(this, getAccountDiffString(account, oldAccount));
+        } else {
+            Log.i(this, "New phone account registered: " + account);
         }
 
+        mState.accounts.add(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(
+                isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION));
+
         write();
         fireAccountsChanged();
     }
 
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
-        for (int i = 0; i < mState.accounts.size(); i++) {
-            PhoneAccountHandle handle = mState.accounts.get(i).getAccountHandle();
-            if (Objects.equals(accountHandle, handle)) {
-                mState.accounts.remove(i);
-                break;
+        PhoneAccount account = getPhoneAccount(accountHandle);
+        if (account != null) {
+            if (mState.accounts.remove(account)) {
+                write();
+                fireAccountsChanged();
             }
         }
-
-        write();
-        fireAccountsChanged();
     }
 
     /**
@@ -560,7 +572,7 @@
             if (Objects.equals(packageName, handle.getComponentName().getPackageName())
                     && Objects.equals(userHandle, handle.getUserHandle())) {
                 Log.i(this, "Removing phone account " + phoneAccount.getLabel());
-                it.remove();
+                mState.accounts.remove(phoneAccount);
                 accountsRemoved = true;
             }
         }
@@ -573,7 +585,7 @@
 
     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
-        return PhoneNumberUtils.isVoiceMailNumber(subId, number);
+        return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
     }
 
     public void addListener(Listener l) {
@@ -604,50 +616,143 @@
         }
     }
 
+    private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) {
+        if (account1 == null || account2 == null) {
+            return "Diff: " + account1 + ", " + account2;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("[").append(account1.getAccountHandle());
+        appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
+                Log.piiHandle(account2.getAddress()));
+        appendDiff(sb, "cap", account1.getCapabilities(), account2.getCapabilities());
+        appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
+        appendDiff(sb, "icon", account1.getIcon(), account2.getIcon());
+        appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
+        appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
+        appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
+                Log.piiHandle(account2.getSubscriptionAddress()));
+        appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
+                account2.getSupportedUriSchemes());
+        sb.append("]");
+        return sb.toString();
+    }
+
+    private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) {
+        if (!Objects.equals(obj1, obj2)) {
+            sb.append("(")
+                .append(attrName)
+                .append(": ")
+                .append(obj1)
+                .append(" -> ")
+                .append(obj2)
+                .append(")");
+        }
+    }
+
     /**
-     * Determines if the connection service specified by a {@link PhoneAccountHandle} has the
-     * {@link Manifest.permission#BIND_CONNECTION_SERVICE} permission.
+     * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
+     * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
      *
      * @param phoneAccountHandle The phone account to check.
      * @return {@code True} if the phone account has permission.
      */
-    public boolean phoneAccountHasPermission(PhoneAccountHandle phoneAccountHandle) {
-        PackageManager packageManager = mContext.getPackageManager();
-        try {
-            ServiceInfo serviceInfo = packageManager.getServiceInfo(
-                    phoneAccountHandle.getComponentName(), 0);
-
-            return serviceInfo.permission != null &&
-                    serviceInfo.permission.equals(Manifest.permission.BIND_CONNECTION_SERVICE);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(this, "Name not found %s", e);
+    public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) {
+        List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
+        if (resolveInfos.isEmpty()) {
+            Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
             return false;
         }
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo == null) {
+                return false;
+            }
+
+            if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) &&
+                    !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals(
+                            serviceInfo.permission)) {
+                // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE,
+                // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are
+                // system/signature only.
+                return false;
+            }
+        }
+        return true;
     }
 
-    ////////////////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Methods for retrieving PhoneAccounts and PhoneAccountHandles
+    //
 
     /**
-     * Returns a list of phone account handles with the specified flag.
+     * Returns the PhoneAccount for the specified handle.  Does no user checking.
      *
-     * @param flags Flags which the {@code PhoneAccount} must have.
+     * @param handle
+     * @return The corresponding phone account if one exists.
      */
-    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags) {
-        return getPhoneAccountHandles(flags, null);
+    PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
+        for (PhoneAccount m : mState.accounts) {
+            if (Objects.equals(handle, m.getAccountHandle())) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone
+     * account before returning it. The current user is the active user on the actual android
+     * device.
+     */
+    public PhoneAccount getPhoneAccountCheckCallingUser(PhoneAccountHandle handle) {
+        PhoneAccount account = getPhoneAccount(handle);
+        if (account != null && isVisibleForUser(account)) {
+            return account;
+        }
+        return null;
+    }
+
+    /**
+     * Returns a list of phone account handles with the specified capabilities, uri scheme,
+     * and package name.
+     */
+    private List<PhoneAccountHandle> getPhoneAccountHandles(
+            int capabilities,
+            String uriScheme,
+            String packageName,
+            boolean includeDisabledAccounts) {
+        List<PhoneAccountHandle> handles = new ArrayList<>();
+
+        for (PhoneAccount account : getPhoneAccounts(
+                capabilities, uriScheme, packageName, includeDisabledAccounts)) {
+            handles.add(account.getAccountHandle());
+        }
+        return handles;
     }
 
     /**
      * Returns a list of phone account handles with the specified flag, supporting the specified
-     * URI scheme.
+     * URI scheme, within the specified package name.
      *
-     * @param flags Flags which the {@code PhoneAccount} must have.
-     * @param uriScheme URI schemes the PhoneAccount must handle.  {@code Null} bypasses the
+     * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0.
+     * @param uriScheme URI schemes the PhoneAccount must handle.  {@code null} bypasses the
      *                  URI scheme check.
+     * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
      */
-    private List<PhoneAccountHandle> getPhoneAccountHandles(int flags, String uriScheme) {
-        List<PhoneAccountHandle> accountHandles = new ArrayList<>();
+    private List<PhoneAccount> getPhoneAccounts(
+            int capabilities,
+            String uriScheme,
+            String packageName,
+            boolean includeDisabledAccounts) {
+        List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
         for (PhoneAccount m : mState.accounts) {
-            if (!m.hasCapabilities(flags)) {
+            if (!(m.isEnabled() || includeDisabledAccounts)) {
+                // Do not include disabled accounts.
+                continue;
+            }
+
+            if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
                 // Account doesn't have the right capabilities; skip this one.
                 continue;
             }
@@ -655,19 +760,30 @@
                 // Account doesn't support this URI scheme; skip this one.
                 continue;
             }
-            if (resolveComponent(m.getAccountHandle()).isEmpty()) {
+            PhoneAccountHandle handle = m.getAccountHandle();
+
+            if (resolveComponent(handle).isEmpty()) {
                 // This component cannot be resolved anymore; skip this one.
                 continue;
             }
+            if (packageName != null &&
+                    !packageName.equals(handle.getComponentName().getPackageName())) {
+                // Not the right package name; skip this one.
+                continue;
+            }
             if (!isVisibleForUser(m)) {
                 // Account is not visible for the current user; skip this one.
                 continue;
             }
-            accountHandles.add(m.getAccountHandle());
+            accounts.add(m);
         }
-        return accountHandles;
+        return accounts;
     }
 
+    //
+    // State Implementation for PhoneAccountRegistrar
+    //
+
     /**
      * The state of this {@code PhoneAccountRegistrar}.
      */
@@ -680,15 +796,9 @@
         public PhoneAccountHandle defaultOutgoing = null;
 
         /**
-         * A {@code PhoneAccount} having {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} which
-         * manages and optimizes a user's PSTN SIM connections.
-         */
-        public PhoneAccountHandle simCallManager;
-
-        /**
          * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
          */
-        public final List<PhoneAccount> accounts = new ArrayList<>();
+        public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>();
 
         /**
          * The version number of the State data.
@@ -706,8 +816,7 @@
             pw.println("xmlVersion: " + mState.versionNumber);
             pw.println("defaultOutgoing: " + (mState.defaultOutgoing == null ? "none" :
                     mState.defaultOutgoing));
-            pw.println("simCallManager: " + (mState.simCallManager == null ? "none" :
-                    mState.simCallManager));
+            pw.println("simCallManager: " + getSimCallManager());
             pw.println("phoneAccounts:");
             pw.increaseIndent();
             for (PhoneAccount phoneAccount : mState.accounts) {
@@ -868,13 +977,13 @@
             serializer.endTag(null, tagName);
         }
 
-        protected void writeBitmapIfNonNull(String tagName, Bitmap value, XmlSerializer serializer)
+        protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer)
                 throws IOException {
-            if (value != null && value.getByteCount() > 0) {
+            if (value != null) {
                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
-                value.compress(Bitmap.CompressFormat.PNG, 100, stream);
-                byte[] imageByteArray = stream.toByteArray();
-                String text = Base64.encodeToString(imageByteArray, 0, imageByteArray.length, 0);
+                value.writeToStream(stream);
+                byte[] iconByteArray = stream.toByteArray();
+                String text = Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0);
 
                 serializer.startTag(null, tagName);
                 serializer.text(text);
@@ -920,11 +1029,16 @@
             return arrayEntries;
         }
 
-        protected Bitmap readBitmap(XmlPullParser parser)
-                throws IOException, XmlPullParserException {
+        protected Bitmap readBitmap(XmlPullParser parser) {
             byte[] imageByteArray = Base64.decode(parser.getText(), 0);
             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
         }
+
+        protected Icon readIcon(XmlPullParser parser) throws IOException {
+            byte[] iconByteArray = Base64.decode(parser.getText(), 0);
+            ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
+            return Icon.createFromStream(stream);
+        }
     }
 
     @VisibleForTesting
@@ -932,7 +1046,6 @@
             new XmlSerialization<State>() {
         private static final String CLASS_STATE = "phone_account_registrar_state";
         private static final String DEFAULT_OUTGOING = "default_outgoing";
-        private static final String SIM_CALL_MANAGER = "sim_call_manager";
         private static final String ACCOUNTS = "accounts";
         private static final String VERSION = "version";
 
@@ -949,12 +1062,6 @@
                     serializer.endTag(null, DEFAULT_OUTGOING);
                 }
 
-                if (o.simCallManager != null) {
-                    serializer.startTag(null, SIM_CALL_MANAGER);
-                    sPhoneAccountHandleXml.writeToXml(o.simCallManager, serializer, context);
-                    serializer.endTag(null, SIM_CALL_MANAGER);
-                }
-
                 serializer.startTag(null, ACCOUNTS);
                 for (PhoneAccount m : o.accounts) {
                     sPhoneAccountXml.writeToXml(m, serializer, context);
@@ -981,17 +1088,6 @@
                         parser.nextTag();
                         s.defaultOutgoing = sPhoneAccountHandleXml.readFromXml(parser,
                                 s.versionNumber, context);
-                    } else if (parser.getName().equals(SIM_CALL_MANAGER)) {
-                        parser.nextTag();
-                        s.simCallManager = sPhoneAccountHandleXml.readFromXml(parser,
-                                s.versionNumber, context);
-                        if (s.simCallManager.getUserHandle() == null) {
-                            // This should never happen, but handle the upgrade case.
-                            s.simCallManager = new PhoneAccountHandle(
-                                    s.simCallManager.getComponentName(),
-                                    s.simCallManager.getId(),
-                                    Process.myUserHandle());
-                        }
                     } else if (parser.getName().equals(ACCOUNTS)) {
                         int accountsDepth = parser.getDepth();
                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
@@ -1026,6 +1122,8 @@
         private static final String LABEL = "label";
         private static final String SHORT_DESCRIPTION = "short_description";
         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
+        private static final String ICON = "icon";
+        private static final String ENABLED = "enabled";
 
         @Override
         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
@@ -1042,15 +1140,13 @@
                 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer);
                 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
                 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
-                writeTextIfNonNull(ICON_RES_ID, Integer.toString(o.getIconResId()), serializer);
-                writeTextIfNonNull(ICON_PACKAGE_NAME, o.getIconPackageName(), serializer);
-                writeBitmapIfNonNull(ICON_BITMAP, o.getIconBitmap(), serializer);
-                writeTextIfNonNull(ICON_TINT, Integer.toString(o.getIconTint()), serializer);
+                writeIconIfNonNull(ICON, o.getIcon(), serializer);
                 writeTextIfNonNull(HIGHLIGHT_COLOR,
                         Integer.toString(o.getHighlightColor()), serializer);
                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
+                writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
 
                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
             }
@@ -1072,6 +1168,8 @@
                 String label = null;
                 String shortDescription = null;
                 List<String> supportedUriSchemes = null;
+                Icon icon = null;
+                boolean enabled = false;
 
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
@@ -1111,14 +1209,22 @@
                         shortDescription = parser.getText();
                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
                         supportedUriSchemes = readStringList(parser);
+                    } else if (parser.getName().equals(ICON)) {
+                        parser.next();
+                        icon = readIcon(parser);
+                    } else if (parser.getName().equals(ENABLED)) {
+                        parser.next();
+                        enabled = "true".equalsIgnoreCase(parser.getText());
                     }
                 }
 
+                ComponentName pstnComponentName = new ComponentName("com.android.phone",
+                        "com.android.services.telephony.TelephonyConnectionService");
+                ComponentName sipComponentName = new ComponentName("com.android.phone",
+                        "com.android.services.telephony.sip.SipConnectionService");
+
                 // Upgrade older phone accounts to specify the supported URI schemes.
                 if (version < 2) {
-                    ComponentName sipComponentName = new ComponentName("com.android.phone",
-                            "com.android.services.telephony.sip.SipConnectionService");
-
                     supportedUriSchemes = new ArrayList<>();
 
                     // Handle the SIP connection service.
@@ -1142,18 +1248,47 @@
                     }
                 }
 
+                if (version < 6) {
+                    // Always enable all SIP accounts on upgrade to version 6
+                    if (accountHandle.getComponentName().equals(sipComponentName)) {
+                        enabled = true;
+                    }
+                }
+                if (version < 7) {
+                    // Always enabled all PSTN acocunts on upgrade to version 7
+                    if (accountHandle.getComponentName().equals(pstnComponentName)) {
+                        enabled = true;
+                    }
+                }
+                if (version < 8) {
+                    // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
+                    if (accountHandle.getComponentName().equals(sipComponentName)) {
+                        Uri accountUri = Uri.parse(accountHandle.getId());
+                        if (accountUri.getScheme() != null &&
+                            accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
+                            accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
+                                    accountUri.getSchemeSpecificPart(),
+                                    accountHandle.getUserHandle());
+                        }
+                    }
+                }
+
                 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
                         .setAddress(address)
                         .setSubscriptionAddress(subscriptionAddress)
                         .setCapabilities(capabilities)
                         .setShortDescription(shortDescription)
                         .setSupportedUriSchemes(supportedUriSchemes)
-                        .setHighlightColor(highlightColor);
+                        .setHighlightColor(highlightColor)
+                        .setIsEnabled(enabled);
 
-                if (iconBitmap == null) {
-                    builder.setIcon(iconPackageName, iconResId, iconTint);
-                } else {
-                    builder.setIcon(iconBitmap);
+                if (icon != null) {
+                    builder.setIcon(icon);
+                } else if (iconBitmap != null) {
+                    builder.setIcon(Icon.createWithBitmap(iconBitmap));
+                } else if (!TextUtils.isEmpty(iconPackageName)) {
+                    builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
+                    // TODO: Need to set tint.
                 }
 
                 return builder.build();
@@ -1162,7 +1297,8 @@
         }
 
         /**
-         * Determines if the SIP call settings specify to use SIP for all calls, including PSTN calls.
+         * Determines if the SIP call settings specify to use SIP for all calls, including PSTN
+         * calls.
          *
          * @param context The context.
          * @return {@code True} if SIP should be used for all calls.
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index b96eb02..57ae24b 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -18,7 +18,6 @@
 
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telecom.CallState;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -29,10 +28,12 @@
  */
 final class PhoneStateBroadcaster extends CallsManagerListenerBase {
 
+    private final CallsManager mCallsManager;
     private final ITelephonyRegistry mRegistry;
     private int mCurrentState = TelephonyManager.CALL_STATE_IDLE;
 
-    public PhoneStateBroadcaster() {
+    public PhoneStateBroadcaster(CallsManager callsManager) {
+        mCallsManager = callsManager;
         mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                 "telephony.registry"));
         if (mRegistry == null) {
@@ -43,7 +44,8 @@
     @Override
     public void onCallStateChanged(Call call, int oldState, int newState) {
         if ((newState == CallState.DIALING || newState == CallState.ACTIVE
-                || newState == CallState.ON_HOLD) && !CallsManager.getInstance().hasRingingCall()) {
+                || newState == CallState.ON_HOLD) &&
+                !mCallsManager.hasRingingCall()) {
             /*
              * EXTRA_STATE_RINGING takes precedence over EXTRA_STATE_OFFHOOK, so if there is
              * already a ringing call, don't broadcast EXTRA_STATE_OFFHOOK.
@@ -63,11 +65,10 @@
     public void onCallRemoved(Call call) {
         // Recalculate the current phone state based on the consolidated state of the remaining
         // calls in the call list.
-        final CallsManager callsManager = CallsManager.getInstance();
         int callState = TelephonyManager.CALL_STATE_IDLE;
-        if (callsManager.hasRingingCall()) {
+        if (mCallsManager.hasRingingCall()) {
             callState = TelephonyManager.CALL_STATE_RINGING;
-        } else if (callsManager.getFirstCallWithState(CallState.DIALING, CallState.ACTIVE,
+        } else if (mCallsManager.getFirstCallWithState(CallState.DIALING, CallState.ACTIVE,
                     CallState.ON_HOLD) != null) {
             callState = TelephonyManager.CALL_STATE_OFFHOOK;
         }
diff --git a/src/com/android/server/telecom/ProximitySensorManager.java b/src/com/android/server/telecom/ProximitySensorManager.java
index 5b82c43..5fddb89 100644
--- a/src/com/android/server/telecom/ProximitySensorManager.java
+++ b/src/com/android/server/telecom/ProximitySensorManager.java
@@ -26,8 +26,9 @@
     private static final String TAG = ProximitySensorManager.class.getSimpleName();
 
     private final PowerManager.WakeLock mProximityWakeLock;
+    private final CallsManager mCallsManager;
 
-    public ProximitySensorManager(Context context) {
+    public ProximitySensorManager(Context context, CallsManager callsManager) {
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 
         if (pm.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
@@ -36,12 +37,14 @@
         } else {
             mProximityWakeLock = null;
         }
+
+        mCallsManager = callsManager;
         Log.d(this, "onCreate: mProximityWakeLock: ", mProximityWakeLock);
     }
 
     @Override
     public void onCallRemoved(Call call) {
-        if (CallsManager.getInstance().getCalls().isEmpty()) {
+        if (mCallsManager.getCalls().isEmpty()) {
             Log.i(this, "All calls removed, resetting proximity sensor to default state");
             turnOff(true);
         }
@@ -52,7 +55,7 @@
      * Turn the proximity sensor on.
      */
     void turnOn() {
-        if (CallsManager.getInstance().getCalls().isEmpty()) {
+        if (mCallsManager.getCalls().isEmpty()) {
             Log.w(this, "Asking to turn on prox sensor without a call? I don't think so.");
             return;
         }
diff --git a/src/com/android/server/telecom/ProximitySensorManagerFactory.java b/src/com/android/server/telecom/ProximitySensorManagerFactory.java
new file mode 100644
index 0000000..b73636f
--- /dev/null
+++ b/src/com/android/server/telecom/ProximitySensorManagerFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.Context;
+
+/**
+ * This is a TEMPORARY fix to make the {@link ProximitySensorManager} object injectable for testing.
+ * Class {@link ProximitySensorManager} itself is not testable because it grabs lots of special
+ * stuff from its {@code Context} that cannot be conveniently mocked.
+ *
+ * TODO: Replace with a better design.
+ */
+public interface ProximitySensorManagerFactory {
+
+    ProximitySensorManager create(Context context, CallsManager callsManager);
+
+}
diff --git a/src/com/android/server/telecom/QuickResponseUtils.java b/src/com/android/server/telecom/QuickResponseUtils.java
index ec77b33..fd0dbd2 100644
--- a/src/com/android/server/telecom/QuickResponseUtils.java
+++ b/src/com/android/server/telecom/QuickResponseUtils.java
@@ -64,19 +64,16 @@
                 SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
         final Resources res = context.getResources();
 
-        final boolean responsesExist = prefs.contains(KEY_CANNED_RESPONSE_PREF_1);
+        final boolean responsesExist = prefs.contains(KEY_CANNED_RESPONSE_PREF_1)
+                || prefs.contains(KEY_CANNED_RESPONSE_PREF_2)
+                || prefs.contains(KEY_CANNED_RESPONSE_PREF_3)
+                || prefs.contains(KEY_CANNED_RESPONSE_PREF_4);
         if (responsesExist) {
-            // If one QuickResponse exists, they all exist.
+            // Skip if the user has set any canned responses.
             Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Telecom QuickResponses exist");
             return;
         }
 
-        // Grab the all the default QuickResponses from our resources.
-        String cannedResponse1 = res.getString(R.string.respond_via_sms_canned_response_1);
-        String cannedResponse2 = res.getString(R.string.respond_via_sms_canned_response_2);
-        String cannedResponse3 = res.getString(R.string.respond_via_sms_canned_response_3);
-        String cannedResponse4 = res.getString(R.string.respond_via_sms_canned_response_4);
-
         Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - No local QuickResponses");
 
         // We don't have local QuickResponses, let's see if they live in
@@ -90,24 +87,31 @@
 
         // Read the old canned responses from the Telephony SharedPreference if possible.
         if (telephonyContext != null) {
-            // Note that if any one QuickResponse does not exist, we'll use the default
-            // value to populate it.
             Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Using Telephony QuickResponses.");
             final SharedPreferences oldPrefs = telephonyContext.getSharedPreferences(
                     SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
-            cannedResponse1 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_1, cannedResponse1);
-            cannedResponse2 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_2, cannedResponse2);
-            cannedResponse3 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_3, cannedResponse3);
-            cannedResponse4 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_4, cannedResponse4);
-        }
+            if (!oldPrefs.contains(KEY_CANNED_RESPONSE_PREF_1)) {
+                // Skip migration if old responses don't exist.
+                // If they exist, the first canned response should be present.
+                return;
+            }
+            String cannedResponse1 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_1,
+                    res.getString(R.string.respond_via_sms_canned_response_1));
+            String cannedResponse2 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_2,
+                    res.getString(R.string.respond_via_sms_canned_response_2));
+            String cannedResponse3 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_3,
+                    res.getString(R.string.respond_via_sms_canned_response_3));
+            String cannedResponse4 = oldPrefs.getString(KEY_CANNED_RESPONSE_PREF_4,
+                    res.getString(R.string.respond_via_sms_canned_response_4));
 
-        // Either way, write them back into Telecom SharedPreferences.
-        final SharedPreferences.Editor editor = prefs.edit();
-        editor.putString(KEY_CANNED_RESPONSE_PREF_1, cannedResponse1);
-        editor.putString(KEY_CANNED_RESPONSE_PREF_2, cannedResponse2);
-        editor.putString(KEY_CANNED_RESPONSE_PREF_3, cannedResponse3);
-        editor.putString(KEY_CANNED_RESPONSE_PREF_4, cannedResponse4);
-        editor.commit();
+            // Write them into Telecom SharedPreferences.
+            final SharedPreferences.Editor editor = prefs.edit();
+            editor.putString(KEY_CANNED_RESPONSE_PREF_1, cannedResponse1);
+            editor.putString(KEY_CANNED_RESPONSE_PREF_2, cannedResponse2);
+            editor.putString(KEY_CANNED_RESPONSE_PREF_3, cannedResponse3);
+            editor.putString(KEY_CANNED_RESPONSE_PREF_4, cannedResponse4);
+            editor.commit();
+        }
 
         Log.d(LOG_TAG, "maybeMigrateLegacyQuickResponses() - Done.");
         return;
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index ebedf9f..e5a2042 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -28,6 +28,7 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.telecom.Response;
 import android.telephony.SubscriptionManager;
@@ -41,32 +42,15 @@
  * Helper class to manage the "Respond via Message" feature for incoming calls.
  */
 public class RespondViaSmsManager extends CallsManagerListenerBase {
-    private static final int MSG_CANNED_TEXT_MESSAGES_READY = 1;
     private static final int MSG_SHOW_SENT_TOAST = 2;
 
-    private static final RespondViaSmsManager sInstance = new RespondViaSmsManager();
+    private final CallsManager mCallsManager;
+    private final TelecomSystem.SyncRoot mLock;
 
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_CANNED_TEXT_MESSAGES_READY: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        Response<Void, List<String>> response =
-                                (Response<Void, List<String>>) args.arg1;
-                        List<String> textMessages =
-                                (List<String>) args.arg2;
-                        if (textMessages != null) {
-                            response.onResult(null, textMessages);
-                        } else {
-                            response.onError(null, 0, null);
-                        }
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
                 case MSG_SHOW_SENT_TOAST: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -82,9 +66,10 @@
         }
     };
 
-    public static RespondViaSmsManager getInstance() { return sInstance; }
-
-    private RespondViaSmsManager() {}
+    public RespondViaSmsManager(CallsManager callsManager, TelecomSystem.SyncRoot lock) {
+        mCallsManager = callsManager;
+        mLock = lock;
+    }
 
     /**
      * Read the (customizable) canned responses from SharedPreferences,
@@ -132,10 +117,9 @@
                         "loadCannedResponses() completed, found responses: %s",
                         textMessages.toString());
 
-                SomeArgs args = SomeArgs.obtain();
-                args.arg1 = response;
-                args.arg2 = textMessages;
-                mHandler.obtainMessage(MSG_CANNED_TEXT_MESSAGES_READY, args).sendToTarget();
+                synchronized (mLock) {
+                    response.onResult(null, textMessages);
+                }
             }
         }.start();
     }
@@ -143,9 +127,7 @@
     @Override
     public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
         if (rejectWithMessage && call.getHandle() != null) {
-            PhoneAccountRegistrar phoneAccountRegistrar =
-                    CallsManager.getInstance().getPhoneAccountRegistrar();
-            int subId = phoneAccountRegistrar.getSubscriptionIdForPhoneAccount(
+            int subId = mCallsManager.getPhoneAccountRegistrar().getSubscriptionIdForPhoneAccount(
                     call.getTargetPhoneAccount());
             rejectCallWithMessage(call.getContext(), call.getHandle().getSchemeSpecificPart(),
                     textMessage, subId);
diff --git a/src/com/android/server/telecom/RespondViaSmsSettings.java b/src/com/android/server/telecom/RespondViaSmsSettings.java
index f5876a0..f8aa568 100644
--- a/src/com/android/server/telecom/RespondViaSmsSettings.java
+++ b/src/com/android/server/telecom/RespondViaSmsSettings.java
@@ -24,108 +24,102 @@
 import android.preference.EditTextPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
 import android.view.Menu;
 import android.view.MenuItem;
 
-// TODO: Needed for move to system service: import com.android.internal.R;
+// TODO: This class is newly copied into Telecom (com.android.server.telecom) from it previous
+// location in Telephony (com.android.phone). User's preferences stored in the old location
+// will be lost. We need code here to migrate KLP -> LMP settings values.
 
 /**
- * Helper class to manage the "Respond via SMS Message" feature for incoming calls.
+ * Settings activity to manage the responses available for the "Respond via SMS Message" feature to
+ * respond to incoming calls.
  */
-public class RespondViaSmsSettings {
-    // TODO: This class is newly copied into Telecom (com.android.server.telecom) from it previous
-    // location in Telephony (com.android.phone). User's preferences stored in the old location
-    // will be lost. We need code here to migrate KLP -> LMP settings values.
+public class RespondViaSmsSettings extends PreferenceActivity
+        implements Preference.OnPreferenceChangeListener {
 
-    /**
-     * Settings activity under "Call settings" to let you manage the
-     * canned responses; see respond_via_sms_settings.xml
-     */
-    public static class Settings extends PreferenceActivity
-            implements Preference.OnPreferenceChangeListener {
-        @Override
-        protected void onCreate(Bundle icicle) {
-            super.onCreate(icicle);
-            Log.d(this, "Settings: onCreate()...");
+    private SharedPreferences mPrefs;
 
-            // This function guarantees that QuickResponses will be in our
-            // SharedPreferences with the proper values considering there may be
-            // old QuickResponses in Telephony pre L.
-            QuickResponseUtils.maybeMigrateLegacyQuickResponses(this);
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.d(this, "Settings: onCreate()...");
 
-            getPreferenceManager().setSharedPreferencesName(
-                    QuickResponseUtils.SHARED_PREFERENCES_NAME);
+        // This function guarantees that QuickResponses will be in our
+        // SharedPreferences with the proper values considering there may be
+        // old QuickResponses in Telephony pre L.
+        QuickResponseUtils.maybeMigrateLegacyQuickResponses(this);
 
-            // This preference screen is ultra-simple; it's just 4 plain
-            // <EditTextPreference>s, one for each of the 4 "canned responses".
-            //
-            // The only nontrivial thing we do here is copy the text value of
-            // each of those EditTextPreferences and use it as the preference's
-            // "title" as well, so that the user will immediately see all 4
-            // strings when they arrive here.
-            //
-            // Also, listen for change events (since we'll need to update the
-            // title any time the user edits one of the strings.)
+        getPreferenceManager().setSharedPreferencesName(QuickResponseUtils.SHARED_PREFERENCES_NAME);
+        mPrefs = getPreferenceManager().getSharedPreferences();
+    }
 
-            addPreferencesFromResource(R.xml.respond_via_sms_settings);
+    @Override
+    public void onResume() {
+        super.onResume();
 
-            EditTextPreference pref;
-            pref = (EditTextPreference) findPreference(
-                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1);
-            pref.setTitle(pref.getText());
-            pref.setOnPreferenceChangeListener(this);
-
-            pref = (EditTextPreference) findPreference(
-                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2);
-            pref.setTitle(pref.getText());
-            pref.setOnPreferenceChangeListener(this);
-
-            pref = (EditTextPreference) findPreference(
-                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3);
-            pref.setTitle(pref.getText());
-            pref.setOnPreferenceChangeListener(this);
-
-            pref = (EditTextPreference) findPreference(
-                    QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4);
-            pref.setTitle(pref.getText());
-            pref.setOnPreferenceChangeListener(this);
-
-            ActionBar actionBar = getActionBar();
-            if (actionBar != null) {
-                // android.R.id.home will be triggered in onOptionsItemSelected()
-                actionBar.setDisplayHomeAsUpEnabled(true);
-            }
+        PreferenceScreen preferenceScreen = getPreferenceScreen();
+        if (preferenceScreen != null) {
+            preferenceScreen.removeAll();
         }
 
-        // Preference.OnPreferenceChangeListener implementation
-        @Override
-        public boolean onPreferenceChange(Preference preference, Object newValue) {
-            Log.d(this, "onPreferenceChange: key = %s", preference.getKey());
-            Log.d(this, "  preference = '%s'", preference);
-            Log.d(this, "  newValue = '%s'", newValue);
+        // This preference screen is ultra-simple; it's just 4 plain
+        // <EditTextPreference>s, one for each of the 4 "canned responses".
+        //
+        // The only nontrivial thing we do here is copy the text value of
+        // each of those EditTextPreferences and use it as the preference's
+        // "title" as well, so that the user will immediately see all 4
+        // strings when they arrive here.
+        //
+        // Also, listen for change events (since we'll need to update the
+        // title any time the user edits one of the strings.)
 
-            EditTextPreference pref = (EditTextPreference) preference;
+        addPreferencesFromResource(R.xml.respond_via_sms_settings);
+        initPref(findPreference(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_1));
+        initPref(findPreference(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_2));
+        initPref(findPreference(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_3));
+        initPref(findPreference(QuickResponseUtils.KEY_CANNED_RESPONSE_PREF_4));
 
-            // Copy the new text over to the title, just like in onCreate().
-            // (Watch out: onPreferenceChange() is called *before* the
-            // Preference itself gets updated, so we need to use newValue here
-            // rather than pref.getText().)
-            pref.setTitle((String) newValue);
-
-            return true;  // means it's OK to update the state of the Preference with the new value
+        ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            // android.R.id.home will be triggered in onOptionsItemSelected()
+            actionBar.setDisplayHomeAsUpEnabled(true);
         }
+    }
 
-        @Override
-        public boolean onOptionsItemSelected(MenuItem item) {
-            final int itemId = item.getItemId();
-            switch (itemId) {
-                case android.R.id.home:
-                    goUpToTopLevelSetting(this);
-                    return true;
-                default:
-            }
-            return super.onOptionsItemSelected(item);
+    // Preference.OnPreferenceChangeListener implementation
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        Log.d(this, "onPreferenceChange: key = %s", preference.getKey());
+        Log.d(this, "  preference = '%s'", preference);
+        Log.d(this, "  newValue = '%s'", newValue);
+
+        EditTextPreference pref = (EditTextPreference) preference;
+
+        // Copy the new text over to the title, just like in onCreate().
+        // (Watch out: onPreferenceChange() is called *before* the
+        // Preference itself gets updated, so we need to use newValue here
+        // rather than pref.getText().)
+        pref.setTitle((String) newValue);
+
+        // Save the new preference value.
+        SharedPreferences.Editor editor = mPrefs.edit();
+        editor.putString(pref.getKey(), (String) newValue).commit();
+
+        return true;  // means it's OK to update the state of the Preference with the new value
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        final int itemId = item.getItemId();
+        switch (itemId) {
+            case android.R.id.home:
+                goUpToTopLevelSetting(this);
+                return true;
+            default:
         }
+        return super.onOptionsItemSelected(item);
     }
 
     /**
@@ -133,5 +127,15 @@
      */
     public static void goUpToTopLevelSetting(Activity activity) {
         activity.finish();
-     }
+    }
+
+    /**
+     * Initialize the preference to the persisted preference value or default text.
+     */
+    private void initPref(Preference preference) {
+        EditTextPreference pref = (EditTextPreference) preference;
+        pref.setText(mPrefs.getString(pref.getKey(), pref.getText()));
+        pref.setTitle(pref.getText());
+        pref.setOnPreferenceChangeListener(this);
+    }
 }
diff --git a/src/com/android/server/telecom/RingbackPlayer.java b/src/com/android/server/telecom/RingbackPlayer.java
index e6d703c..bb2055f 100644
--- a/src/com/android/server/telecom/RingbackPlayer.java
+++ b/src/com/android/server/telecom/RingbackPlayer.java
@@ -16,8 +16,6 @@
 
 package com.android.server.telecom;
 
-import android.telecom.CallState;
-
 import com.android.internal.util.Preconditions;
 
 /**
@@ -89,7 +87,6 @@
      */
     private void startRingbackForCall(Call call) {
         Preconditions.checkState(call.getState() == CallState.DIALING);
-        ThreadUtil.checkOnMainThread();
 
         if (mCall == call) {
             Log.w(this, "Ignoring duplicate requests to ring for %s.", call);
@@ -116,8 +113,6 @@
      * @param call The call for which to stop ringback.
      */
     private void stopRingbackForCall(Call call) {
-        ThreadUtil.checkOnMainThread();
-
         if (mCall == call) {
             // The foreground call is no longer dialing or is no longer the foreground call. In
             // either case, stop the ringback tone.
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 6b46a71..99fb842 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -26,13 +26,13 @@
 import android.os.SystemVibrator;
 import android.os.Vibrator;
 import android.provider.Settings;
-import android.telecom.CallState;
 
 import java.util.LinkedList;
 import java.util.List;
 
 /**
  * Controls the ringtone player.
+ * TODO: Turn this into a proper state machine: Ringing, CallWaiting, Stopped.
  */
 final class Ringer extends CallsManagerListenerBase {
     private static final long[] VIBRATION_PATTERN = new long[] {
@@ -41,6 +41,10 @@
         1000, // How long to wait before vibrating again
     };
 
+    private static final int STATE_RINGING = 1;
+    private static final int STATE_CALL_WAITING = 2;
+    private static final int STATE_STOPPED = 3;
+
     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
             .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
@@ -63,6 +67,7 @@
     private final Context mContext;
     private final Vibrator mVibrator;
 
+    private int mState = STATE_STOPPED;
     private InCallTonePlayer mCallWaitingPlayer;
 
     /**
@@ -94,7 +99,7 @@
                 Log.wtf(this, "New ringing call is already in list of unanswered calls");
             }
             mRingingCalls.add(call);
-            updateRinging();
+            updateRinging(call);
         }
     }
 
@@ -122,9 +127,14 @@
 
     @Override
     public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) {
-        if (mRingingCalls.contains(oldForegroundCall) ||
-                mRingingCalls.contains(newForegroundCall)) {
-            updateRinging();
+        Call ringingCall = null;
+        if (mRingingCalls.contains(newForegroundCall)) {
+            ringingCall = newForegroundCall;
+        } else if (mRingingCalls.contains(oldForegroundCall)) {
+            ringingCall = oldForegroundCall;
+        }
+        if (ringingCall != null) {
+            updateRinging(ringingCall);
         }
     }
 
@@ -134,7 +144,7 @@
     void silence() {
         // Remove all calls from the "ringing" set and then update the ringer.
         mRingingCalls.clear();
-        updateRinging();
+        updateRinging(null);
     }
 
     private void onRespondedToIncomingCall(Call call) {
@@ -155,25 +165,25 @@
      */
     private void removeFromUnansweredCall(Call call) {
         mRingingCalls.remove(call);
-        updateRinging();
+        updateRinging(call);
     }
 
-    private void updateRinging() {
+    private void updateRinging(Call call) {
         if (mRingingCalls.isEmpty()) {
-            stopRinging();
-            stopCallWaiting();
+            stopRinging(call, "No more ringing calls found");
+            stopCallWaiting(call);
         } else {
-            startRingingOrCallWaiting();
+            startRingingOrCallWaiting(call);
         }
     }
 
-    private void startRingingOrCallWaiting() {
+    private void startRingingOrCallWaiting(Call call) {
         Call foregroundCall = mCallsManager.getForegroundCall();
         Log.v(this, "startRingingOrCallWaiting, foregroundCall: %s.", foregroundCall);
 
         if (mRingingCalls.contains(foregroundCall)) {
             // The foreground call is one of incoming calls so play the ringer out loud.
-            stopCallWaiting();
+            stopCallWaiting(call);
 
             if (!shouldRingForContact(foregroundCall.getContactUri())) {
                 return;
@@ -182,8 +192,11 @@
             AudioManager audioManager =
                     (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
             if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
-                Log.v(this, "startRingingOrCallWaiting");
-                mCallAudioManager.setIsRinging(true);
+                if (mState != STATE_RINGING) {
+                    Log.event(call, Log.Events.START_RINGER);
+                    mState = STATE_RINGING;
+                }
+                mCallAudioManager.setIsRinging(call, true);
 
                 // Because we wait until a contact info query to complete before processing a
                 // call (for the purposes of direct-to-voicemail), the information about custom
@@ -207,7 +220,13 @@
             Log.v(this, "Playing call-waiting tone.");
 
             // All incoming calls are in background so play call waiting.
-            stopRinging();
+            stopRinging(call, "Stop for call-waiting");
+
+
+            if (mState != STATE_CALL_WAITING) {
+                Log.event(call, Log.Events.START_CALL_WAITING_TONE);
+                mState = STATE_CALL_WAITING;
+            }
 
             if (mCallWaitingPlayer == null) {
                 mCallWaitingPlayer =
@@ -227,8 +246,11 @@
         return manager.matchesCallFilter(extras);
     }
 
-    private void stopRinging() {
-        Log.v(this, "stopRinging");
+    private void stopRinging(Call call, String reasonTag) {
+        if (mState == STATE_RINGING) {
+            Log.event(call, Log.Events.STOP_RINGER, reasonTag);
+            mState = STATE_STOPPED;
+        }
 
         mRingtonePlayer.stop();
 
@@ -239,15 +261,20 @@
 
         // Even though stop is asynchronous it's ok to update the audio manager. Things like audio
         // focus are voluntary so releasing focus too early is not detrimental.
-        mCallAudioManager.setIsRinging(false);
+        mCallAudioManager.setIsRinging(call, false);
     }
 
-    private void stopCallWaiting() {
+    private void stopCallWaiting(Call call) {
         Log.v(this, "stop call waiting.");
         if (mCallWaitingPlayer != null) {
             mCallWaitingPlayer.stopTone();
             mCallWaitingPlayer = null;
         }
+
+        if (mState == STATE_CALL_WAITING) {
+            Log.event(call, Log.Events.STOP_CALL_WAITING_TONE);
+            mState = STATE_STOPPED;
+        }
     }
 
     private boolean shouldVibrate(Context context) {
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index 9a5ad03..2e63512 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -21,8 +21,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -38,7 +36,7 @@
  * Subclasses supply the service intent and component name and this class will invoke protected
  * methods when the class is bound, unbound, or upon failure.
  */
-abstract class ServiceBinder<ServiceInterface extends IInterface> {
+abstract class ServiceBinder {
 
     /**
      * Callback to notify after a binding succeeds or fails.
@@ -51,22 +49,22 @@
     /**
      * Listener for bind events on ServiceBinder.
      */
-    interface Listener<ServiceBinderClass extends ServiceBinder<?>> {
+    interface Listener<ServiceBinderClass extends ServiceBinder> {
         void onUnbind(ServiceBinderClass serviceBinder);
     }
 
     /**
      * Helper class to perform on-demand binding.
      */
-    final class Binder {
+    final class Binder2 {
         /**
          * Performs an asynchronous bind to the service (only if not already bound) and executes the
          * specified callback.
          *
          * @param callback The callback to notify of the binding's success or failure.
+         * @param call The call for which we are being bound.
          */
-        void bind(BindCallback callback) {
-            ThreadUtil.checkOnMainThread();
+        void bind(BindCallback callback, Call call) {
             Log.d(ServiceBinder.this, "bind()");
 
             // Reset any abort request if we're asked to bind again.
@@ -81,18 +79,18 @@
             mCallbacks.add(callback);
             if (mServiceConnection == null) {
                 Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
-                ServiceConnection connection = new ServiceBinderConnection();
+                ServiceConnection connection = new ServiceBinderConnection(call);
 
-                Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent);
-                final boolean binding;
+                Log.event(call, Log.Events.BIND_CS, mComponentName);
+                final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+                final boolean isBound;
                 if (mUserHandle != null) {
-                    binding = mContext.bindServiceAsUser(serviceIntent, connection,
-                        Context.BIND_AUTO_CREATE, mUserHandle);
+                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
+                            mUserHandle);
                 } else {
-                    binding = mContext.bindService(serviceIntent, connection,
-                        Context.BIND_AUTO_CREATE);
+                    isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
                 }
-                if (!binding) {
+                if (!isBound) {
                     handleFailedConnection();
                     return;
                 }
@@ -105,39 +103,57 @@
     }
 
     private final class ServiceBinderConnection implements ServiceConnection {
+        /**
+         * The initial call for which the service was bound.
+         */
+        private Call mCall;
+
+        ServiceBinderConnection(Call call) {
+            mCall = call;
+        }
+
         @Override
         public void onServiceConnected(ComponentName componentName, IBinder binder) {
-            ThreadUtil.checkOnMainThread();
-            Log.i(this, "Service bound %s", componentName);
+            synchronized (mLock) {
+                Log.i(this, "Service bound %s", componentName);
 
-            // Unbind request was queued so unbind immediately.
-            if (mIsBindingAborted) {
-                clearAbort();
-                logServiceDisconnected("onServiceConnected");
-                mContext.unbindService(this);
-                handleFailedConnection();
-                return;
+                Log.event(mCall, Log.Events.CS_BOUND, componentName);
+                mCall = null;
+
+                // Unbind request was queued so unbind immediately.
+                if (mIsBindingAborted) {
+                    clearAbort();
+                    logServiceDisconnected("onServiceConnected");
+                    mContext.unbindService(this);
+                    handleFailedConnection();
+                    return;
+                }
+
+                mServiceConnection = this;
+                setBinder(binder);
+                handleSuccessfulConnection();
             }
-
-            mServiceConnection = this;
-            setBinder(binder);
-            handleSuccessfulConnection();
         }
 
         @Override
         public void onServiceDisconnected(ComponentName componentName) {
-            logServiceDisconnected("onServiceDisconnected");
+            synchronized (mLock) {
+                logServiceDisconnected("onServiceDisconnected");
 
-            mServiceConnection = null;
-            clearAbort();
+                mServiceConnection = null;
+                clearAbort();
 
-            handleServiceDisconnected();
+                handleServiceDisconnected();
+            }
         }
     }
 
     /** The application context. */
     private final Context mContext;
 
+    /** The Telecom lock object. */
+    protected final TelecomSystem.SyncRoot mLock;
+
     /** The intent action to use when binding through {@link Context#bindService}. */
     private final String mServiceAction;
 
@@ -182,11 +198,12 @@
      * @param userHandle The {@link UserHandle} to use for binding.
      */
     protected ServiceBinder(String serviceAction, ComponentName componentName, Context context,
-            UserHandle userHandle) {
+            TelecomSystem.SyncRoot lock, UserHandle userHandle) {
         Preconditions.checkState(!TextUtils.isEmpty(serviceAction));
         Preconditions.checkNotNull(componentName);
 
         mContext = context;
+        mLock = lock;
         mServiceAction = serviceAction;
         mComponentName = componentName;
         mUserHandle = userHandle;
@@ -221,8 +238,6 @@
      * Unbinds from the service if already bound, no-op otherwise.
      */
     final void unbind() {
-        ThreadUtil.checkOnMainThread();
-
         if (mServiceConnection == null) {
             // We're not yet bound, so queue up an abort request.
             mIsBindingAborted = true;
diff --git a/src/com/android/server/telecom/TelecomBroadcastReceiver.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
similarity index 75%
rename from src/com/android/server/telecom/TelecomBroadcastReceiver.java
rename to src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index cc5116d..89aa2aa 100644
--- a/src/com/android/server/telecom/TelecomBroadcastReceiver.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -16,57 +16,58 @@
 
 package com.android.server.telecom;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
 
-/**
- * Handles miscellaneous Telecom broadcast intents. This should be visible from outside, but
- * should not be in the "exported" state.
- */
-public final class TelecomBroadcastReceiver extends BroadcastReceiver {
+public final class TelecomBroadcastIntentProcessor {
     /** The action used to send SMS response for the missed call notification. */
-    static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
+    public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
             "com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION";
 
     /** The action used to call a handle back for the missed call notification. */
-    static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
+    public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
             "com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION";
 
     /** The action used to clear missed calls. */
-    static final String ACTION_CLEAR_MISSED_CALLS =
+    public static final String ACTION_CLEAR_MISSED_CALLS =
             "com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS";
 
-    /** {@inheritDoc} */
-    @Override
-    public void onReceive(Context context, Intent intent) {
+    private final Context mContext;
+    private final CallsManager mCallsManager;
+
+    public TelecomBroadcastIntentProcessor(Context context, CallsManager callsManager) {
+        mContext = context;
+        mCallsManager = callsManager;
+    }
+
+    public void processIntent(Intent intent) {
         String action = intent.getAction();
 
         Log.v(this, "Action received: %s.", action);
 
-        MissedCallNotifier missedCallNotifier = CallsManager.getInstance().getMissedCallNotifier();
+        MissedCallNotifier missedCallNotifier = mCallsManager.getMissedCallNotifier();
 
         // Send an SMS from the missed call notification.
         if (ACTION_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
             // Close the notification shade and the notification itself.
-            closeSystemDialogs(context);
+            closeSystemDialogs(mContext);
             missedCallNotifier.clearMissedCalls();
 
             Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
             callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            context.startActivity(callIntent);
+            mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
 
         // Call back recent caller from the missed call notification.
         } else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
             // Close the notification shade and the notification itself.
-            closeSystemDialogs(context);
+            closeSystemDialogs(mContext);
             missedCallNotifier.clearMissedCalls();
 
             Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
             callIntent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            context.startActivity(callIntent);
+            mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
 
         // Clear the missed call notification and call log entries.
         } else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
diff --git a/src/com/android/server/telecom/TelecomGlobals.java b/src/com/android/server/telecom/TelecomGlobals.java
deleted file mode 100644
index cf0936c..0000000
--- a/src/com/android/server/telecom/TelecomGlobals.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.telecom;
-
-import android.app.Application;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-
-/**
- * Top-level Application class for Telecom.
- */
-public final class TelecomGlobals {
-    private static final String TAG = TelecomGlobals.class.getSimpleName();
-
-    private static final IntentFilter USER_SWITCHED_FILTER =
-            new IntentFilter(Intent.ACTION_USER_SWITCHED);
-
-    private static final TelecomGlobals INSTANCE = new TelecomGlobals();
-
-    /**
-     * The Telecom service implementation.
-     */
-    private TelecomService mTelecomService;
-
-    /**
-     * Missed call notifier. Exists here so that the instance can be shared with
-     * {@link TelecomBroadcastReceiver}.
-     */
-    private MissedCallNotifier mMissedCallNotifier;
-
-    /**
-     * Maintains the list of registered {@link android.telecom.PhoneAccountHandle}s.
-     */
-    private PhoneAccountRegistrar mPhoneAccountRegistrar;
-
-    /**
-     * The calls manager for the Telecom service.
-     */
-    private CallsManager mCallsManager;
-
-    /**
-     * The application context.
-     */
-    private Context mContext;
-
-    private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-            UserHandle currentUserHandle = new UserHandle(userHandleId);
-            mPhoneAccountRegistrar.setCurrentUserHandle(currentUserHandle);
-        }
-    };
-
-    static TelecomGlobals getInstance() {
-        return INSTANCE;
-    }
-
-    void initialize(Context context) {
-        if (mContext != null) {
-            Log.e(TAG, new Exception(), "Attempting to intialize TelecomGlobals a second time.");
-            return;
-        } else {
-            Log.i(TAG, "TelecomGlobals initializing");
-        }
-        mContext = context.getApplicationContext();
-
-        mMissedCallNotifier = new MissedCallNotifier(mContext);
-        mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);
-
-        mCallsManager = new CallsManager(mContext, mMissedCallNotifier, mPhoneAccountRegistrar);
-        CallsManager.initialize(mCallsManager);
-        Log.i(this, "CallsManager initialized");
-
-        // Start the BluetoothPhoneService
-        BluetoothPhoneService.start(mContext);
-
-        mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);
-    }
-
-    MissedCallNotifier getMissedCallNotifier() {
-        return mMissedCallNotifier;
-    }
-
-    PhoneAccountRegistrar getPhoneAccountRegistrar() {
-        return mPhoneAccountRegistrar;
-    }
-
-    CallsManager getCallsManager() {
-        return mCallsManager;
-    }
-}
diff --git a/src/com/android/server/telecom/TelecomService.java b/src/com/android/server/telecom/TelecomService.java
deleted file mode 100644
index 77fb1d2..0000000
--- a/src/com/android/server/telecom/TelecomService.java
+++ /dev/null
@@ -1,1029 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.telecom;
-
-import android.Manifest;
-import android.annotation.SdkConstant;
-import android.app.AppOpsManager;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.telecom.CallState;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import android.util.EventLog;
-
-// TODO: Needed for move to system service: import com.android.internal.R;
-import com.android.internal.telecom.ITelecomService;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation of the ITelecom interface.
- */
-public class TelecomService extends Service {
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE = "android.telecom.ITelecomService";
-
-    /** The context. */
-    private Context mContext;
-
-    /**
-     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
-     * request after sending. The main thread will notify the request when it is complete.
-     */
-    private static final class MainThreadRequest {
-        /** The result of the request that is run on the main thread */
-        public Object result;
-        /** Object that can be used to store non-integer arguments */
-        public Object arg;
-    }
-
-    /**
-     * A handler that processes messages on the main thread. Since many of the method calls are not
-     * thread safe this is needed to shuttle the requests from the inbound binder threads to the
-     * main thread.
-     */
-    private final class MainThreadHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.obj instanceof MainThreadRequest) {
-                MainThreadRequest request = (MainThreadRequest) msg.obj;
-                Object result = null;
-                switch (msg.what) {
-                    case MSG_SILENCE_RINGER:
-                        mCallsManager.getRinger().silence();
-                        break;
-                    case MSG_SHOW_CALL_SCREEN:
-                        mCallsManager.getInCallController().bringToForeground(msg.arg1 == 1);
-                        break;
-                    case MSG_END_CALL:
-                        result = endCallInternal();
-                        break;
-                    case MSG_ACCEPT_RINGING_CALL:
-                        acceptRingingCallInternal();
-                        break;
-                    case MSG_CANCEL_MISSED_CALLS_NOTIFICATION:
-                        mMissedCallNotifier.clearMissedCalls();
-                        break;
-                    case MSG_IS_TTY_SUPPORTED:
-                        result = mCallsManager.isTtySupported();
-                        break;
-                    case MSG_GET_CURRENT_TTY_MODE:
-                        result = mCallsManager.getCurrentTtyMode();
-                        break;
-                    case MSG_NEW_INCOMING_CALL:
-                        if (request.arg == null || !(request.arg instanceof Intent)) {
-                            Log.w(this, "Invalid new incoming call request");
-                            break;
-                        }
-                        CallReceiver.processIncomingCallIntent((Intent) request.arg);
-                        break;
-                }
-
-                if (result != null) {
-                    request.result = result;
-                    synchronized(request) {
-                        request.notifyAll();
-                    }
-                }
-            }
-        }
-    }
-
-    private static final String TAG = TelecomService.class.getSimpleName();
-
-    private static final String SERVICE_NAME = "telecom";
-
-    private static final int MSG_SILENCE_RINGER = 1;
-    private static final int MSG_SHOW_CALL_SCREEN = 2;
-    private static final int MSG_END_CALL = 3;
-    private static final int MSG_ACCEPT_RINGING_CALL = 4;
-    private static final int MSG_CANCEL_MISSED_CALLS_NOTIFICATION = 5;
-    private static final int MSG_IS_TTY_SUPPORTED = 6;
-    private static final int MSG_GET_CURRENT_TTY_MODE = 7;
-    private static final int MSG_NEW_INCOMING_CALL = 8;
-
-    private final MainThreadHandler mMainThreadHandler = new MainThreadHandler();
-
-    private CallsManager mCallsManager;
-    private MissedCallNotifier mMissedCallNotifier;
-    private PhoneAccountRegistrar mPhoneAccountRegistrar;
-    private AppOpsManager mAppOpsManager;
-    private UserManager mUserManager;
-    private PackageManager mPackageManager;
-    private TelecomServiceImpl mServiceImpl;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        Log.d(this, "onCreate");
-        mContext = this;
-        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        mServiceImpl = new TelecomServiceImpl();
-
-        TelecomGlobals globals = TelecomGlobals.getInstance();
-        globals.initialize(this);
-
-        mMissedCallNotifier = globals.getMissedCallNotifier();
-        mPhoneAccountRegistrar = globals.getPhoneAccountRegistrar();
-        mCallsManager = globals.getCallsManager();
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mPackageManager = mContext.getPackageManager();
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        Log.d(this, "onBind");
-        return mServiceImpl;
-    }
-
-    /**
-     * Implementation of the ITelecomService interface.
-     * TODO: Reorganize this inner class to top of file.
-     */
-    class TelecomServiceImpl extends ITelecomService.Stub {
-        @Override
-        public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
-            enforceReadPermission();
-            long token = Binder.clearCallingIdentity();
-            try {
-                PhoneAccountHandle defaultOutgoingPhoneAccount =
-                        mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount(uriScheme);
-                // Make sure that the calling user can see this phone account.
-                if (defaultOutgoingPhoneAccount != null
-                        && !isVisibleToCaller(defaultOutgoingPhoneAccount)) {
-                    Log.w(this, "No account found for the calling user");
-                    return null;
-                }
-                return defaultOutgoingPhoneAccount;
-            } catch (Exception e) {
-                Log.e(this, e, "getDefaultOutgoingPhoneAccount");
-                throw e;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
-            try {
-                PhoneAccountHandle userSelectedOutgoingPhoneAccount =
-                        mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount();
-                // Make sure that the calling user can see this phone account.
-                if (!isVisibleToCaller(userSelectedOutgoingPhoneAccount)) {
-                    Log.w(this, "No account found for the calling user");
-                    return null;
-                }
-                return userSelectedOutgoingPhoneAccount;
-            } catch (Exception e) {
-                Log.e(this, e, "getUserSelectedOutgoingPhoneAccount");
-                throw e;
-            }
-        }
-
-        @Override
-        public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
-            enforceModifyPermission();
-
-            try {
-                mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle);
-            } catch (Exception e) {
-                Log.e(this, e, "setUserSelectedOutgoingPhoneAccount");
-                throw e;
-            }
-        }
-
-        @Override
-        public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
-            enforceReadPermission();
-            long token = Binder.clearCallingIdentity();
-            try {
-                return filterForAccountsVisibleToCaller(
-                        mPhoneAccountRegistrar.getCallCapablePhoneAccounts());
-            } catch (Exception e) {
-                Log.e(this, e, "getCallCapablePhoneAccounts");
-                throw e;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
-            enforceReadPermission();
-            long token = Binder.clearCallingIdentity();
-            try {
-                return filterForAccountsVisibleToCaller(
-                        mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme));
-            } catch (Exception e) {
-                Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
-                throw e;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
-            try {
-                return filterForAccountsVisibleToCaller(
-                        mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName));
-            } catch (Exception e) {
-                Log.e(this, e, "getPhoneAccountsForPackage %s", packageName);
-                throw e;
-            }
-        }
-
-        @Override
-        public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
-            try {
-                if (!isVisibleToCaller(accountHandle)) {
-                    Log.w(this, "%s is not visible for the calling user", accountHandle);
-                    return null;
-                }
-                return mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle);
-            } catch (Exception e) {
-                Log.e(this, e, "getPhoneAccount %s", accountHandle);
-                throw e;
-            }
-        }
-
-        @Override
-        public int getAllPhoneAccountsCount() {
-            try {
-                // This list is pre-filtered for the calling user.
-                return getAllPhoneAccounts().size();
-            } catch (Exception e) {
-                Log.e(this, e, "getAllPhoneAccountsCount");
-                throw e;
-            }
-        }
-
-        @Override
-        public List<PhoneAccount> getAllPhoneAccounts() {
-            try {
-                List<PhoneAccount> allPhoneAccounts = mPhoneAccountRegistrar.getAllPhoneAccounts();
-                List<PhoneAccount> profilePhoneAccounts = new ArrayList<>(allPhoneAccounts.size());
-                for (PhoneAccount phoneAccount : profilePhoneAccounts) {
-                    if (isVisibleToCaller(phoneAccount)) {
-                        profilePhoneAccounts.add(phoneAccount);
-                    }
-                }
-                return profilePhoneAccounts;
-            } catch (Exception e) {
-                Log.e(this, e, "getAllPhoneAccounts");
-                throw e;
-            }
-        }
-
-        @Override
-        public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
-            try {
-                return filterForAccountsVisibleToCaller(
-                        mPhoneAccountRegistrar.getAllPhoneAccountHandles());
-            } catch (Exception e) {
-                Log.e(this, e, "getAllPhoneAccounts");
-                throw e;
-            }
-        }
-
-        @Override
-        public PhoneAccountHandle getSimCallManager() {
-            try {
-                PhoneAccountHandle accountHandle = mPhoneAccountRegistrar.getSimCallManager();
-                if (!isVisibleToCaller(accountHandle)) {
-                    Log.w(this, "%s is not visible for the calling user", accountHandle);
-                    return null;
-                }
-                return accountHandle;
-            } catch (Exception e) {
-                Log.e(this, e, "getSimCallManager");
-                throw e;
-            }
-        }
-
-        @Override
-        public void setSimCallManager(PhoneAccountHandle accountHandle) {
-            enforceModifyPermission();
-
-            try {
-                mPhoneAccountRegistrar.setSimCallManager(accountHandle);
-            } catch (Exception e) {
-                Log.e(this, e, "setSimCallManager");
-                throw e;
-            }
-        }
-
-        @Override
-        public List<PhoneAccountHandle> getSimCallManagers() {
-            enforceReadPermission();
-            long token = Binder.clearCallingIdentity();
-            try {
-                return filterForAccountsVisibleToCaller(
-                        mPhoneAccountRegistrar.getConnectionManagerPhoneAccounts());
-            } catch (Exception e) {
-                Log.e(this, e, "getSimCallManagers");
-                throw e;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void registerPhoneAccount(PhoneAccount account) {
-            try {
-                enforcePhoneAccountModificationForPackage(
-                        account.getAccountHandle().getComponentName().getPackageName());
-                if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
-                    enforceRegisterCallProviderPermission();
-                }
-                if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
-                    enforceRegisterSimSubscriptionPermission();
-                }
-                if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
-                    enforceRegisterConnectionManagerPermission();
-                }
-                if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
-                    enforceRegisterMultiUser();
-                }
-                enforceUserHandleMatchesCaller(account.getAccountHandle());
-
-                mPhoneAccountRegistrar.registerPhoneAccount(account);
-            } catch (Exception e) {
-                Log.e(this, e, "registerPhoneAccount %s", account);
-                throw e;
-            }
-        }
-
-        @Override
-        public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
-            try {
-                enforcePhoneAccountModificationForPackage(
-                        accountHandle.getComponentName().getPackageName());
-                enforceUserHandleMatchesCaller(accountHandle);
-                mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
-            } catch (Exception e) {
-                Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
-                throw e;
-            }
-        }
-
-        @Override
-        public void clearAccounts(String packageName) {
-            try {
-                enforcePhoneAccountModificationForPackage(packageName);
-                mPhoneAccountRegistrar.clearAccounts(packageName, Binder.getCallingUserHandle());
-            } catch (Exception e) {
-                Log.e(this, e, "clearAccounts %s", packageName);
-                throw e;
-            }
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#isVoiceMailNumber
-         */
-        @Override
-        public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
-            enforceReadPermissionOrDefaultDialer();
-            try {
-                if (!isVisibleToCaller(accountHandle)) {
-                    Log.w(this, "%s is not visible for the calling user", accountHandle);
-                    return false;
-                }
-                return mPhoneAccountRegistrar.isVoiceMailNumber(accountHandle, number);
-            } catch (Exception e) {
-                Log.e(this, e, "getSubscriptionIdForPhoneAccount");
-                throw e;
-            }
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#hasVoiceMailNumber
-         */
-        @Override
-        public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
-            enforceReadPermissionOrDefaultDialer();
-            try {
-                if (!isVisibleToCaller(accountHandle)) {
-                    Log.w(this, "%s is not visible for the calling user", accountHandle);
-                    return false;
-                }
-
-                int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-                return !TextUtils.isEmpty(getTelephonyManager().getVoiceMailNumber(subId));
-            } catch (Exception e) {
-                Log.e(this, e, "getSubscriptionIdForPhoneAccount");
-                throw e;
-            }
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#getLine1Number
-         */
-        @Override
-        public String getLine1Number(PhoneAccountHandle accountHandle) {
-            enforceReadPermissionOrDefaultDialer();
-            try {
-                if (!isVisibleToCaller(accountHandle)) {
-                    Log.w(this, "%s is not visible for the calling user", accountHandle);
-                    return null;
-                }
-                int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-                return getTelephonyManager().getLine1NumberForSubscriber(subId);
-            } catch (Exception e) {
-                Log.e(this, e, "getSubscriptionIdForPhoneAccount");
-                throw e;
-            }
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#silenceRinger
-         */
-        @Override
-        public void silenceRinger() {
-            Log.d(this, "silenceRinger");
-            enforceModifyPermission();
-            sendRequestAsync(MSG_SILENCE_RINGER, 0);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#getDefaultPhoneApp
-         */
-        @Override
-        public ComponentName getDefaultPhoneApp() {
-            Resources resources = mContext.getResources();
-            return new ComponentName(
-                    resources.getString(R.string.ui_default_package),
-                    resources.getString(R.string.dialer_default_class));
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#isInCall
-         */
-        @Override
-        public boolean isInCall() {
-            enforceReadPermission();
-            // Do not use sendRequest() with this method since it could cause a deadlock with
-            // audio service, which we call into from the main thread: AudioManager.setMode().
-            final int callState = mCallsManager.getCallState();
-            return callState == TelephonyManager.CALL_STATE_OFFHOOK
-                    || callState == TelephonyManager.CALL_STATE_RINGING;
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#isRinging
-         */
-        @Override
-        public boolean isRinging() {
-            enforceReadPermission();
-            return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
-        }
-
-        /**
-         * @see TelecomManager#getCallState
-         */
-        @Override
-        public int getCallState() {
-            return mCallsManager.getCallState();
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#endCall
-         */
-        @Override
-        public boolean endCall() {
-            enforceModifyPermission();
-            return (boolean) sendRequest(MSG_END_CALL);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#acceptRingingCall
-         */
-        @Override
-        public void acceptRingingCall() {
-            enforceModifyPermission();
-            sendRequestAsync(MSG_ACCEPT_RINGING_CALL, 0);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#showInCallScreen
-         */
-        @Override
-        public void showInCallScreen(boolean showDialpad) {
-            enforceReadPermissionOrDefaultDialer();
-            sendRequestAsync(MSG_SHOW_CALL_SCREEN, showDialpad ? 1 : 0);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#cancelMissedCallsNotification
-         */
-        @Override
-        public void cancelMissedCallsNotification() {
-            enforceModifyPermissionOrDefaultDialer();
-            sendRequestAsync(MSG_CANCEL_MISSED_CALLS_NOTIFICATION, 0);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#handleMmi
-         */
-        @Override
-        public boolean handlePinMmi(String dialString) {
-            enforceModifyPermissionOrDefaultDialer();
-
-            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-            long token = Binder.clearCallingIdentity();
-            boolean retval = false;
-            try {
-                retval = getTelephonyManager().handlePinMmi(dialString);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-            return retval;
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#handleMmi
-         */
-        @Override
-        public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
-                String dialString) {
-            enforceModifyPermissionOrDefaultDialer();
-
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return false;
-            }
-
-            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-            long token = Binder.clearCallingIdentity();
-            boolean retval = false;
-            try {
-                int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-                retval = getTelephonyManager().handlePinMmiForSubscriber(subId, dialString);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-            return retval;
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#getAdnUriForPhoneAccount
-         */
-        @Override
-        public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
-            enforceModifyPermissionOrDefaultDialer();
-
-            if (!isVisibleToCaller(accountHandle)) {
-                Log.w(this, "%s is not visible for the calling user", accountHandle);
-                return null;
-            }
-
-            // Switch identity so that TelephonyManager checks Telecom's permissions instead.
-            long token = Binder.clearCallingIdentity();
-            String retval = "content://icc/adn/";
-            try {
-                long subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
-                retval = retval + "subId/" + subId;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-            return Uri.parse(retval);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#isTtySupported
-         */
-        @Override
-        public boolean isTtySupported() {
-            enforceReadPermission();
-            return (boolean) sendRequest(MSG_IS_TTY_SUPPORTED);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#getCurrentTtyMode
-         */
-        @Override
-        public int getCurrentTtyMode() {
-            enforceReadPermission();
-            return (int) sendRequest(MSG_GET_CURRENT_TTY_MODE);
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#addNewIncomingCall
-         */
-        @Override
-        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
-            Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle);
-            if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
-                // TODO(sail): Add unit tests for adding incoming calls from a SIM call manager.
-                if (isCallerSimCallManager() && TelephonyUtil.isPstnComponentName(
-                        phoneAccountHandle.getComponentName())) {
-                    Log.v(this, "Allowing call manager to add incoming call with PSTN handle");
-                } else {
-                    mAppOpsManager.checkPackage(Binder.getCallingUid(),
-                            phoneAccountHandle.getComponentName().getPackageName());
-
-                    enforcePhoneAccountIsRegistered(phoneAccountHandle);
-                    // Make sure it doesn't cross the UserHandle boundary
-                    enforceUserHandleMatchesCaller(phoneAccountHandle);
-                }
-
-                Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
-                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
-                intent.putExtra(CallReceiver.KEY_IS_INCOMING_CALL, true);
-                if (extras != null) {
-                    intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
-                }
-                sendRequestAsync(MSG_NEW_INCOMING_CALL, 0, intent);
-            } else {
-                Log.w(this, "Null phoneAccountHandle. Ignoring request to add new incoming call");
-            }
-        }
-
-        /**
-         * @see android.telecom.TelecomManager#addNewUnknownCall
-         */
-        @Override
-        public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
-            if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null &&
-                    TelephonyUtil.isPstnComponentName(phoneAccountHandle.getComponentName())) {
-                mAppOpsManager.checkPackage(
-                        Binder.getCallingUid(), phoneAccountHandle.getComponentName().getPackageName());
-
-                enforcePhoneAccountIsRegistered(phoneAccountHandle);
-                // Make sure it doesn't cross the UserHandle boundary
-                enforceUserHandleMatchesCaller(phoneAccountHandle);
-
-                Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
-                intent.setClass(mContext, CallReceiver.class);
-                intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                intent.putExtras(extras);
-                intent.putExtra(CallReceiver.KEY_IS_UNKNOWN_CALL, true);
-                intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
-                mContext.sendBroadcastAsUser(intent, phoneAccountHandle.getUserHandle());
-            } else {
-                Log.i(this, "Null phoneAccountHandle or not initiated by Telephony. Ignoring request"
-                        + " to add new unknown call.");
-            }
-        }
-
-        /**
-         * Dumps the current state of the TelecomService.  Used when generating problem reports.
-         *
-         * @param fd The file descriptor.
-         * @param writer The print writer to dump the state to.
-         * @param args Optional dump arguments.
-         */
-        @Override
-        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
-            if (mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.DUMP)
-                    != PackageManager.PERMISSION_GRANTED) {
-                writer.println("Permission Denial: can't dump TelecomService " +
-                        "from from pid=" + Binder.getCallingPid() + ", uid=" +
-                        Binder.getCallingUid());
-                return;
-            }
-
-            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-            if (mCallsManager != null) {
-                pw.println("mCallsManager: ");
-                pw.increaseIndent();
-                mCallsManager.dump(pw);
-                pw.decreaseIndent();
-
-                pw.println("mPhoneAccountRegistrar: ");
-                pw.increaseIndent();
-                mPhoneAccountRegistrar.dump(pw);
-                pw.decreaseIndent();
-            }
-        }
-    }
-
-    //
-    // Supporting methods for the ITelecomService interface implementation.
-    //
-
-    private boolean isVisibleToCaller(PhoneAccountHandle accountHandle) {
-        if (accountHandle == null) {
-            return false;
-        }
-
-        return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccountInternal(accountHandle));
-    }
-
-    private boolean isVisibleToCaller(PhoneAccount account) {
-        if (account == null) {
-            return false;
-        }
-
-        // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
-        // all profiles. Only Telephony and SIP accounts should have this capability.
-        if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
-            return true;
-        }
-
-        UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
-        if (phoneAccountUserHandle == null) {
-            return false;
-        }
-
-        List<UserHandle> profileUserHandles;
-        if (isCallerSystemApp()) {
-            // If the caller lives in /system/priv-app, it can see PhoneAccounts for all of the
-            // *profiles* that the calling user owns, but not for any other *users*.
-            profileUserHandles = mUserManager.getUserProfiles();
-        } else {
-            // Otherwise, it has to be owned by the current caller's profile.
-            profileUserHandles = new ArrayList<>(1);
-            profileUserHandles.add(Binder.getCallingUserHandle());
-        }
-
-        return profileUserHandles.contains(phoneAccountUserHandle);
-    }
-
-    /**
-     * Given a list of {@link PhoneAccountHandle}s, filter them to the ones that the calling
-     * user can see.
-     *
-     * @param phoneAccountHandles Unfiltered list of account handles.
-     *
-     * @return {@link PhoneAccountHandle}s visible to the calling user and its profiles.
-     */
-    private List<PhoneAccountHandle> filterForAccountsVisibleToCaller(
-            List<PhoneAccountHandle> phoneAccountHandles) {
-        List<PhoneAccountHandle> profilePhoneAccountHandles =
-                new ArrayList<>(phoneAccountHandles.size());
-        for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
-            if (isVisibleToCaller(phoneAccountHandle)) {
-                profilePhoneAccountHandles.add(phoneAccountHandle);
-            }
-        }
-        return profilePhoneAccountHandles;
-    }
-
-    private boolean isCallerSystemApp() {
-        int uid = Binder.getCallingUid();
-        String[] packages = mPackageManager.getPackagesForUid(uid);
-        for (String packageName : packages) {
-            if (isPackageSystemApp(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isPackageSystemApp(String packageName) {
-        try {
-            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA);
-            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                return true;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-        }
-        return false;
-    }
-
-    private void acceptRingingCallInternal() {
-        Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
-        if (call != null) {
-            call.answer(call.getVideoState());
-        }
-    }
-
-    private boolean endCallInternal() {
-        // Always operate on the foreground call if one exists, otherwise get the first call in
-        // priority order by call-state.
-        Call call = mCallsManager.getForegroundCall();
-        if (call == null) {
-            call = mCallsManager.getFirstCallWithState(
-                    CallState.ACTIVE,
-                    CallState.DIALING,
-                    CallState.RINGING,
-                    CallState.ON_HOLD);
-        }
-
-        if (call != null) {
-            if (call.getState() == CallState.RINGING) {
-                call.reject(false /* rejectWithMessage */, null);
-            } else {
-                call.disconnect();
-            }
-            return true;
-        }
-
-        return false;
-    }
-
-    // Enforce that the PhoneAccountHandle being passed in is registered to a valid PhoneAccount. 
-    private void enforcePhoneAccountIsRegistered(PhoneAccountHandle phoneAccountHandle) {
-        PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle);
-        if(phoneAccount == null) {
-            EventLog.writeEvent(0x534e4554, "26864502", Binder.getCallingUid(), "R");
-            throw new SecurityException("This PhoneAccountHandle is not registered to a valid " +
-                    "PhoneAccount!");
-        }
-    }
-
-    private void enforcePhoneAccountModificationForPackage(String packageName) {
-        // TODO: Use a new telecomm permission for this instead of reusing modify.
-
-        int result = mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
-
-        // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
-        // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
-        // may also modify PhoneAccounts on behalf of any 'packageName'.
-
-        if (result != PackageManager.PERMISSION_GRANTED) {
-            // Other callers are only allowed to modify PhoneAccounts if the relevant system
-            // feature is enabled ...
-            enforceConnectionServiceFeature();
-            // ... and the PhoneAccounts they refer to are for their own package.
-            enforceCallingPackage(packageName);
-        }
-    }
-
-    private void enforceReadPermissionOrDefaultDialer() {
-        if (!isDefaultDialerCalling()) {
-            enforceReadPermission();
-        }
-    }
-
-    private void enforceModifyPermissionOrDefaultDialer() {
-        if (!isDefaultDialerCalling()) {
-            enforceModifyPermission();
-        }
-    }
-
-    private void enforceCallingPackage(String packageName) {
-        mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
-    }
-
-    private void enforceConnectionServiceFeature() {
-        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
-    }
-
-    private void enforceRegisterCallProviderPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_CALL_PROVIDER);
-    }
-
-    private void enforceRegisterSimSubscriptionPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION);
-    }
-
-    private void enforceRegisterConnectionManagerPermission() {
-        enforcePermission(android.Manifest.permission.REGISTER_CONNECTION_MANAGER);
-    }
-
-    private void enforceReadPermission() {
-        enforcePermission(Manifest.permission.READ_PHONE_STATE);
-    }
-
-    private void enforceModifyPermission() {
-        enforcePermission(Manifest.permission.MODIFY_PHONE_STATE);
-    }
-
-    private void enforcePermission(String permission) {
-        mContext.enforceCallingOrSelfPermission(permission, null);
-    }
-
-    private void enforceRegisterMultiUser() {
-        if (!isCallerSystemApp()) {
-            throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");
-        }
-    }
-
-    private void enforceUserHandleMatchesCaller(PhoneAccountHandle accountHandle) {
-        if (!Binder.getCallingUserHandle().equals(accountHandle.getUserHandle())) {
-            throw new SecurityException("Calling UserHandle does not match PhoneAccountHandle's");
-        }
-    }
-
-    private void enforceFeature(String feature) {
-        PackageManager pm = mContext.getPackageManager();
-        if (!pm.hasSystemFeature(feature)) {
-            throw new UnsupportedOperationException(
-                    "System does not support feature " + feature);
-        }
-    }
-
-    private boolean isCallerSimCallManager() {
-        PhoneAccountHandle accountHandle = mPhoneAccountRegistrar.getSimCallManager();
-        if (accountHandle != null) {
-            try {
-                mAppOpsManager.checkPackage(
-                        Binder.getCallingUid(), accountHandle.getComponentName().getPackageName());
-                return true;
-            } catch (SecurityException e) {
-            }
-        }
-        return false;
-    }
-
-    private boolean isDefaultDialerCalling() {
-        ComponentName defaultDialerComponent = getDefaultPhoneAppInternal();
-        if (defaultDialerComponent != null) {
-            try {
-                mAppOpsManager.checkPackage(
-                        Binder.getCallingUid(), defaultDialerComponent.getPackageName());
-                return true;
-            } catch (SecurityException e) {
-                Log.e(TAG, e, "Could not get default dialer.");
-            }
-        }
-        return false;
-    }
-
-    private ComponentName getDefaultPhoneAppInternal() {
-        Resources resources = mContext.getResources();
-        return new ComponentName(
-                resources.getString(R.string.ui_default_package),
-                resources.getString(R.string.dialer_default_class));
-    }
-
-    private TelephonyManager getTelephonyManager() {
-        return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
-    }
-
-    private MainThreadRequest sendRequestAsync(int command, int arg1) {
-        return sendRequestAsync(command, arg1, null);
-    }
-
-    private MainThreadRequest sendRequestAsync(int command, int arg1, Object arg) {
-        MainThreadRequest request = new MainThreadRequest();
-        request.arg = arg;
-        mMainThreadHandler.obtainMessage(command, arg1, 0, request).sendToTarget();
-        return request;
-    }
-
-    /**
-     * Posts the specified command to be executed on the main thread, waits for the request to
-     * complete, and returns the result.
-     */
-    private Object sendRequest(int command) {
-        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
-            MainThreadRequest request = new MainThreadRequest();
-            mMainThreadHandler.handleMessage(mMainThreadHandler.obtainMessage(command, request));
-            return request.result;
-        } else {
-            MainThreadRequest request = sendRequestAsync(command, 0);
-
-            // Wait for the request to complete
-            synchronized (request) {
-                while (request.result == null) {
-                    try {
-                        request.wait();
-                    } catch (InterruptedException e) {
-                        // Do nothing, go back and wait until the request is complete
-                    }
-                }
-            }
-            return request.result;
-        }
-    }
-}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
new file mode 100644
index 0000000..3ceaa73
--- /dev/null
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import static android.Manifest.permission.CALL_PHONE;
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.DefaultDialerManager;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.EventLog;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+import com.android.internal.telecom.ITelecomService;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.telecom.components.UserCallIntentProcessor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Implementation of the ITelecom interface.
+ */
+public class TelecomServiceImpl {
+    private static final String PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION =
+            "android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION";
+
+    private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
+        @Override
+        public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme,
+                String callingPackage) {
+            synchronized (mLock) {
+                if (!canReadPhoneState(callingPackage, "getDefaultOutgoingPhoneAccount")) {
+                    return null;
+                }
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    PhoneAccountHandle defaultOutgoingPhoneAccount =
+                            mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(uriScheme);
+                    // Make sure that the calling user can see this phone account.
+                    // TODO: Does this isVisible check actually work considering we are clearing
+                    // the calling identity?
+                    if (defaultOutgoingPhoneAccount != null
+                            && !isVisibleToCaller(defaultOutgoingPhoneAccount)) {
+                        Log.w(this, "No account found for the calling user");
+                        return null;
+                    }
+                    return defaultOutgoingPhoneAccount;
+                } catch (Exception e) {
+                    Log.e(this, e, "getDefaultOutgoingPhoneAccount");
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
+            synchronized (mLock) {
+                try {
+                    PhoneAccountHandle userSelectedOutgoingPhoneAccount =
+                            mPhoneAccountRegistrar.getUserSelectedOutgoingPhoneAccount();
+                    // Make sure that the calling user can see this phone account.
+                    if (!isVisibleToCaller(userSelectedOutgoingPhoneAccount)) {
+                        Log.w(this, "No account found for the calling user");
+                        return null;
+                    }
+                    return userSelectedOutgoingPhoneAccount;
+                } catch (Exception e) {
+                    Log.e(this, e, "getUserSelectedOutgoingPhoneAccount");
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mPhoneAccountRegistrar.setUserSelectedOutgoingPhoneAccount(accountHandle);
+                } catch (Exception e) {
+                    Log.e(this, e, "setUserSelectedOutgoingPhoneAccount");
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+                boolean includeDisabledAccounts, String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "getDefaultOutgoingPhoneAccount")) {
+                return Collections.emptyList();
+            }
+
+            synchronized (mLock) {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    // TODO: Does this isVisible check actually work considering we are clearing
+                    // the calling identity?
+                    return filterForAccountsVisibleToCaller(
+                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
+                                    null, includeDisabledAccounts));
+                } catch (Exception e) {
+                    Log.e(this, e, "getCallCapablePhoneAccounts");
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme,
+                String callingPackage) {
+            synchronized (mLock) {
+                if (!canReadPhoneState(callingPackage, "getPhoneAccountsSupportingScheme")) {
+                    return Collections.emptyList();
+                }
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    // TODO: Does this isVisible check actually work considering we are clearing
+                    // the calling identity?
+                    return filterForAccountsVisibleToCaller(
+                            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(uriScheme, false));
+                } catch (Exception e) {
+                    Log.e(this, e, "getPhoneAccountsSupportingScheme %s", uriScheme);
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
+            synchronized (mLock) {
+                try {
+                    return filterForAccountsVisibleToCaller(
+                            mPhoneAccountRegistrar.getPhoneAccountsForPackage(packageName));
+                } catch (Exception e) {
+                    Log.e(this, e, "getPhoneAccountsForPackage %s", packageName);
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
+            synchronized (mLock) {
+                try {
+                    if (!isVisibleToCaller(accountHandle)) {
+                        Log.d(this, "%s is not visible for the calling user [gPA]", accountHandle);
+                        return null;
+                    }
+                    // TODO: Do we really want to return for *any* user?
+                    return mPhoneAccountRegistrar.getPhoneAccount(accountHandle);
+                } catch (Exception e) {
+                    Log.e(this, e, "getPhoneAccount %s", accountHandle);
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public int getAllPhoneAccountsCount() {
+            synchronized (mLock) {
+                try {
+                    // This list is pre-filtered for the calling user.
+                    return getAllPhoneAccounts().size();
+                } catch (Exception e) {
+                    Log.e(this, e, "getAllPhoneAccountsCount");
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public List<PhoneAccount> getAllPhoneAccounts() {
+            synchronized (mLock) {
+                try {
+                    List<PhoneAccount> allPhoneAccounts = mPhoneAccountRegistrar
+                            .getAllPhoneAccounts();
+                    List<PhoneAccount> profilePhoneAccounts = new ArrayList<>(
+                            allPhoneAccounts.size());
+                    for (PhoneAccount phoneAccount : profilePhoneAccounts) {
+                        if (isVisibleToCaller(phoneAccount)) {
+                            profilePhoneAccounts.add(phoneAccount);
+                        }
+                    }
+                    return profilePhoneAccounts;
+                } catch (Exception e) {
+                    Log.e(this, e, "getAllPhoneAccounts");
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
+            synchronized (mLock) {
+                try {
+                    return filterForAccountsVisibleToCaller(
+                            mPhoneAccountRegistrar.getAllPhoneAccountHandles());
+                } catch (Exception e) {
+                    Log.e(this, e, "getAllPhoneAccounts");
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public PhoneAccountHandle getSimCallManager() {
+            long token  = Binder.clearCallingIdentity();
+            int user;
+            try {
+                user = ActivityManager.getCurrentUser();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return getSimCallManagerForUser(user);
+        }
+
+        @Override
+        public PhoneAccountHandle getSimCallManagerForUser(int user) {
+            synchronized (mLock) {
+                try {
+                    PhoneAccountHandle accountHandle = null;
+
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        accountHandle = mPhoneAccountRegistrar.getSimCallManager(user);
+                    } finally {
+                        // We restore early so that isVisibleToCaller invocation below uses the
+                        // right user context.
+                        Binder.restoreCallingIdentity(token);
+                    }
+
+                    if (!isVisibleToCaller(accountHandle)) {
+                        Log.d(this, "%s is not visible for the calling user [gsCM]", accountHandle);
+                        return null;
+                    }
+                    return accountHandle;
+                } catch (Exception e) {
+                    Log.e(this, e, "getSimCallManager");
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public void registerPhoneAccount(PhoneAccount account) {
+            synchronized (mLock) {
+                if (!mContext.getApplicationContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_voice_capable)) {
+                    Log.w(this, "registerPhoneAccount not allowed on non-voice capable device.");
+                    return;
+                }
+                try {
+                    enforcePhoneAccountModificationForPackage(
+                            account.getAccountHandle().getComponentName().getPackageName());
+                    if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+                        enforceRegisterSimSubscriptionPermission();
+                    }
+                    if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+                        enforceRegisterMultiUser();
+                    }
+                    enforceUserHandleMatchesCaller(account.getAccountHandle());
+
+                    mPhoneAccountRegistrar.registerPhoneAccount(account);
+
+                    // Broadcast an intent indicating the phone account which was registered.
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        Intent intent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED);
+                        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                                account.getAccountHandle());
+                        Log.i(this, "Sending phone-account intent as user");
+                        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                                PERMISSION_PROCESS_PHONE_ACCOUNT_REGISTRATION);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                } catch (Exception e) {
+                    Log.e(this, e, "registerPhoneAccount %s", account);
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
+            synchronized (mLock) {
+                try {
+                    enforcePhoneAccountModificationForPackage(
+                            accountHandle.getComponentName().getPackageName());
+                    enforceUserHandleMatchesCaller(accountHandle);
+                    mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
+                } catch (Exception e) {
+                    Log.e(this, e, "unregisterPhoneAccount %s", accountHandle);
+                    throw e;
+                }
+            }
+        }
+
+        @Override
+        public void clearAccounts(String packageName) {
+            synchronized (mLock) {
+                try {
+                    enforcePhoneAccountModificationForPackage(packageName);
+                    mPhoneAccountRegistrar
+                            .clearAccounts(packageName, Binder.getCallingUserHandle());
+                } catch (Exception e) {
+                    Log.e(this, e, "clearAccounts %s", packageName);
+                    throw e;
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isVoiceMailNumber
+         */
+        @Override
+        public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number,
+                String callingPackage) {
+            synchronized (mLock) {
+                if (!canReadPhoneState(callingPackage, "isVoiceMailNumber")) {
+                    return false;
+                }
+
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.d(this, "%s is not visible for the calling user [iVMN]", accountHandle);
+                    return false;
+                }
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    return mPhoneAccountRegistrar.isVoiceMailNumber(accountHandle, number);
+                } catch (Exception e) {
+                    Log.e(this, e, "getSubscriptionIdForPhoneAccount");
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getVoiceMailNumber
+         */
+        @Override
+        public String getVoiceMailNumber(PhoneAccountHandle accountHandle, String callingPackage) {
+            synchronized (mLock) {
+                if (!canReadPhoneState(callingPackage, "getVoiceMailNumber")) {
+                    return null;
+                }
+
+                try {
+                    if (!isVisibleToCaller(accountHandle)) {
+                        Log.d(this, "%s is not visible for the calling user [gVMN]", accountHandle);
+                        return null;
+                    }
+
+                    int subId = SubscriptionManager.getDefaultVoiceSubId();
+                    if (accountHandle != null) {
+                        subId = mPhoneAccountRegistrar
+                                .getSubscriptionIdForPhoneAccount(accountHandle);
+                    }
+                    return getTelephonyManager().getVoiceMailNumber(subId);
+                } catch (Exception e) {
+                    Log.e(this, e, "getSubscriptionIdForPhoneAccount");
+                    throw e;
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getLine1Number
+         */
+        @Override
+        public String getLine1Number(PhoneAccountHandle accountHandle, String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "getLine1Number")) {
+                return null;
+            }
+
+            synchronized (mLock) {
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.d(this, "%s is not visible for the calling user [gL1N]", accountHandle);
+                    return null;
+                }
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    int subId =
+                            mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle);
+                    return getTelephonyManager().getLine1NumberForSubscriber(subId);
+                } catch (Exception e) {
+                    Log.e(this, e, "getSubscriptionIdForPhoneAccount");
+                    throw e;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#silenceRinger
+         */
+        @Override
+        public void silenceRinger(String callingPackage) {
+            synchronized (mLock) {
+                enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Log.i(this, "Silence Ringer requested by %s", callingPackage);
+                    mCallsManager.getRinger().silence();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getDefaultPhoneApp
+         * @deprecated - Use {@link android.telecom.TelecomManager#getDefaultDialerPackage()}
+         *         instead.
+         */
+        @Override
+        public ComponentName getDefaultPhoneApp() {
+            // No need to synchronize
+            Resources resources = mContext.getResources();
+            return new ComponentName(
+                    resources.getString(R.string.ui_default_package),
+                    resources.getString(R.string.dialer_default_class));
+        }
+
+        /**
+         * @return the package name of the current user-selected default dialer. If no default
+         *         has been selected, the package name of the system dialer is returned. If
+         *         neither exists, then {@code null} is returned.
+         * @see android.telecom.TelecomManager#getDefaultDialerPackage
+         */
+        @Override
+        public String getDefaultDialerPackage() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return DefaultDialerManager.getDefaultDialerApplication(mContext);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getSystemDialerPackage
+         */
+        @Override
+        public String getSystemDialerPackage() {
+            return mContext.getResources().getString(R.string.ui_default_package);
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isInCall
+         */
+        @Override
+        public boolean isInCall(String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "isInCall")) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                final int callState = mCallsManager.getCallState();
+                return callState == TelephonyManager.CALL_STATE_OFFHOOK
+                        || callState == TelephonyManager.CALL_STATE_RINGING;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isRinging
+         */
+        @Override
+        public boolean isRinging(String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "isRinging")) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                return mCallsManager.getCallState() == TelephonyManager.CALL_STATE_RINGING;
+            }
+        }
+
+        /**
+         * @see TelecomManager#getCallState
+         */
+        @Override
+        public int getCallState() {
+            synchronized (mLock) {
+                return mCallsManager.getCallState();
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#endCall
+         */
+        @Override
+        public boolean endCall() {
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    return endCallInternal();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#acceptRingingCall
+         */
+        @Override
+        public void acceptRingingCall() {
+            synchronized (mLock) {
+                enforceModifyPermission();
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    acceptRingingCallInternal();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#showInCallScreen
+         */
+        @Override
+        public void showInCallScreen(boolean showDialpad, String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "showInCallScreen")) {
+                return;
+            }
+
+            synchronized (mLock) {
+
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallsManager.getInCallController().bringToForeground(showDialpad);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#cancelMissedCallsNotification
+         */
+        @Override
+        public void cancelMissedCallsNotification(String callingPackage) {
+            synchronized (mLock) {
+                enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallsManager.getMissedCallNotifier().clearMissedCalls();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#handleMmi
+         */
+        @Override
+        public boolean handlePinMmi(String dialString, String callingPackage) {
+            synchronized (mLock) {
+                enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
+
+                // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+                long token = Binder.clearCallingIdentity();
+                boolean retval = false;
+                try {
+                    retval = getTelephonyManager().handlePinMmi(dialString);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+
+                return retval;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#handleMmi
+         */
+        @Override
+        public boolean handlePinMmiForPhoneAccount(
+                PhoneAccountHandle accountHandle,
+                String dialString,
+                String callingPackage) {
+            synchronized (mLock) {
+                enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
+
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.d(this, "%s is not visible for the calling user [hMMI]", accountHandle);
+                    return false;
+                }
+
+                // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+                long token = Binder.clearCallingIdentity();
+                boolean retval = false;
+                try {
+                    int subId = mPhoneAccountRegistrar
+                            .getSubscriptionIdForPhoneAccount(accountHandle);
+                    retval = getTelephonyManager().handlePinMmiForSubscriber(subId, dialString);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+
+                return retval;
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getAdnUriForPhoneAccount
+         */
+        @Override
+        public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle,
+                String callingPackage) {
+            synchronized (mLock) {
+                enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
+
+                if (!isVisibleToCaller(accountHandle)) {
+                    Log.d(this, "%s is not visible for the calling user [gA4PA]", accountHandle);
+                    return null;
+                }
+
+                // Switch identity so that TelephonyManager checks Telecom's permissions instead.
+                long token = Binder.clearCallingIdentity();
+                String retval = "content://icc/adn/";
+                try {
+                    long subId = mPhoneAccountRegistrar
+                            .getSubscriptionIdForPhoneAccount(accountHandle);
+                    retval = retval + "subId/" + subId;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+
+                return Uri.parse(retval);
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#isTtySupported
+         */
+        @Override
+        public boolean isTtySupported(String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "hasVoiceMailNumber")) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                return mCallsManager.isTtySupported();
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#getCurrentTtyMode
+         */
+        @Override
+        public int getCurrentTtyMode(String callingPackage) {
+            if (!canReadPhoneState(callingPackage, "getCurrentTtyMode")) {
+                return TelecomManager.TTY_MODE_OFF;
+            }
+
+            synchronized (mLock) {
+                return mCallsManager.getCurrentTtyMode();
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#addNewIncomingCall
+         */
+        @Override
+        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
+            synchronized (mLock) {
+                Log.i(this, "Adding new incoming call with phoneAccountHandle %s",
+                        phoneAccountHandle);
+                if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
+                    // TODO(sail): Add unit tests for adding incoming calls from a SIM call manager.
+                    if (isCallerSimCallManager() && TelephonyUtil.isPstnComponentName(
+                            phoneAccountHandle.getComponentName())) {
+                        Log.v(this, "Allowing call manager to add incoming call with PSTN handle");
+                    } else {
+                        mAppOpsManager.checkPackage(
+                                Binder.getCallingUid(),
+                                phoneAccountHandle.getComponentName().getPackageName());
+                        // Make sure it doesn't cross the UserHandle boundary
+                        enforceUserHandleMatchesCaller(phoneAccountHandle);
+                        enforcePhoneAccountIsRegisteredEnabled(phoneAccountHandle);
+                    }
+
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
+                        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                            phoneAccountHandle);
+                        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
+                        if (extras != null) {
+                            intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
+                        }
+                        CallIntentProcessor.processIncomingCallIntent(mCallsManager, intent);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                } else {
+                    Log.w(this,
+                            "Null phoneAccountHandle. Ignoring request to add new incoming call");
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#addNewUnknownCall
+         */
+        @Override
+        public void addNewUnknownCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
+            synchronized (mLock) {
+                if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
+                    mAppOpsManager.checkPackage(
+                            Binder.getCallingUid(),
+                            phoneAccountHandle.getComponentName().getPackageName());
+
+                    // Make sure it doesn't cross the UserHandle boundary
+                    enforceUserHandleMatchesCaller(phoneAccountHandle);
+                    enforcePhoneAccountIsRegisteredEnabled(phoneAccountHandle);
+                    long token = Binder.clearCallingIdentity();
+
+                    try {
+                        Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
+                        intent.putExtras(extras);
+                        intent.putExtra(CallIntentProcessor.KEY_IS_UNKNOWN_CALL, true);
+                        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                            phoneAccountHandle);
+                        CallIntentProcessor.processUnknownCallIntent(mCallsManager, intent);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                } else {
+                    Log.i(this,
+                            "Null phoneAccountHandle or not initiated by Telephony. " +
+                            "Ignoring request to add new unknown call.");
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#placeCall
+         */
+        @Override
+        public void placeCall(Uri handle, Bundle extras, String callingPackage) {
+            enforceCallingPackage(callingPackage);
+            if (!canCallPhone(callingPackage, "placeCall")) {
+                throw new SecurityException("Package " + callingPackage
+                        + " is not allowed to place phone calls");
+            }
+
+            // Note: we can still get here for the default/system dialer, even if the Phone
+            // permission is turned off. This is because the default/system dialer is always
+            // allowed to attempt to place a call (regardless of permission state), in case
+            // it turns out to be an emergency call. If the permission is denied and the
+            // call is being made to a non-emergency number, the call will be denied later on
+            // by {@link UserCallIntentProcessor}.
+
+            final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
+                    Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+
+            final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
+                    PackageManager.PERMISSION_GRANTED;
+
+            synchronized (mLock) {
+                final UserHandle userHandle = Binder.getCallingUserHandle();
+                long token = Binder.clearCallingIdentity();
+                try {
+                    final Intent intent = new Intent(Intent.ACTION_CALL, handle);
+                    intent.putExtras(extras);
+                    new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,
+                            callingPackage, hasCallAppOp && hasCallPermission);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * @see android.telecom.TelecomManager#enablePhoneAccount
+         */
+        @Override
+        public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
+            enforceModifyPermission();
+            synchronized (mLock) {
+                long token  = Binder.clearCallingIdentity();
+                try {
+                    // enable/disable phone account
+                    return mPhoneAccountRegistrar.enablePhoneAccount(accountHandle, isEnabled);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        @Override
+        public boolean setDefaultDialer(String packageName) {
+            enforcePermission(MODIFY_PHONE_STATE);
+            enforcePermission(WRITE_SECURE_SETTINGS);
+            synchronized (mLock) {
+                long token  = Binder.clearCallingIdentity();
+                try {
+                    final boolean result =
+                            DefaultDialerManager.setDefaultDialerApplication(mContext, packageName);
+                    if (result) {
+                        final Intent intent =
+                                new Intent(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
+                        intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
+                                packageName);
+                        mContext.sendBroadcastAsUser(intent,
+                                new UserHandle(ActivityManager.getCurrentUser()));
+                    }
+                    return result;
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+
+        /**
+         * Dumps the current state of the TelecomService.  Used when generating problem reports.
+         *
+         * @param fd The file descriptor.
+         * @param writer The print writer to dump the state to.
+         * @param args Optional dump arguments.
+         */
+        @Override
+        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                writer.println("Permission Denial: can't dump TelecomService " +
+                        "from from pid=" + Binder.getCallingPid() + ", uid=" +
+                        Binder.getCallingUid());
+                return;
+            }
+
+            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+            if (mCallsManager != null) {
+                pw.println("CallsManager: ");
+                pw.increaseIndent();
+                mCallsManager.dump(pw);
+                pw.decreaseIndent();
+
+                pw.println("PhoneAccountRegistrar: ");
+                pw.increaseIndent();
+                mPhoneAccountRegistrar.dump(pw);
+                pw.decreaseIndent();
+            }
+
+            Log.dumpCallEvents(pw);
+        }
+    };
+
+    private Context mContext;
+    private AppOpsManager mAppOpsManager;
+    private UserManager mUserManager;
+    private PackageManager mPackageManager;
+    private CallsManager mCallsManager;
+    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
+    private final TelecomSystem.SyncRoot mLock;
+
+    public TelecomServiceImpl(
+            Context context,
+            CallsManager callsManager,
+            PhoneAccountRegistrar phoneAccountRegistrar,
+            TelecomSystem.SyncRoot lock) {
+        mContext = context;
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+
+        mCallsManager = callsManager;
+        mLock = lock;
+        mPhoneAccountRegistrar = phoneAccountRegistrar;
+    }
+
+    public ITelecomService.Stub getBinder() {
+        return mBinderImpl;
+    }
+
+    //
+    // Supporting methods for the ITelecomService interface implementation.
+    //
+
+    private boolean isVisibleToCaller(PhoneAccountHandle accountHandle) {
+        if (accountHandle == null) {
+            return false;
+        }
+        return isVisibleToCaller(mPhoneAccountRegistrar.getPhoneAccount(accountHandle));
+    }
+
+    private boolean isVisibleToCaller(PhoneAccount account) {
+        if (account == null) {
+            return false;
+        }
+
+        // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
+        // all profiles. Only Telephony and SIP accounts should have this capability.
+        if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
+            return true;
+        }
+
+        UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
+        if (phoneAccountUserHandle == null) {
+            return false;
+        }
+
+        if (phoneAccountUserHandle.equals(Binder.getCallingUserHandle())) {
+            return true;
+        }
+
+        List<UserHandle> profileUserHandles;
+        if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
+            profileUserHandles = mUserManager.getUserProfiles();
+        } else {
+            // Otherwise, it has to be owned by the current caller's profile.
+            profileUserHandles = new ArrayList<>(1);
+            profileUserHandles.add(Binder.getCallingUserHandle());
+        }
+
+        return profileUserHandles.contains(phoneAccountUserHandle);
+    }
+
+    /**
+     * Given a list of {@link PhoneAccountHandle}s, filter them to the ones that the calling
+     * user can see.
+     *
+     * @param phoneAccountHandles Unfiltered list of account handles.
+     *
+     * @return {@link PhoneAccountHandle}s visible to the calling user and its profiles.
+     */
+    private List<PhoneAccountHandle> filterForAccountsVisibleToCaller(
+            List<PhoneAccountHandle> phoneAccountHandles) {
+        List<PhoneAccountHandle> profilePhoneAccountHandles =
+                new ArrayList<>(phoneAccountHandles.size());
+        for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
+            if (isVisibleToCaller(phoneAccountHandle)) {
+                profilePhoneAccountHandles.add(phoneAccountHandle);
+            }
+        }
+        return profilePhoneAccountHandles;
+    }
+
+    private boolean isCallerSystemApp() {
+        int uid = Binder.getCallingUid();
+        String[] packages = mPackageManager.getPackagesForUid(uid);
+        for (String packageName : packages) {
+            if (isPackageSystemApp(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isPackageSystemApp(String packageName) {
+        try {
+            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName,
+                    PackageManager.GET_META_DATA);
+            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                return true;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        return false;
+    }
+
+    private void acceptRingingCallInternal() {
+        Call call = mCallsManager.getFirstCallWithState(CallState.RINGING);
+        if (call != null) {
+            call.answer(call.getVideoState());
+        }
+    }
+
+    private boolean endCallInternal() {
+        // Always operate on the foreground call if one exists, otherwise get the first call in
+        // priority order by call-state.
+        Call call = mCallsManager.getForegroundCall();
+        if (call == null) {
+            call = mCallsManager.getFirstCallWithState(
+                    CallState.ACTIVE,
+                    CallState.DIALING,
+                    CallState.RINGING,
+                    CallState.ON_HOLD);
+        }
+
+        if (call != null) {
+            if (call.getState() == CallState.RINGING) {
+                call.reject(false /* rejectWithMessage */, null);
+            } else {
+                call.disconnect();
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    // Enforce that the PhoneAccountHandle being passed in is both registered to the current user
+    // and enabled.
+    private void enforcePhoneAccountIsRegisteredEnabled(PhoneAccountHandle phoneAccountHandle) {
+        PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountCheckCallingUser(
+                phoneAccountHandle);
+        if (phoneAccount == null) {
+            EventLog.writeEvent(0x534e4554, "26864502", Binder.getCallingUid(), "R");
+            throw new SecurityException("This PhoneAccountHandle is not registered for this user!");
+        }
+        if (!phoneAccount.isEnabled()) {
+            EventLog.writeEvent(0x534e4554, "26864502", Binder.getCallingUid(), "E");
+            throw new SecurityException("This PhoneAccountHandle is not enabled for this user!");
+        }
+    }
+
+    private void enforcePhoneAccountModificationForPackage(String packageName) {
+        // TODO: Use a new telecomm permission for this instead of reusing modify.
+
+        int result = mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
+
+        // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
+        // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
+        // may also modify PhoneAccounts on behalf of any 'packageName'.
+
+        if (result != PackageManager.PERMISSION_GRANTED) {
+            // Other callers are only allowed to modify PhoneAccounts if the relevant system
+            // feature is enabled ...
+            enforceConnectionServiceFeature();
+            // ... and the PhoneAccounts they refer to are for their own package.
+            enforceCallingPackage(packageName);
+        }
+    }
+
+    private void enforcePermissionOrPrivilegedDialer(String permission, String packageName) {
+        if (!isPrivilegedDialerCalling(packageName)) {
+            try {
+                enforcePermission(permission);
+            } catch (SecurityException e) {
+                Log.e(this, e, "Caller must be the default or system dialer, or have the permission"
+                        + " %s to perform this operation.", permission);
+                throw e;
+            }
+        }
+    }
+
+    private void enforceCallingPackage(String packageName) {
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+    }
+
+    private void enforceConnectionServiceFeature() {
+        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
+    }
+
+    private void enforceRegisterSimSubscriptionPermission() {
+        enforcePermission(REGISTER_SIM_SUBSCRIPTION);
+    }
+
+    private void enforceModifyPermission() {
+        enforcePermission(MODIFY_PHONE_STATE);
+    }
+
+    private void enforcePermission(String permission) {
+        mContext.enforceCallingOrSelfPermission(permission, null);
+    }
+
+    private void enforceRegisterMultiUser() {
+        if (!isCallerSystemApp()) {
+            throw new SecurityException("CAPABILITY_MULTI_USER is only available to system apps.");
+        }
+    }
+
+    private void enforceUserHandleMatchesCaller(PhoneAccountHandle accountHandle) {
+        if (!Binder.getCallingUserHandle().equals(accountHandle.getUserHandle())) {
+            throw new SecurityException("Calling UserHandle does not match PhoneAccountHandle's");
+        }
+    }
+
+    private void enforceFeature(String feature) {
+        PackageManager pm = mContext.getPackageManager();
+        if (!pm.hasSystemFeature(feature)) {
+            throw new UnsupportedOperationException(
+                    "System does not support feature " + feature);
+        }
+    }
+
+    private boolean canReadPhoneState(String callingPackage, String message) {
+        // The system/default dialer can always read phone state - so that emergency calls will
+        // still work.
+        if (isPrivilegedDialerCalling(callingPackage)) {
+            return true;
+        }
+
+        try {
+            mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
+            // SKIP checking run-time OP_READ_PHONE_STATE since caller or self has PRIVILEGED
+            // permission
+            return true;
+        } catch (SecurityException e) {
+            // Accessing phone state is gated by a special permission.
+            mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, message);
+
+            // Some apps that have the permission can be restricted via app ops.
+            return mAppOpsManager.noteOp(AppOpsManager.OP_READ_PHONE_STATE,
+                    Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+        }
+    }
+
+    private boolean canCallPhone(String callingPackage, String message) {
+        // The system/default dialer can always read phone state - so that emergency calls will
+        // still work.
+        if (isPrivilegedDialerCalling(callingPackage)) {
+            return true;
+        }
+
+        // Accessing phone state is gated by a special permission.
+        mContext.enforceCallingOrSelfPermission(CALL_PHONE, message);
+
+        // Some apps that have the permission can be restricted via app ops.
+        return mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
+                Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    private boolean isCallerSimCallManager() {
+        PhoneAccountHandle accountHandle = null;
+        long token = Binder.clearCallingIdentity();
+        try {
+            accountHandle = mPhoneAccountRegistrar.getSimCallManager();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        if (accountHandle != null) {
+            try {
+                mAppOpsManager.checkPackage(
+                        Binder.getCallingUid(), accountHandle.getComponentName().getPackageName());
+                return true;
+            } catch (SecurityException e) {
+            }
+        }
+        return false;
+    }
+
+    private boolean isPrivilegedDialerCalling(String callingPackage) {
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
+        return DefaultDialerManager.isDefaultOrSystemDialer(mContext, callingPackage);
+    }
+
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
new file mode 100644
index 0000000..c3ab0dc
--- /dev/null
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+
+/**
+ * Top-level Application class for Telecom.
+ */
+public final class TelecomSystem {
+
+    /**
+     * This interface is implemented by system-instantiated components (e.g., Services and
+     * Activity-s) that wish to use the TelecomSystem but would like to be testable. Such a
+     * component should implement the getTelecomSystem() method to return the global singleton,
+     * and use its own method. Tests can subclass the component to return a non-singleton.
+     *
+     * A refactoring goal for Telecom is to limit use of the TelecomSystem singleton to those
+     * system-instantiated components, and have all other parts of the system just take all their
+     * dependencies as explicit arguments to their constructor or other methods.
+     */
+    public interface Component {
+        TelecomSystem getTelecomSystem();
+    }
+
+
+    /**
+     * Tagging interface for the object used for synchronizing multi-threaded operations in
+     * the Telecom system.
+     */
+    public interface SyncRoot {
+    }
+
+    private static final IntentFilter USER_SWITCHED_FILTER =
+            new IntentFilter(Intent.ACTION_USER_SWITCHED);
+
+    private static TelecomSystem INSTANCE = null;
+
+    private final SyncRoot mLock = new SyncRoot() { };
+    private final MissedCallNotifier mMissedCallNotifier;
+    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
+    private final CallsManager mCallsManager;
+    private final RespondViaSmsManager mRespondViaSmsManager;
+    private final Context mContext;
+    private final BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
+    private final CallIntentProcessor mCallIntentProcessor;
+    private final TelecomBroadcastIntentProcessor mTelecomBroadcastIntentProcessor;
+    private final TelecomServiceImpl mTelecomServiceImpl;
+    private final ContactsAsyncHelper mContactsAsyncHelper;
+
+    private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+            UserHandle currentUserHandle = new UserHandle(userHandleId);
+            mPhoneAccountRegistrar.setCurrentUserHandle(currentUserHandle);
+        }
+    };
+
+    public static TelecomSystem getInstance() {
+        return INSTANCE;
+    }
+
+    public static void setInstance(TelecomSystem instance) {
+        if (INSTANCE != null) {
+            throw new RuntimeException("Attempt to set TelecomSystem.INSTANCE twice");
+        }
+        Log.i(TelecomSystem.class, "TelecomSystem.INSTANCE being set");
+        INSTANCE = instance;
+    }
+
+    public TelecomSystem(
+            Context context,
+            MissedCallNotifier missedCallNotifier,
+            CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory,
+            HeadsetMediaButtonFactory headsetMediaButtonFactory,
+            ProximitySensorManagerFactory proximitySensorManagerFactory,
+            InCallWakeLockControllerFactory inCallWakeLockControllerFactory) {
+        mContext = context.getApplicationContext();
+
+        mMissedCallNotifier = missedCallNotifier;
+        mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);
+        mContactsAsyncHelper = new ContactsAsyncHelper(mLock);
+
+        mCallsManager = new CallsManager(
+                mContext,
+                mLock,
+                mContactsAsyncHelper,
+                callerInfoAsyncQueryFactory,
+                mMissedCallNotifier,
+                mPhoneAccountRegistrar,
+                headsetMediaButtonFactory,
+                proximitySensorManagerFactory,
+                inCallWakeLockControllerFactory);
+
+        mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
+        mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
+
+        mContext.registerReceiver(mUserSwitchedReceiver, USER_SWITCHED_FILTER);
+        mBluetoothPhoneServiceImpl = new BluetoothPhoneServiceImpl(
+                mContext, mLock, mCallsManager, mPhoneAccountRegistrar);
+        mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);
+        mTelecomBroadcastIntentProcessor = new TelecomBroadcastIntentProcessor(
+                mContext, mCallsManager);
+        mTelecomServiceImpl = new TelecomServiceImpl(
+                mContext, mCallsManager, mPhoneAccountRegistrar, mLock);
+    }
+
+    @VisibleForTesting
+    public PhoneAccountRegistrar getPhoneAccountRegistrar() {
+        return mPhoneAccountRegistrar;
+    }
+
+    public BluetoothPhoneServiceImpl getBluetoothPhoneServiceImpl() {
+        return mBluetoothPhoneServiceImpl;
+    }
+
+    public CallIntentProcessor getCallIntentProcessor() {
+        return mCallIntentProcessor;
+    }
+
+    public TelecomBroadcastIntentProcessor getTelecomBroadcastIntentProcessor() {
+        return mTelecomBroadcastIntentProcessor;
+    }
+
+    public TelecomServiceImpl getTelecomServiceImpl() {
+        return mTelecomServiceImpl;
+    }
+
+    public Object getLock() {
+        return mLock;
+    }
+}
diff --git a/src/com/android/server/telecom/TelephonyUtil.java b/src/com/android/server/telecom/TelephonyUtil.java
index a130522..5f43ee9 100644
--- a/src/com/android/server/telecom/TelephonyUtil.java
+++ b/src/com/android/server/telecom/TelephonyUtil.java
@@ -28,8 +28,6 @@
  * differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
  */
 public final class TelephonyUtil {
-    private static final String TAG = TelephonyUtil.class.getSimpleName();
-
     private static final String TELEPHONY_PACKAGE_NAME = "com.android.phone";
 
     private static final String PSTN_CALL_SERVICE_CLASS_NAME =
@@ -51,7 +49,9 @@
         return PhoneAccount.builder(DEFAULT_EMERGENCY_PHONE_ACCOUNT_HANDLE, "E")
                 .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
                         PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS).build();
+                        PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
+                .setIsEnabled(true)
+                .build();
     }
 
     static boolean isPstnComponentName(ComponentName componentName) {
@@ -60,8 +60,8 @@
         return pstnComponentName.equals(componentName);
     }
 
-    static boolean shouldProcessAsEmergency(Context context, Uri handle) {
-        return handle != null && PhoneNumberUtils.isPotentialLocalEmergencyNumber(
+    public static boolean shouldProcessAsEmergency(Context context, Uri handle) {
+        return handle != null && PhoneNumberUtils.isLocalEmergencyNumber(
                 context, handle.getSchemeSpecificPart());
     }
 }
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index b5cf39a..f047971 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -60,7 +60,7 @@
      * in-call UI.
      */
     public static long getNewOutgoingCallCancelMillis(ContentResolver contentResolver) {
-        return get(contentResolver, "new_outgoing_call_cancel_ms", 300L);
+        return get(contentResolver, "new_outgoing_call_cancel_ms", 400L);
     }
 
     /**
@@ -89,4 +89,13 @@
         return get(contentResolver, "emergency_call_timeout_radio_off_millis",
                 60000L /* 1 minute */);
     }
+
+    /**
+     * Returns the amount of delay before unbinding the in-call services after all the calls
+     * are removed.
+     */
+    public static long getCallRemoveUnbindInCallServicesDelay(ContentResolver contentResolver) {
+        return get(contentResolver, "call_remove_unbind_in_call_services_delay",
+                2000L /* 2 seconds */);
+    }
 }
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
new file mode 100644
index 0000000..7dcfdfb
--- /dev/null
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom;
+
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.telecom.Connection;
+import android.telecom.InCallService;
+import android.telecom.VideoProfile;
+import android.view.Surface;
+
+import com.android.internal.telecom.IVideoCallback;
+import com.android.internal.telecom.IVideoProvider;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Proxies video provider messages from {@link InCallService.VideoCall}
+ * implementations to the underlying {@link Connection.VideoProvider} implementation.  Also proxies
+ * callbacks from the {@link Connection.VideoProvider} to {@link InCallService.VideoCall}
+ * implementations.
+ *
+ * Also provides a means for Telecom to send and receive these messages.
+ */
+public class VideoProviderProxy extends Connection.VideoProvider {
+
+    /**
+     * Listener for Telecom components interested in callbacks from the video provider.
+     */
+    interface Listener {
+        void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
+    }
+
+    /**
+     * Set of listeners on this VideoProviderProxy.
+     *
+     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+     * load factor before resizing, 1 means we only expect a single thread to
+     * access the map so make only a single shard
+     */
+    private final Set<Listener> mListeners = Collections.newSetFromMap(
+            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
+
+    /** The TelecomSystem SyncRoot used for synchronized operations. */
+    private final TelecomSystem.SyncRoot mLock;
+
+    /**
+     * The {@link android.telecom.Connection.VideoProvider} implementation residing with the
+     * {@link android.telecom.ConnectionService} which is being wrapped by this
+     * {@link VideoProviderProxy}.
+     */
+    private final IVideoProvider mConectionServiceVideoProvider;
+
+    /**
+     * Binder used to bind to the {@link android.telecom.ConnectionService}'s
+     * {@link com.android.internal.telecom.IVideoCallback}.
+     */
+    private final VideoCallListenerBinder mVideoCallListenerBinder;
+
+    /**
+     * The Telecom {@link Call} this {@link VideoProviderProxy} is associated with.
+     */
+    private Call mCall;
+
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            mConectionServiceVideoProvider.asBinder().unlinkToDeath(this, 0);
+        }
+    };
+
+    /**
+     * Creates a new instance of the {@link VideoProviderProxy}, binding it to the passed in
+     * {@code videoProvider} residing with the {@link android.telecom.ConnectionService}.
+     *
+     *
+     * @param lock
+     * @param videoProvider The {@link android.telecom.ConnectionService}'s video provider.
+     * @param call The current call.
+     * @throws RemoteException Remote exception.
+     */
+    VideoProviderProxy(TelecomSystem.SyncRoot lock,
+            IVideoProvider videoProvider, Call call) throws RemoteException {
+
+        super(Looper.getMainLooper());
+
+        mLock = lock;
+
+        mConectionServiceVideoProvider = videoProvider;
+        mConectionServiceVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
+
+        mVideoCallListenerBinder = new VideoCallListenerBinder();
+        mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder);
+        mCall = call;
+    }
+
+    /**
+     * IVideoCallback stub implementation.  An instance of this class receives callbacks from the
+     * {@code ConnectionService}'s video provider.
+     */
+    private final class VideoCallListenerBinder extends IVideoCallback.Stub {
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when a session modification request is received.
+         *
+         * @param videoProfile The requested video profile.
+         */
+        @Override
+        public void receiveSessionModifyRequest(VideoProfile videoProfile) {
+            synchronized (mLock) {
+                logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile);
+
+                // Inform other Telecom components of the session modification request.
+                for (Listener listener : mListeners) {
+                    listener.onSessionModifyRequestReceived(mCall, videoProfile);
+                }
+
+                VideoProviderProxy.this.receiveSessionModifyRequest(videoProfile);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when a session modification response is received.
+         *
+         * @param status The status of the response.
+         * @param requestProfile The requested video profile.
+         * @param responseProfile The response video profile.
+         */
+        @Override
+        public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
+                VideoProfile responseProfile) {
+            synchronized (mLock) {
+                logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
+                        " requestProfile=" + requestProfile + " responseProfile=" +
+                        responseProfile);
+                VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile,
+                        responseProfile);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when a call session event occurs.
+         *
+         * @param event The call session event.
+         */
+        @Override
+        public void handleCallSessionEvent(int event) {
+            synchronized (mLock) {
+                logFromVideoProvider("handleCallSessionEvent: " + event);
+                VideoProviderProxy.this.handleCallSessionEvent(event);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when the peer dimensions change.
+         *
+         * @param width The width of the peer's video.
+         * @param height The height of the peer's video.
+         */
+        @Override
+        public void changePeerDimensions(int width, int height) {
+            synchronized (mLock) {
+                logFromVideoProvider("changePeerDimensions: width=" + width + " height=" +
+                        height);
+                VideoProviderProxy.this.changePeerDimensions(width, height);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when the video quality changes.
+         *
+         * @param videoQuality The video quality.
+         */
+        @Override
+        public void changeVideoQuality(int videoQuality) {
+            synchronized (mLock) {
+                logFromVideoProvider("changeVideoQuality: " + videoQuality);
+                VideoProviderProxy.this.changeVideoQuality(videoQuality);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when the call data usage changes.
+         *
+         * @param dataUsage The data usage.
+         */
+        @Override
+        public void changeCallDataUsage(long dataUsage) {
+            synchronized (mLock) {
+                logFromVideoProvider("changeCallDataUsage: " + dataUsage);
+                VideoProviderProxy.this.setCallDataUsage(dataUsage);
+            }
+        }
+
+        /**
+         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
+         * {@link InCallService} when the camera capabilities change.
+         *
+         * @param cameraCapabilities The camera capabilities.
+         */
+        @Override
+        public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
+            synchronized (mLock) {
+                logFromVideoProvider("changeCameraCapabilities: " + cameraCapabilities);
+                VideoProviderProxy.this.changeCameraCapabilities(cameraCapabilities);
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to change the camera.
+     *
+     * @param cameraId The id of the camera.
+     */
+    @Override
+    public void onSetCamera(String cameraId) {
+        synchronized (mLock) {
+            logFromInCall("setCamera: " + cameraId);
+            try {
+                mConectionServiceVideoProvider.setCamera(cameraId);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to set the preview surface.
+     *
+     * @param surface The surface.
+     */
+    @Override
+    public void onSetPreviewSurface(Surface surface) {
+        synchronized (mLock) {
+            logFromInCall("setPreviewSurface");
+            try {
+                mConectionServiceVideoProvider.setPreviewSurface(surface);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to change the display surface.
+     *
+     * @param surface The surface.
+     */
+    @Override
+    public void onSetDisplaySurface(Surface surface) {
+        synchronized (mLock) {
+            logFromInCall("setDisplaySurface");
+            try {
+                mConectionServiceVideoProvider.setDisplaySurface(surface);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to change the device orientation.
+     *
+     * @param rotation The device orientation, in degrees.
+     */
+    @Override
+    public void onSetDeviceOrientation(int rotation) {
+        synchronized (mLock) {
+            logFromInCall("setDeviceOrientation: " + rotation);
+            try {
+                mConectionServiceVideoProvider.setDeviceOrientation(rotation);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to change the camera zoom ratio.
+     *
+     * @param value The camera zoom ratio.
+     */
+    @Override
+    public void onSetZoom(float value) {
+        synchronized (mLock) {
+            logFromInCall("setZoom: " + value);
+            try {
+                mConectionServiceVideoProvider.setZoom(value);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to provide a response to a session modification
+     * request.
+     *
+     * @param fromProfile The video properties prior to the request.
+     * @param toProfile The video properties with the requested changes made.
+     */
+    @Override
+    public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+        synchronized (mLock) {
+            logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
+            try {
+                mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to send a session modification request.
+     *
+     * @param responseProfile The response connection video properties.
+     */
+    @Override
+    public void onSendSessionModifyResponse(VideoProfile responseProfile) {
+        synchronized (mLock) {
+            logFromInCall("sendSessionModifyResponse: " + responseProfile);
+            try {
+                mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to request the camera capabilities.
+     */
+    @Override
+    public void onRequestCameraCapabilities() {
+        synchronized (mLock) {
+            logFromInCall("requestCameraCapabilities");
+            try {
+                mConectionServiceVideoProvider.requestCameraCapabilities();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to request the connection data usage.
+     */
+    @Override
+    public void onRequestConnectionDataUsage() {
+        synchronized (mLock) {
+            logFromInCall("requestCallDataUsage");
+            try {
+                mConectionServiceVideoProvider.requestCallDataUsage();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Proxies a request from the {@link InCallService} to the
+     * {@link #mConectionServiceVideoProvider} to set the pause image.
+     *
+     * @param uri URI of image to display.
+     */
+    @Override
+    public void onSetPauseImage(Uri uri) {
+        synchronized (mLock) {
+            logFromInCall("setPauseImage: " + uri);
+            try {
+                mConectionServiceVideoProvider.setPauseImage(uri);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
+     * Add a listener to this {@link VideoProviderProxy}.
+     *
+     * @param listener The listener.
+     */
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Remove a listener from this {@link VideoProviderProxy}.
+     *
+     * @param listener The listener.
+     */
+    public void removeListener(Listener listener) {
+        if (listener != null) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Logs a message originating from the {@link InCallService}.
+     *
+     * @param toLog The message to log.
+     */
+    private void logFromInCall(String toLog) {
+        Log.v(this, "IC->VP: " + toLog);
+    }
+
+    /**
+     * Logs a message originating from the {@link android.telecom.ConnectionService}'s
+     * {@link Connection.VideoProvider}.
+     *
+     * @param toLog The message to log.
+     */
+    private void logFromVideoProvider(String toLog) {
+        Log.v(this, "VP->IC: " + toLog);
+    }
+}
diff --git a/src/com/android/server/telecom/components/BluetoothPhoneService.java b/src/com/android/server/telecom/components/BluetoothPhoneService.java
new file mode 100644
index 0000000..c5e195c
--- /dev/null
+++ b/src/com/android/server/telecom/components/BluetoothPhoneService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 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.components;
+
+import com.android.server.telecom.TelecomSystem;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Bluetooth headset manager for Telecom. This class shares the call state with the bluetooth device
+ * and accepts call-related commands to perform on behalf of the BT device.
+ */
+public final class BluetoothPhoneService extends Service implements TelecomSystem.Component {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        synchronized (getTelecomSystem().getLock()) {
+            return getTelecomSystem().getBluetoothPhoneServiceImpl().getBinder();
+        }
+    }
+
+    @Override
+    public TelecomSystem getTelecomSystem() {
+        return TelecomSystem.getInstance();
+    }
+}
diff --git a/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java b/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java
new file mode 100644
index 0000000..5fd7904
--- /dev/null
+++ b/src/com/android/server/telecom/components/ChangeDefaultDialerDialog.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.components;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.telecom.DefaultDialerManager;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.server.telecom.R;
+
+/**
+ * Activity that shows a dialog for the user to confirm whether or not the default dialer should
+ * be changed.
+ *
+ * This dialog can be skipped directly for CTS tests using the adb command:
+ * adb shell am start -a android.telecom.action.CHANGE_DEFAULT_DIALER_PRIVILEGED -e android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME <packageName>
+ */
+public class ChangeDefaultDialerDialog extends AlertActivity implements
+        DialogInterface.OnClickListener{
+    private static final String TAG = ChangeDefaultDialerDialog.class.getSimpleName();
+    private String mNewPackage;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final String oldPackage = DefaultDialerManager.getDefaultDialerApplication(this);
+        mNewPackage = getIntent().getStringExtra(
+                TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
+        if (!canChangeToProvidedPackage(oldPackage, mNewPackage)) {
+            setResult(RESULT_CANCELED);
+            finish();
+        }
+
+        // Show dialog to require user confirmation.
+         buildDialog(oldPackage, mNewPackage);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case BUTTON_POSITIVE:
+                TelecomManager.from(this).setDefaultDialer(mNewPackage);
+                setResult(RESULT_OK);
+                break;
+            case BUTTON_NEGATIVE:
+                setResult(RESULT_CANCELED);
+                break;
+        }
+    }
+
+    private boolean canChangeToProvidedPackage(String oldPackage, String newPackage) {
+        final TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
+        if (!tm.isVoiceCapable()) {
+            Log.w(TAG, "Dialog launched but device is not voice capable.");
+            return false;
+        }
+
+        if (!DefaultDialerManager.getInstalledDialerApplications(this).contains(newPackage)) {
+            Log.w(TAG, "Provided package name does not correspond to an installed Dialer "
+                    + "application.");
+            return false;
+        }
+
+        if (!TextUtils.isEmpty(oldPackage) && TextUtils.equals(oldPackage, newPackage)) {
+            Log.w(TAG, "Provided package name is already the current default Dialer application.");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean buildDialog(String oldPackage, String newPackage) {
+        final PackageManager pm = getPackageManager();
+        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.mPositiveButtonListener = this;
+        p.mNegativeButtonListener = this;
+        setupAlert();
+
+        return true;
+    }
+
+    /**
+     * Returns the application label that corresponds to the given package name
+     *
+     * @param pm An instance of a {@link PackageManager}.
+     * @param packageName A valid package name.
+     *
+     * @return Application label for the given package name, or null if not found.
+     */
+    private String getApplicationLabelForPackageName(PackageManager pm, String packageName) {
+        ApplicationInfo info = null;
+        try {
+            info = pm.getApplicationInfo(packageName, 0);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Application info not found for packageName " + packageName);
+        }
+        if (info == null) {
+            return packageName;
+        } else {
+            return info.loadLabel(pm).toString();
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/ErrorDialogActivity.java b/src/com/android/server/telecom/components/ErrorDialogActivity.java
similarity index 97%
rename from src/com/android/server/telecom/ErrorDialogActivity.java
rename to src/com/android/server/telecom/components/ErrorDialogActivity.java
index a669f10..858682e 100644
--- a/src/com/android/server/telecom/ErrorDialogActivity.java
+++ b/src/com/android/server/telecom/components/ErrorDialogActivity.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server.telecom;
+package com.android.server.telecom.components;
+
+import com.android.server.telecom.Log;
+import com.android.server.telecom.R;
 
 import android.app.Activity;
 import android.app.AlertDialog;
diff --git a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java b/src/com/android/server/telecom/components/PhoneAccountBroadcastReceiver.java
similarity index 96%
rename from src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
rename to src/com/android/server/telecom/components/PhoneAccountBroadcastReceiver.java
index 9634eda..7737cd8 100644
--- a/src/com/android/server/telecom/PhoneAccountBroadcastReceiver.java
+++ b/src/com/android/server/telecom/components/PhoneAccountBroadcastReceiver.java
@@ -14,7 +14,9 @@
  * limitations under the License
  */
 
-package com.android.server.telecom;
+package com.android.server.telecom.components;
+
+import com.android.server.telecom.PhoneAccountRegistrar;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/src/com/android/server/telecom/components/PrimaryCallReceiver.java b/src/com/android/server/telecom/components/PrimaryCallReceiver.java
new file mode 100644
index 0000000..5198862
--- /dev/null
+++ b/src/com/android/server/telecom/components/PrimaryCallReceiver.java
@@ -0,0 +1,28 @@
+package com.android.server.telecom.components;
+
+import com.android.server.telecom.TelecomSystem;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Single point of entry for all outgoing and incoming calls. {@link UserCallIntentProcessor} serves
+ * as a trampoline that captures call intents for individual users and forwards it to
+ * the {@link PrimaryCallReceiver} which interacts with the rest of Telecom, both of which run only as
+ * the primary user.
+ */
+public class PrimaryCallReceiver extends BroadcastReceiver implements TelecomSystem.Component {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        synchronized (getTelecomSystem().getLock()) {
+            getTelecomSystem().getCallIntentProcessor().processIntent(intent);
+        }
+    }
+
+    @Override
+    public TelecomSystem getTelecomSystem() {
+        return TelecomSystem.getInstance();
+    }
+}
diff --git a/src/com/android/server/telecom/components/TelecomBroadcastReceiver.java b/src/com/android/server/telecom/components/TelecomBroadcastReceiver.java
new file mode 100644
index 0000000..e0ca3c4
--- /dev/null
+++ b/src/com/android/server/telecom/components/TelecomBroadcastReceiver.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 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.components;
+
+import com.android.server.telecom.TelecomSystem;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Handles miscellaneous Telecom broadcast intents. This should be visible from outside, but
+ * should not be in the "exported" state.
+ */
+public final class TelecomBroadcastReceiver
+        extends BroadcastReceiver implements TelecomSystem.Component {
+
+    /** {@inheritDoc} */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        synchronized (getTelecomSystem().getLock()) {
+            getTelecomSystem().getTelecomBroadcastIntentProcessor().processIntent(intent);
+        }
+    }
+
+    @Override
+    public TelecomSystem getTelecomSystem() {
+        return TelecomSystem.getInstance();
+    }
+
+}
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
new file mode 100644
index 0000000..7856094
--- /dev/null
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 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.components;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.internal.telephony.CallerInfoAsyncQuery;
+import com.android.server.telecom.CallerInfoAsyncQueryFactory;
+import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.HeadsetMediaButton;
+import com.android.server.telecom.HeadsetMediaButtonFactory;
+import com.android.server.telecom.InCallWakeLockControllerFactory;
+import com.android.server.telecom.ProximitySensorManagerFactory;
+import com.android.server.telecom.InCallWakeLockController;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.ProximitySensorManager;
+import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.ui.MissedCallNotifierImpl;
+
+/**
+ * Implementation of the ITelecom interface.
+ */
+public class TelecomService extends Service implements TelecomSystem.Component {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.d(this, "onBind");
+        initializeTelecomSystem(this);
+        synchronized (getTelecomSystem().getLock()) {
+            return getTelecomSystem().getTelecomServiceImpl().getBinder();
+        }
+    }
+
+    /**
+     * This method is to be called by components (Activitys, Services, ...) to initialize the
+     * Telecom singleton. It should only be called on the main thread. As such, it is atomic
+     * and needs no synchronization -- it will either perform its initialization, after which
+     * the {@link TelecomSystem#getInstance()} will be initialized, or some other invocation of
+     * this method on the main thread will have happened strictly prior to it, and this method
+     * will be a benign no-op.
+     *
+     * @param context
+     */
+    static void initializeTelecomSystem(Context context) {
+        if (TelecomSystem.getInstance() == null) {
+            TelecomSystem.setInstance(
+                    new TelecomSystem(
+                            context,
+                            new MissedCallNotifierImpl(context.getApplicationContext()),
+                            new CallerInfoAsyncQueryFactory() {
+                                @Override
+                                public CallerInfoAsyncQuery startQuery(int token, Context context,
+                                        String number,
+                                        CallerInfoAsyncQuery.OnQueryCompleteListener listener,
+                                        Object cookie) {
+                                    Log.i(TelecomSystem.getInstance(),
+                                            "CallerInfoAsyncQuery.startQuery number=%s cookie=%s",
+                                            Log.pii(number), cookie);
+                                    return CallerInfoAsyncQuery.startQuery(
+                                            token, context, number, listener, cookie);
+                                }
+                            },
+                            new HeadsetMediaButtonFactory() {
+                                @Override
+                                public HeadsetMediaButton create(
+                                        Context context,
+                                        CallsManager callsManager,
+                                        TelecomSystem.SyncRoot lock) {
+                                    return new HeadsetMediaButton(context, callsManager, lock);
+                                }
+                            },
+                            new ProximitySensorManagerFactory() {
+                                @Override
+                                public ProximitySensorManager create(
+                                        Context context,
+                                        CallsManager callsManager) {
+                                    return new ProximitySensorManager(context, callsManager);
+                                }
+                            },
+                            new InCallWakeLockControllerFactory() {
+                                @Override
+                                public InCallWakeLockController create(Context context,
+                                        CallsManager callsManager) {
+                                    return new InCallWakeLockController(context, callsManager);
+                                }
+                            }));
+        }
+        if (BluetoothAdapter.getDefaultAdapter() != null) {
+            context.startService(new Intent(context, BluetoothPhoneService.class));
+        }
+    }
+
+    @Override
+    public TelecomSystem getTelecomSystem() {
+        return TelecomSystem.getInstance();
+    }
+}
diff --git a/src/com/android/server/telecom/components/UserCallActivity.java b/src/com/android/server/telecom/components/UserCallActivity.java
new file mode 100644
index 0000000..d88e09e
--- /dev/null
+++ b/src/com/android/server/telecom/components/UserCallActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.components;
+
+import com.android.server.telecom.CallIntentProcessor;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.TelecomSystem;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.TelecomManager;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+
+/**
+ * Activity that handles system CALL actions and forwards them to {@link CallIntentProcessor}.
+ * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY.
+ *
+ * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the
+ * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission).
+ *
+ * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency
+ * calls via ACTION_CALL_PRIVILEGED.
+ *
+ * In addition, the default dialer (identified via
+ * {@link TelecomManager#getDefaultPhoneApp()} will also be granted the ability to
+ * make emergency outgoing calls using the CALL action. In order to do this, it must call
+ * startActivityForResult on the CALL intent to allow its package name to be passed to
+ * {@link UserCallActivity}. Calling startActivity will continue to work on all non-emergency
+ * numbers just like it did pre-L.
+ */
+public class UserCallActivity extends Activity implements TelecomSystem.Component {
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        // TODO: Figure out if there is something to restore from bundle.
+        // See OutgoingCallBroadcaster in services/Telephony for more.
+        Intent intent = getIntent();
+        verifyCallAction(intent);
+        final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        final UserHandle userHandle = new UserHandle(userManager.getUserHandle());
+        // Once control flow has passed to this activity, it is no longer guaranteed that we can
+        // accurately determine whether the calling package has the CALL_PHONE runtime permission.
+        // At this point in time we trust that the ActivityManager has already performed this
+        // validation before starting this activity.
+        new UserCallIntentProcessor(this, userHandle).processIntent(getIntent(),
+                getCallingPackage(), true /* hasCallAppOp*/);
+        finish();
+    }
+
+    private void verifyCallAction(Intent intent) {
+        if (getClass().getName().equals(intent.getComponent().getClassName())) {
+            // If we were launched directly from the CallActivity, not one of its more privileged
+            // aliases, then make sure that only the non-privileged actions are allowed.
+            if (!Intent.ACTION_CALL.equals(intent.getAction())) {
+                Log.w(this, "Attempt to deliver non-CALL action; forcing to CALL");
+                intent.setAction(Intent.ACTION_CALL);
+            }
+        }
+    }
+
+    @Override
+    public TelecomSystem getTelecomSystem() {
+        return TelecomSystem.getInstance();
+    }
+}
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
new file mode 100644
index 0000000..8f451b5
--- /dev/null
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.components;
+
+import com.android.server.telecom.CallIntentProcessor;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.R;
+import com.android.server.telecom.TelephonyUtil;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.DefaultDialerManager;
+import android.telecom.PhoneAccount;
+import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+
+/**
+ * Handles system CALL actions and forwards them to {@link CallIntentProcessor}.
+ * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY.
+ *
+ * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the
+ * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission).
+ *
+ * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency
+ * calls via ACTION_CALL_PRIVILEGED.
+ *
+ * In addition, the default dialer (identified via
+ * {@link android.telecom.TelecomManager#getDefaultDialerPackage()} will also be granted the
+ * ability to make emergency outgoing calls using the CALL action. In order to do this, it must
+ * use the {@link TelecomManager#placeCall(Uri, android.os.Bundle)} method to allow its package
+ * name to be passed to {@link UserCallIntentProcessor}. Calling startActivity will continue to
+ * work on all non-emergency numbers just like it did pre-L.
+ */
+public class UserCallIntentProcessor {
+
+    private final Context mContext;
+    private final UserHandle mUserHandle;
+
+    public UserCallIntentProcessor(Context context, UserHandle userHandle) {
+        mContext = context;
+        mUserHandle = userHandle;
+    }
+
+    /**
+     * Processes intents sent to the activity.
+     *
+     * @param intent The intent.
+     */
+    public void processIntent(Intent intent, String callingPackageName,
+            boolean canCallNonEmergency) {
+        // Ensure call intents are not processed on devices that are not capable of calling.
+        if (!isVoiceCapable()) {
+            return;
+        }
+
+        String action = intent.getAction();
+
+        if (Intent.ACTION_CALL.equals(action) ||
+                Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
+                Intent.ACTION_CALL_EMERGENCY.equals(action)) {
+            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
+        }
+    }
+
+    private void processOutgoingCallIntent(Intent intent, String callingPackageName,
+            boolean canCallNonEmergency) {
+        Uri handle = intent.getData();
+        String scheme = handle.getScheme();
+        String uriString = handle.getSchemeSpecificPart();
+
+        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
+                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+        }
+
+        final UserManager userManager =
+                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, mUserHandle)
+                && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
+            // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS
+            // restriction.
+            showErrorDialogForRestrictedOutgoingCall(mContext,
+                    R.string.outgoing_call_not_allowed_user_restriction);
+            Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS "
+                    + "restriction");
+            return;
+        }
+
+        if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
+            showErrorDialogForRestrictedOutgoingCall(mContext,
+                    R.string.outgoing_call_not_allowed_no_permission);
+            Log.w(this, "Rejecting non-emergency phone call because "
+                    + android.Manifest.permission.CALL_PHONE + " permission is not granted.");
+            return;
+        }
+
+        int videoState = intent.getIntExtra(
+                TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                VideoProfile.STATE_AUDIO_ONLY);
+        Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
+
+        if (VideoProfile.isVideo(videoState)
+                && TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
+            Log.d(this, "Emergency call...Converting video call to voice...");
+            videoState = VideoProfile.STATE_AUDIO_ONLY;
+            intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                    videoState);
+        }
+
+        if (VideoProfile.isVideo(videoState) && isTtyModeEnabled()) {
+            Toast.makeText(mContext, mContext.getResources().getString(R.string.
+                    video_call_not_allowed_if_tty_enabled), Toast.LENGTH_SHORT).show();
+            Log.d(this, "Rejecting video calls as tty is enabled");
+            return;
+        }
+
+        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
+                isDefaultOrSystemDialer(callingPackageName));
+        sendBroadcastToReceiver(intent);
+    }
+
+    private boolean isTtyModeEnabled() {
+        return (android.provider.Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                android.provider.Settings.Secure.PREFERRED_TTY_MODE,
+                TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
+    }
+
+    private boolean isDefaultOrSystemDialer(String callingPackageName) {
+        if (TextUtils.isEmpty(callingPackageName)) {
+            return false;
+        }
+
+        final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext,
+                mUserHandle.getIdentifier());
+        if (TextUtils.equals(defaultDialer, callingPackageName)) {
+            return true;
+        }
+
+        final TelecomManager telecomManager =
+                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+        return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName);
+    }
+
+    /**
+     * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
+     *
+     * @return {@code True} if the device is voice-capable.
+     */
+    private boolean isVoiceCapable() {
+        return mContext.getApplicationContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
+    }
+
+    /**
+     * Trampolines the intent to the broadcast receiver that runs only as the primary user.
+     */
+    private boolean sendBroadcastToReceiver(Intent intent) {
+        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
+        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.setClass(mContext, PrimaryCallReceiver.class);
+        Log.d(this, "Sending broadcast as user to CallReceiver");
+        mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+        return true;
+    }
+
+    private static void showErrorDialogForRestrictedOutgoingCall(Context context, int stringId) {
+        final Intent intent = new Intent(context, ErrorDialogActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, stringId);
+        context.startActivityAsUser(intent, UserHandle.CURRENT);
+    }
+}
diff --git a/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java b/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java
new file mode 100644
index 0000000..2367825
--- /dev/null
+++ b/src/com/android/server/telecom/settings/EnableAccountPreferenceActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.settings;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.Log;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.view.MenuItem;
+
+public class EnableAccountPreferenceActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getFragmentManager().beginTransaction()
+                .replace(android.R.id.content, new EnableAccountPreferenceFragment())
+                .commit();
+
+        ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+    }
+
+    /** ${inheritDoc} */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                onBackPressed();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+}
diff --git a/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java b/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java
new file mode 100644
index 0000000..83eb113
--- /dev/null
+++ b/src/com/android/server/telecom/settings/EnableAccountPreferenceFragment.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.settings;
+
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+import com.android.server.telecom.R;
+
+import java.util.List;
+
+/**
+ * Lists all call-capable {@link PhoneAccount}s which are not SIM-based and provides a settings
+ * for enabling and disabling each of the accounts.  Only enabled accounts will be (1) listed as
+ * options with which to place a call and (2) capable of receiving incoming calls through the
+ * default dialer UI.
+ */
+public class EnableAccountPreferenceFragment extends PreferenceFragment {
+
+    private final class AccountSwitchPreference extends SwitchPreference {
+        private final PhoneAccount mAccount;
+
+        public AccountSwitchPreference(Context context, PhoneAccount account) {
+            super(context);
+            mAccount = account;
+
+            setTitle(account.getLabel());
+            setSummary(account.getShortDescription());
+            Icon icon = account.getIcon();
+            if (icon != null) {
+                setIcon(icon.loadDrawable(context));
+            }
+            setChecked(account.isEnabled());
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        protected void onClick() {
+            super.onClick();
+
+            mTelecomManager.enablePhoneAccount(mAccount.getAccountHandle(), isChecked());
+        }
+    }
+
+    private TelecomManager mTelecomManager;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mTelecomManager = TelecomManager.from(getActivity());
+    }
+
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        PreferenceScreen screen = getPreferenceScreen();
+        if (screen != null) {
+            screen.removeAll();
+        }
+
+        addPreferencesFromResource(R.xml.enable_account_preference);
+        screen = getPreferenceScreen();
+
+        List<PhoneAccountHandle> accountHandles =
+                mTelecomManager.getCallCapablePhoneAccounts(true /* includeDisabledAccounts */);
+
+        Context context = getActivity();
+        for (PhoneAccountHandle handle : accountHandles) {
+            PhoneAccount account = mTelecomManager.getPhoneAccount(handle);
+            if (account != null) {
+                final boolean isSimAccount =
+                        0 != (account.getCapabilities() & PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
+                if (!isSimAccount) {
+                    screen.addPreference(new AccountSwitchPreference(context, account));
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
new file mode 100644
index 0000000..f1d1078
--- /dev/null
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2014, 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.ui;
+
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallState;
+import com.android.server.telecom.CallerInfoAsyncQueryFactory;
+import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.CallsManagerListenerBase;
+import com.android.server.telecom.Constants;
+import com.android.server.telecom.ContactsAsyncHelper;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.MissedCallNotifier;
+import com.android.server.telecom.R;
+import com.android.server.telecom.TelecomBroadcastIntentProcessor;
+import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.components.TelecomBroadcastReceiver;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.TaskStackBuilder;
+import android.content.AsyncQueryHandler;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.provider.CallLog.Calls;
+import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccount;
+import android.telephony.PhoneNumberUtils;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+
+/**
+ * Creates a notification for calls that the user missed (neither answered nor rejected).
+ *
+ * TODO: Make TelephonyManager.clearMissedCalls call into this class.
+ *
+ * TODO: Reduce dependencies in this implementation; remove the need to create a new Call
+ *     simply to look up caller metadata, and if possible, make it unnecessary to get a
+ *     direct reference to the CallsManager. Try to make this class simply handle the UI
+ *     and Android-framework entanglements of missed call notification.
+ */
+public class MissedCallNotifierImpl extends CallsManagerListenerBase implements MissedCallNotifier {
+
+    private static final String[] CALL_LOG_PROJECTION = new String[] {
+        Calls._ID,
+        Calls.NUMBER,
+        Calls.NUMBER_PRESENTATION,
+        Calls.DATE,
+        Calls.DURATION,
+        Calls.TYPE,
+    };
+
+    private static final int CALL_LOG_COLUMN_ID = 0;
+    private static final int CALL_LOG_COLUMN_NUMBER = 1;
+    private static final int CALL_LOG_COLUMN_NUMBER_PRESENTATION = 2;
+    private static final int CALL_LOG_COLUMN_DATE = 3;
+    private static final int CALL_LOG_COLUMN_DURATION = 4;
+    private static final int CALL_LOG_COLUMN_TYPE = 5;
+
+    private static final int MISSED_CALL_NOTIFICATION_ID = 1;
+
+    private final Context mContext;
+    private final NotificationManager mNotificationManager;
+
+    // Used to track the number of missed calls.
+    private int mMissedCallCount = 0;
+
+    public MissedCallNotifierImpl(Context context) {
+        mContext = context;
+        mNotificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void onCallStateChanged(Call call, int oldState, int newState) {
+        if (oldState == CallState.RINGING && newState == CallState.DISCONNECTED &&
+                call.getDisconnectCause().getCode() == DisconnectCause.MISSED) {
+            showMissedCallNotification(call);
+        }
+    }
+
+    /** Clears missed call notification and marks the call log's missed calls as read. */
+    @Override
+    public void clearMissedCalls() {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                // Clear the list of new missed calls from the call log.
+                ContentValues values = new ContentValues();
+                values.put(Calls.NEW, 0);
+                values.put(Calls.IS_READ, 1);
+                StringBuilder where = new StringBuilder();
+                where.append(Calls.NEW);
+                where.append(" = 1 AND ");
+                where.append(Calls.TYPE);
+                where.append(" = ?");
+                try {
+                    mContext.getContentResolver().update(Calls.CONTENT_URI, values,
+                            where.toString(), new String[]{ Integer.toString(Calls.
+                            MISSED_TYPE) });
+                } catch (IllegalArgumentException e) {
+                    Log.w(this, "ContactsProvider update command failed", e);
+                }
+            }
+        });
+        cancelMissedCallNotification();
+    }
+
+    /**
+     * Create a system notification for the missed call.
+     *
+     * @param call The missed call.
+     */
+    @Override
+    public void showMissedCallNotification(Call call) {
+        mMissedCallCount++;
+
+        final int titleResId;
+        final String expandedText;  // The text in the notification's line 1 and 2.
+
+        // Display the first line of the notification:
+        // 1 missed call: <caller name || handle>
+        // More than 1 missed call: <number of calls> + "missed calls"
+        if (mMissedCallCount == 1) {
+            titleResId = R.string.notification_missedCallTitle;
+            expandedText = getNameForCall(call);
+        } else {
+            titleResId = R.string.notification_missedCallsTitle;
+            expandedText =
+                    mContext.getString(R.string.notification_missedCallsMsg, mMissedCallCount);
+        }
+
+        // Create the notification.
+        Notification.Builder builder = new Notification.Builder(mContext);
+        builder.setSmallIcon(android.R.drawable.stat_notify_missed_call)
+                .setColor(mContext.getResources().getColor(R.color.theme_color))
+                .setWhen(call.getCreationTimeMillis())
+                .setContentTitle(mContext.getText(titleResId))
+                .setContentText(expandedText)
+                .setContentIntent(createCallLogPendingIntent())
+                .setAutoCancel(true)
+                .setDeleteIntent(createClearMissedCallsPendingIntent());
+
+        Uri handleUri = call.getHandle();
+        String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart();
+
+        // Add additional actions when there is only 1 missed call, like call-back and SMS.
+        if (mMissedCallCount == 1) {
+            Log.d(this, "Add actions with number %s.", Log.piiHandle(handle));
+
+            if (!TextUtils.isEmpty(handle)
+                    && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))) {
+                builder.addAction(R.drawable.ic_phone_24dp,
+                        mContext.getString(R.string.notification_missedCall_call_back),
+                        createCallBackPendingIntent(handleUri));
+
+                builder.addAction(R.drawable.ic_message_24dp,
+                        mContext.getString(R.string.notification_missedCall_message),
+                        createSendSmsFromNotificationPendingIntent(handleUri));
+            }
+
+            Bitmap photoIcon = call.getPhotoIcon();
+            if (photoIcon != null) {
+                builder.setLargeIcon(photoIcon);
+            } else {
+                Drawable photo = call.getPhoto();
+                if (photo != null && photo instanceof BitmapDrawable) {
+                    builder.setLargeIcon(((BitmapDrawable) photo).getBitmap());
+                }
+            }
+        } else {
+            Log.d(this, "Suppress actions. handle: %s, missedCalls: %d.", Log.piiHandle(handle),
+                    mMissedCallCount);
+        }
+
+        Notification notification = builder.build();
+        configureLedOnNotification(notification);
+
+        Log.i(this, "Adding missed call notification for %s.", call);
+        long token = Binder.clearCallingIdentity();
+        try {
+            mNotificationManager.notifyAsUser(
+                    null /* tag */, MISSED_CALL_NOTIFICATION_ID, notification, UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /** Cancels the "missed call" notification. */
+    private void cancelMissedCallNotification() {
+        // Reset the number of missed calls to 0.
+        mMissedCallCount = 0;
+        long token = Binder.clearCallingIdentity();
+        try {
+            mNotificationManager.cancelAsUser(null, MISSED_CALL_NOTIFICATION_ID,
+                    UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Returns the name to use in the missed call notification.
+     */
+    private String getNameForCall(Call call) {
+        String handle = call.getHandle() == null ? null : call.getHandle().getSchemeSpecificPart();
+        String name = call.getName();
+
+        if (!TextUtils.isEmpty(name) && TextUtils.isGraphic(name)) {
+            return name;
+        } else if (!TextUtils.isEmpty(handle)) {
+            // A handle should always be displayed LTR using {@link BidiFormatter} regardless of the
+            // content of the rest of the notification.
+            // TODO: Does this apply to SIP addresses?
+            BidiFormatter bidiFormatter = BidiFormatter.getInstance();
+            return bidiFormatter.unicodeWrap(handle, TextDirectionHeuristics.LTR);
+        } else {
+            // Use "unknown" if the call is unidentifiable.
+            return mContext.getString(R.string.unknown);
+        }
+    }
+
+    /**
+     * Creates a new pending intent that sends the user to the call log.
+     *
+     * @return The pending intent.
+     */
+    private PendingIntent createCallLogPendingIntent() {
+        Intent intent = new Intent(Intent.ACTION_VIEW, null);
+        intent.setType(Calls.CONTENT_TYPE);
+
+        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext);
+        taskStackBuilder.addNextIntent(intent);
+
+        return taskStackBuilder.getPendingIntent(0, 0, null, UserHandle.CURRENT);
+    }
+
+    /**
+     * Creates an intent to be invoked when the missed call notification is cleared.
+     */
+    private PendingIntent createClearMissedCallsPendingIntent() {
+        return createTelecomPendingIntent(
+                TelecomBroadcastIntentProcessor.ACTION_CLEAR_MISSED_CALLS, null);
+    }
+
+    /**
+     * Creates an intent to be invoked when the user opts to "call back" from the missed call
+     * notification.
+     *
+     * @param handle The handle to call back.
+     */
+    private PendingIntent createCallBackPendingIntent(Uri handle) {
+        return createTelecomPendingIntent(
+                TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION, handle);
+    }
+
+    /**
+     * Creates an intent to be invoked when the user opts to "send sms" from the missed call
+     * notification.
+     */
+    private PendingIntent createSendSmsFromNotificationPendingIntent(Uri handle) {
+        return createTelecomPendingIntent(
+                TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION,
+                Uri.fromParts(Constants.SCHEME_SMSTO, handle.getSchemeSpecificPart(), null));
+    }
+
+    /**
+     * Creates generic pending intent from the specified parameters to be received by
+     * {@link TelecomBroadcastIntentProcessor}.
+     *
+     * @param action The intent action.
+     * @param data The intent data.
+     */
+    private PendingIntent createTelecomPendingIntent(String action, Uri data) {
+        Intent intent = new Intent(action, data, mContext, TelecomBroadcastReceiver.class);
+        return PendingIntent.getBroadcast(mContext, 0, intent, 0);
+    }
+
+    /**
+     * Configures a notification to emit the blinky notification light.
+     */
+    private void configureLedOnNotification(Notification notification) {
+        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
+        notification.defaults |= Notification.DEFAULT_LIGHTS;
+    }
+
+    /**
+     * Adds the missed call notification on startup if there are unread missed calls.
+     */
+    @Override
+    public void updateOnStartup(
+            final TelecomSystem.SyncRoot lock,
+            final CallsManager callsManager,
+            final ContactsAsyncHelper contactsAsyncHelper,
+            final CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory) {
+        Log.d(this, "updateOnStartup()...");
+
+        // instantiate query handler
+        AsyncQueryHandler queryHandler = new AsyncQueryHandler(mContext.getContentResolver()) {
+            @Override
+            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+                Log.d(MissedCallNotifierImpl.this, "onQueryComplete()...");
+                if (cursor != null) {
+                    try {
+                        while (cursor.moveToNext()) {
+                            // Get data about the missed call from the cursor
+                            final String handleString = cursor.getString(CALL_LOG_COLUMN_NUMBER);
+                            final int presentation =
+                                    cursor.getInt(CALL_LOG_COLUMN_NUMBER_PRESENTATION);
+                            final long date = cursor.getLong(CALL_LOG_COLUMN_DATE);
+
+                            final Uri handle;
+                            if (presentation != Calls.PRESENTATION_ALLOWED
+                                    || TextUtils.isEmpty(handleString)) {
+                                handle = null;
+                            } else {
+                                handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(handleString) ?
+                                        PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
+                                                handleString, null);
+                            }
+
+                            synchronized (lock) {
+
+                                // Convert the data to a call object
+                                Call call = new Call(mContext, callsManager, lock,
+                                        null, contactsAsyncHelper, callerInfoAsyncQueryFactory,
+                                        null, null, null, null, true, false);
+                                call.setDisconnectCause(
+                                        new DisconnectCause(DisconnectCause.MISSED));
+                                call.setState(CallState.DISCONNECTED, "throw away call");
+                                call.setCreationTimeMillis(date);
+
+                                // Listen for the update to the caller information before posting
+                                // the notification so that we have the contact info and photo.
+                                call.addListener(new Call.ListenerBase() {
+                                    @Override
+                                    public void onCallerInfoChanged(Call call) {
+                                        call.removeListener(
+                                                this);  // No longer need to listen to call
+                                        // changes after the contact info
+                                        // is retrieved.
+                                        showMissedCallNotification(call);
+                                    }
+                                });
+                                // Set the handle here because that is what triggers the contact
+                                // info query.
+                                call.setHandle(handle, presentation);
+                            }
+                        }
+                    } finally {
+                        cursor.close();
+                    }
+                }
+            }
+        };
+
+        // setup query spec, look for all Missed calls that are new.
+        StringBuilder where = new StringBuilder("type=");
+        where.append(Calls.MISSED_TYPE);
+        where.append(" AND new=1");
+        where.append(" AND is_read=0");
+
+        // start the query
+        queryHandler.startQuery(0, null, Calls.CONTENT_URI, CALL_LOG_PROJECTION,
+                where.toString(), null, Calls.DEFAULT_SORT_ORDER);
+    }
+}
diff --git a/testapps/Android.mk b/testapps/Android.mk
new file mode 100644
index 0000000..74928d0
--- /dev/null
+++ b/testapps/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        android-support-v4 \
+        android-ex-camera2 \
+        guava
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TelecomTestApps
+LOCAL_CERTIFICATE := platform
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
new file mode 100644
index 0000000..df333a5
--- /dev/null
+++ b/testapps/AndroidManifest.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          coreApp="true"
+          package="com.android.server.telecom.testapps">
+
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+    <uses-permission android:name="android.permission.READ_CALL_LOG" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
+    <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
+    <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
+    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+
+    <application android:label="@string/app_name">
+        <uses-library android:name="android.test.runner" />
+
+        <!-- Miscellaneous telecom app-related test activities. -->
+
+        <service android:name="com.android.server.telecom.testapps.TestConnectionService"
+                 android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
+            <intent-filter>
+                <action android:name="android.telecom.ConnectionService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="com.android.server.telecom.testapps.TestConnectionManager"
+                 android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
+            <intent-filter>
+                <action android:name="android.telecom.ConnectionService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="com.android.server.telecom.testapps.TestInCallServiceImpl"
+                 android:process="com.android.server.telecom.testapps.TestInCallService"
+                 android:permission="android.permission.BIND_INCALL_SERVICE" >
+            <intent-filter>
+                <action android:name="android.telecom.InCallService"/>
+            </intent-filter>
+        </service>
+
+        <receiver android:name="com.android.server.telecom.testapps.TestInCallServiceBroadcastReceiver"
+                 android:process="com.android.server.telecom.testapps.TestInCallService" >
+            <intent-filter>
+                <action android:name="android.server.telecom.testapps.ACTION_SEND_UPDATE_REQUEST_FROM_TEST_INCALL_SERVICE"/>
+                <action android:name="android.server.telecom.testapps.ACTION_SEND_UPGRADE_RESPONSE"/>
+                <data android:scheme="int" />
+            </intent-filter>
+        </receiver>
+
+        <activity android:name="com.android.server.telecom.testapps.TestCallActivity"
+                  android:theme="@android:style/Theme.NoDisplay"
+                  android:label="@string/testCallActivityLabel">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.telecom.testapps.ACTION_START_INCOMING_CALL" />
+                <action android:name="android.telecom.testapps.ACTION_NEW_UNKNOWN_CALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="tel" />
+                <data android:scheme="sip" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.telecom.testapps.ACTION_HANGUP_CALLS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="int" />
+            </intent-filter>
+        </activity>
+
+        <receiver android:name="com.android.server.telecom.testapps.CallNotificationReceiver"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.server.telecom.testapps.ACTION_CALL_SERVICE_EXIT" />
+            </intent-filter>
+        </receiver>
+
+        <activity android:name="com.android.server.telecom.testapps.TestDialerActivity"
+                  android:label="@string/testDialerActivityLabel"
+                  android:process="com.android.server.telecom.testapps.TestInCallService">
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:mimeType="vnd.android.cursor.item/phone" />
+                <data android:mimeType="vnd.android.cursor.item/person" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="voicemail" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="tel" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/res/drawable-xhdpi/stat_sys_phone_call.png b/testapps/res/drawable-xhdpi/stat_sys_phone_call.png
similarity index 100%
rename from res/drawable-xhdpi/stat_sys_phone_call.png
rename to testapps/res/drawable-xhdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/tests/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
similarity index 78%
rename from tests/res/layout/testdialer_main.xml
rename to testapps/res/layout/testdialer_main.xml
index a5453fc..2c3e5e4 100644
--- a/tests/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -34,4 +34,14 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@string/defaultDialerButton" />
+    <Button
+        android:id="@+id/test_voicemail_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/testVoicemailButton" />
+    <Button
+        android:id="@+id/cancel_missed_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/cancelMissedButton" />
 </LinearLayout>
diff --git a/tests/res/raw/beep_boop.ogg b/testapps/res/raw/beep_boop.ogg
similarity index 100%
rename from tests/res/raw/beep_boop.ogg
rename to testapps/res/raw/beep_boop.ogg
Binary files differ
diff --git a/tests/res/raw/outgoing_video.mp4 b/testapps/res/raw/outgoing_video.mp4
similarity index 100%
rename from tests/res/raw/outgoing_video.mp4
rename to testapps/res/raw/outgoing_video.mp4
Binary files differ
diff --git a/tests/res/raw/test_pattern.mp4 b/testapps/res/raw/test_pattern.mp4
similarity index 100%
rename from tests/res/raw/test_pattern.mp4
rename to testapps/res/raw/test_pattern.mp4
Binary files differ
diff --git a/tests/res/raw/test_video.mp4 b/testapps/res/raw/test_video.mp4
similarity index 100%
rename from tests/res/raw/test_video.mp4
rename to testapps/res/raw/test_video.mp4
Binary files differ
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
new file mode 100644
index 0000000..43c302d
--- /dev/null
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Application label -->
+    <string name="app_name">TelecommTests</string>
+
+    <!-- String for the TestCallActivity -->
+    <string name="testCallActivityLabel">Test Connection Service App</string>
+
+    <!-- String for the TestDialerActivity -->
+    <string name="testDialerActivityLabel">Test Dialer</string>
+
+    <!-- String for button in TestDialerActivity that reassigns the default Dialer -->
+    <string name="defaultDialerButton">Default dialer request</string>
+
+    <!-- String for button in TestDialerActivity that places a test call -->
+    <string name="placeCallButton">Place call</string>
+
+    <!-- String for button in TestDialerActivity that performs voicemail requests to verify
+            voicemail permissions -->
+    <string name="testVoicemailButton">Exercise voicemail permissions</string>
+
+    <!-- String for button in TestDialerActivity that tries to exercise the
+            TelecomManager.cancelMissedCallNotifications() functionality -->
+    <string name="cancelMissedButton">Cancel missed calls</string>
+</resources>
diff --git a/tests/src/com/android/server/telecom/testapps/CallNotificationReceiver.java b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
similarity index 87%
rename from tests/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
rename to testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
index a835bf1..20a0475 100644
--- a/tests/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallNotificationReceiver.java
@@ -22,7 +22,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.telecom.CallState;
+import android.support.v4.content.LocalBroadcastManager;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.util.Log;
@@ -105,4 +105,17 @@
 
         TelecomManager.from(context).addNewUnknownCall(phoneAccount, extras);
     }
+
+    public static void hangupCalls(Context context) {
+        Log.i(TAG, "Hanging up all calls");
+        LocalBroadcastManager.getInstance(context).sendBroadcast(
+                new Intent(TestCallActivity.ACTION_HANGUP_CALLS));
+    }
+
+    public static void sendUpgradeRequest(Context context, Uri data) {
+        Log.i(TAG, "Sending upgrade request of type: " + data);
+        final Intent intent = new Intent(TestCallActivity.ACTION_SEND_UPGRADE_REQUEST);
+        intent.setData(data);
+        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+    }
 }
diff --git a/tests/src/com/android/server/telecom/testapps/CallServiceNotifier.java b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
similarity index 93%
rename from tests/src/com/android/server/telecom/testapps/CallServiceNotifier.java
rename to testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
index 23e8222..cd0800e 100644
--- a/tests/src/com/android/server/telecom/testapps/CallServiceNotifier.java
+++ b/testapps/src/com/android/server/telecom/testapps/CallServiceNotifier.java
@@ -16,7 +16,7 @@
 
 package com.android.server.telecom.testapps;
 
-import com.android.server.telecom.tests.R;
+import com.android.server.telecom.testapps.R;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -27,6 +27,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -109,8 +110,11 @@
                 "TelecomTestApp Call Provider")
                 .setAddress(Uri.parse("tel:555-TEST"))
                 .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setIcon(context, R.drawable.stat_sys_phone_call, Color.RED)
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_VIDEO_CALLING)
+                .setIcon(Icon.createWithResource(
+                        context.getResources(), R.drawable.stat_sys_phone_call))
+                // TODO: Add icon tint (Color.RED)
                 .setHighlightColor(Color.RED)
                 .setShortDescription("a short description for the call provider")
                 .setSupportedUriSchemes(Arrays.asList("tel"))
@@ -124,8 +128,11 @@
                 .setAddress(Uri.parse("tel:555-TSIM"))
                 .setSubscriptionAddress(Uri.parse("tel:555-TSIM"))
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
-                .setIcon(context, R.drawable.stat_sys_phone_call, Color.GREEN)
+                        PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                        PhoneAccount.CAPABILITY_VIDEO_CALLING)
+                .setIcon(Icon.createWithResource(
+                        context.getResources(), R.drawable.stat_sys_phone_call))
+                // TODO: Add icon tint (Color.GREEN)
                 .setHighlightColor(Color.GREEN)
                 .setShortDescription("a short description for the sim subscription")
                 .build());
@@ -138,7 +145,9 @@
                 .setAddress(Uri.parse("tel:555-CMGR"))
                 .setSubscriptionAddress(Uri.parse("tel:555-CMGR"))
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
-                .setIcon(context, R.drawable.stat_sys_phone_call, Color.BLUE)
+                .setIcon(Icon.createWithResource(
+                        context.getResources(), R.drawable.stat_sys_phone_call))
+                // TODO: Add icon tint (Color.BLUE)
                 .setShortDescription("a short description for the connection manager")
                 .build());
     }
diff --git a/tests/src/com/android/server/telecom/testapps/CameraThread.java b/testapps/src/com/android/server/telecom/testapps/CameraThread.java
similarity index 100%
rename from tests/src/com/android/server/telecom/testapps/CameraThread.java
rename to testapps/src/com/android/server/telecom/testapps/CameraThread.java
diff --git a/tests/src/com/android/server/telecom/testapps/TestCallActivity.java b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
similarity index 79%
rename from tests/src/com/android/server/telecom/testapps/TestCallActivity.java
rename to testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
index 6f4ae20..4ac151f 100644
--- a/tests/src/com/android/server/telecom/testapps/TestCallActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallActivity.java
@@ -42,6 +42,15 @@
     public static final String ACTION_NEW_UNKNOWN_CALL =
             "android.telecom.testapps.ACTION_NEW_UNKNOWN_CALL";
 
+    /*
+     * Hang up any test incoming calls, to simulate the user missing a call.
+     */
+    public static final String ACTION_HANGUP_CALLS =
+            "android.telecom.testapps.ACTION_HANGUP_CALLS";
+
+    public static final String ACTION_SEND_UPGRADE_REQUEST =
+            "android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST";
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -52,6 +61,10 @@
             CallNotificationReceiver.sendIncomingCallIntent(this, data, false);
         } else if (ACTION_NEW_UNKNOWN_CALL.equals(action) && data != null) {
             CallNotificationReceiver.addNewUnknownCall(this, data, intent.getExtras());
+        } else if (ACTION_HANGUP_CALLS.equals(action)) {
+            CallNotificationReceiver.hangupCalls(this);
+        } else if (ACTION_SEND_UPGRADE_REQUEST.equals(action)) {
+            CallNotificationReceiver.sendUpgradeRequest(this, data);
         } else {
             CallServiceNotifier.getInstance().updateNotification(this);
         }
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallList.java b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
new file mode 100644
index 0000000..a16c4e2
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Maintains a list of calls received via the {@link TestInCallServiceImpl}.
+ */
+public class TestCallList extends Call.Listener {
+    private static final TestCallList INSTANCE = new TestCallList();
+    private static final String TAG = "TestCallList";
+
+    private class TestVideoCallListener extends InCallService.VideoCall.Callback {
+        private Call mCall;
+
+        public TestVideoCallListener(Call call) {
+            mCall = call;
+        }
+
+        @Override
+        public void onSessionModifyRequestReceived(VideoProfile videoProfile) {
+            Log.v(TAG,
+                    "onSessionModifyRequestReceived: videoState = " + videoProfile.getVideoState()
+                            + " call = " + mCall);
+        }
+
+        @Override
+        public void onSessionModifyResponseReceived(int status, VideoProfile requestedProfile,
+                VideoProfile responseProfile) {
+            Log.v(TAG,
+                    "onSessionModifyResponseReceived: status = " + status + " videoState = "
+                            + responseProfile.getVideoState()
+                            + " call = " + mCall);
+        }
+
+        @Override
+        public void onCallSessionEvent(int event) {
+
+        }
+
+        @Override
+        public void onPeerDimensionsChanged(int width, int height) {
+
+        }
+
+        @Override
+        public void onVideoQualityChanged(int videoQuality) {
+            Log.v(TAG,
+                    "onVideoQualityChanged: videoQuality = " + videoQuality + " call = " + mCall);
+        }
+
+        @Override
+        public void onCallDataUsageChanged(long dataUsage) {
+
+        }
+
+        @Override
+        public void onCameraCapabilitiesChanged(CameraCapabilities cameraCapabilities) {
+
+        }
+    }
+
+    // The calls the call list knows about.
+    private Set<Call> mCalls = new ArraySet<Call>();
+    private Map<Call, TestVideoCallListener> mVideoCallListeners =
+            new ArrayMap<Call, TestVideoCallListener>();
+
+    /**
+     * Singleton accessor.
+     */
+    public static TestCallList getInstance() {
+        return INSTANCE;
+    }
+
+    public void addCall(Call call) {
+        if (mCalls.contains(call)) {
+            Log.e(TAG, "addCall: Call already added.");
+            return;
+        }
+        Log.v(TAG, "addCall: " + call + " " + System.identityHashCode(this));
+        mCalls.add(call);
+        call.addListener(this);
+    }
+
+    public void removeCall(Call call) {
+        if (!mCalls.contains(call)) {
+            Log.e(TAG, "removeCall: Call cannot be removed -- doesn't exist.");
+            return;
+        }
+        Log.v(TAG, "removeCall: " + call);
+        mCalls.remove(call);
+        call.removeListener(this);
+    }
+
+    public void clearCalls() {
+        mCalls.clear();
+        for (Call call : mVideoCallListeners.keySet()) {
+            if (call.getVideoCall() != null) {
+                call.getVideoCall().destroy();
+            }
+        }
+        mVideoCallListeners.clear();
+    }
+
+    /**
+     * For any video calls tracked, sends an upgrade to video request.
+     */
+    public void sendUpgradeToVideoRequest(int videoState) {
+        Log.v(TAG, "sendUpgradeToVideoRequest : videoState = " + videoState);
+
+        for (Call call : mCalls) {
+            InCallService.VideoCall videoCall = call.getVideoCall();
+            Log.v(TAG, "sendUpgradeToVideoRequest: checkCall "+call);
+            if (videoCall == null) {
+                continue;
+            }
+
+            Log.v(TAG, "send upgrade to video request for call: " + call);
+            videoCall.sendSessionModifyRequest(new VideoProfile(videoState));
+        }
+    }
+
+    /**
+     * For any video calls which are active, sends an upgrade to video response with the specified
+     * video state.
+     *
+     * @param videoState The video state to respond with.
+     */
+    public void sendUpgradeToVideoResponse(int videoState) {
+        Log.v(TAG, "sendUpgradeToVideoResponse : videoState = " + videoState);
+
+        for (Call call : mCalls) {
+            InCallService.VideoCall videoCall = call.getVideoCall();
+            if (videoCall == null) {
+                continue;
+            }
+
+            Log.v(TAG, "send upgrade to video response for call: " + call);
+            videoCall.sendSessionModifyResponse(new VideoProfile(videoState));
+        }
+    }
+
+    @Override
+    public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {
+        Log.v(TAG, "onVideoCallChanged: call = " + call + " " + System.identityHashCode(this));
+        if (videoCall != null) {
+            if (!mVideoCallListeners.containsKey(call)) {
+                TestVideoCallListener listener = new TestVideoCallListener(call);
+                videoCall.registerCallback(listener);
+                mVideoCallListeners.put(call, listener);
+                Log.v(TAG, "onVideoCallChanged: added new listener");
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/server/telecom/testapps/TestConnectionManager.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
similarity index 97%
rename from tests/src/com/android/server/telecom/testapps/TestConnectionManager.java
rename to testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
index a27be39..14e62bc 100644
--- a/tests/src/com/android/server/telecom/testapps/TestConnectionManager.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
@@ -17,7 +17,7 @@
 package com.android.server.telecom.testapps;
 
 import android.net.Uri;
-import android.telecom.AudioState;
+import android.telecom.CallAudioState;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
@@ -82,7 +82,7 @@
 
             @Override
             public void onVideoStateChanged(RemoteConnection connection, int videoState) {
-                if (videoState == VideoProfile.VideoState.BIDIRECTIONAL) {
+                if (videoState == VideoProfile.STATE_BIDIRECTIONAL) {
                     setVideoProvider(new TestManagedVideoProvider(connection.getVideoProvider()));
                 }
                 setVideoState(videoState);
@@ -172,8 +172,8 @@
         }
 
         @Override
-        public void onAudioStateChanged(AudioState state) {
-            mRemote.setAudioState(state);
+        public void onCallAudioStateChanged(CallAudioState state) {
+            mRemote.setCallAudioState(state);
         }
 
         private void setState(int state) {
diff --git a/tests/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
similarity index 81%
rename from tests/src/com/android/server/telecom/testapps/TestConnectionService.java
rename to testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index 2e01276..45896f4 100644
--- a/tests/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -16,13 +16,16 @@
 
 package com.android.server.telecom.testapps;
 
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.telecom.AudioState;
+import android.support.v4.content.LocalBroadcastManager;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
@@ -34,7 +37,7 @@
 import android.telecom.VideoProfile;
 import android.util.Log;
 
-import com.android.server.telecom.tests.R;
+import com.android.server.telecom.testapps.R;
 
 import java.lang.String;
 import java.util.ArrayList;
@@ -125,21 +128,50 @@
         }
     }
 
-    private final class TestConnection extends Connection {
+    final class TestConnection extends Connection {
         private final boolean mIsIncoming;
 
         /** Used to cleanup camera and media when done with connection. */
         private TestVideoProvider mTestVideoCallProvider;
 
+        private BroadcastReceiver mHangupReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                setDisconnected(new DisconnectCause(DisconnectCause.MISSED));
+                destroyCall(TestConnection.this);
+                destroy();
+            }
+        };
+
+        private BroadcastReceiver mUpgradeRequestReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int request = Integer.parseInt(intent.getData().getSchemeSpecificPart());
+                final VideoProfile videoProfile = new VideoProfile(request);
+                mTestVideoCallProvider.receiveSessionModifyRequest(videoProfile);
+            }
+        };
+
         TestConnection(boolean isIncoming) {
             mIsIncoming = isIncoming;
             // Assume all calls are video capable.
             int capabilities = getConnectionCapabilities();
-            capabilities |= CAPABILITY_SUPPORTS_VT_LOCAL;
+            capabilities |= CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL;
+            capabilities |= CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL;
+            capabilities |= CAPABILITY_CAN_UPGRADE_TO_VIDEO;
             capabilities |= CAPABILITY_MUTE;
             capabilities |= CAPABILITY_SUPPORT_HOLD;
             capabilities |= CAPABILITY_HOLD;
+            capabilities |= CAPABILITY_RESPOND_VIA_TEXT;
             setConnectionCapabilities(capabilities);
+
+            LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
+                    mHangupReceiver, new IntentFilter(TestCallActivity.ACTION_HANGUP_CALLS));
+            final IntentFilter filter =
+                    new IntentFilter(TestCallActivity.ACTION_SEND_UPGRADE_REQUEST);
+            filter.addDataScheme("int");
+            LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
+                    mUpgradeRequestReceiver, filter);
         }
 
         void startOutgoing() {
@@ -209,13 +241,17 @@
             setActive();
         }
 
-        @Override
-        public void onAudioStateChanged(AudioState state) { }
-
         public void setTestVideoCallProvider(TestVideoProvider testVideoCallProvider) {
             mTestVideoCallProvider = testVideoCallProvider;
         }
 
+        public void cleanup() {
+            LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(
+                    mHangupReceiver);
+            LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(
+                    mUpgradeRequestReceiver);
+        }
+
         /**
          * Stops playback of test videos.
          */
@@ -267,7 +303,7 @@
                 originalHandle + "]");
 
         final TestConnection connection = new TestConnection(false /* isIncoming */);
-        connection.setAddress(handle, TelecomManager.PRESENTATION_ALLOWED);
+        setAddress(connection, handle);
 
         // If the number starts with 555, then we handle it ourselves. If not, then we
         // use a remote connection service.
@@ -281,7 +317,8 @@
                     handle.getSchemeSpecificPart() + "..", ""),
                     originalRequest.getExtras(),
                     originalRequest.getVideoState());
-
+            connection.setVideoState(originalRequest.getVideoState());
+            addVideoProvider(connection);
             addCall(connection);
             connection.startOutgoing();
 
@@ -312,20 +349,14 @@
             Uri address = providedHandle == null ?
                     Uri.fromParts(PhoneAccount.SCHEME_TEL, getDummyNumber(isVideoCall), null)
                     : providedHandle;
-            if (isVideoCall) {
-                TestVideoProvider testVideoCallProvider =
-                        new TestVideoProvider(getApplicationContext());
-                connection.setVideoProvider(testVideoCallProvider);
-
-                // Keep reference to original so we can clean up the media players later.
-                connection.setTestVideoCallProvider(testVideoCallProvider);
-            }
 
             int videoState = isVideoCall ?
-                    VideoProfile.VideoState.BIDIRECTIONAL :
-                    VideoProfile.VideoState.AUDIO_ONLY;
+                    VideoProfile.STATE_BIDIRECTIONAL :
+                    VideoProfile.STATE_AUDIO_ONLY;
             connection.setVideoState(videoState);
-            connection.setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
+            setAddress(connection, address);
+
+            addVideoProvider(connection);
 
             addCall(connection);
 
@@ -367,6 +398,15 @@
         }
     }
 
+    private void addVideoProvider(TestConnection connection) {
+        TestVideoProvider testVideoCallProvider =
+                new TestVideoProvider(getApplicationContext(), connection);
+        connection.setVideoProvider(testVideoCallProvider);
+
+        // Keep reference to original so we can clean up the media players later.
+        connection.setTestVideoCallProvider(testVideoCallProvider);
+    }
+
     private void activateCall(TestConnection connection) {
         if (mMediaPlayer == null) {
             mMediaPlayer = createMediaPlayer();
@@ -377,6 +417,7 @@
     }
 
     private void destroyCall(TestConnection connection) {
+        connection.cleanup();
         mCalls.remove(connection);
 
         // Ensure any playing media and camera resources are released.
@@ -412,6 +453,13 @@
         }
     }
 
+    private void setAddress(Connection connection, Uri address) {
+        connection.setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
+        if ("5551234".equals(address.getSchemeSpecificPart())) {
+            connection.setCallerDisplayName("Hello World", TelecomManager.PRESENTATION_ALLOWED);
+        }
+    }
+
     private MediaPlayer createMediaPlayer() {
         // Prepare the media player to play a tone when there is a call.
         MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.beep_boop);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
new file mode 100644
index 0000000..596d18d
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -0,0 +1,137 @@
+package com.android.server.telecom.testapps;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccount;
+import android.telecom.TelecomManager;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.android.server.telecom.testapps.R;
+
+public class TestDialerActivity extends Activity {
+    private static final int REQUEST_CODE_SET_DEFAULT_DIALER = 1;
+
+    private EditText mNumberView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.testdialer_main);
+        findViewById(R.id.set_default_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                setDefault();
+            }
+        });
+
+        findViewById(R.id.place_call_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                placeCall();
+            }
+        });
+
+        findViewById(R.id.test_voicemail_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                testVoicemail();
+            }
+        });
+
+        findViewById(R.id.cancel_missed_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                cancelMissedCallNotification();
+            }
+        });
+
+        mNumberView = (EditText) findViewById(R.id.number);
+        updateEditTextWithNumber();
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_SET_DEFAULT_DIALER) {
+            if (resultCode == RESULT_OK) {
+                showToast("User accepted request to become default dialer");
+            } else if (resultCode == RESULT_CANCELED) {
+                showToast("User declined request to become default dialer");
+            }
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        updateEditTextWithNumber();
+    }
+
+    private void updateEditTextWithNumber() {
+        Intent intent = getIntent();
+        if (intent != null) {
+            mNumberView.setText(intent.getDataString());
+        }
+    }
+
+    private void setDefault() {
+        final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
+        intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
+        startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER);
+    }
+
+    private void placeCall() {
+        final TelecomManager telecomManager =
+                (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
+        telecomManager.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL,
+                mNumberView.getText().toString(), null), createCallIntentExtras());
+    }
+
+    private void testVoicemail() {
+        try {
+            // Test read
+            getContentResolver().query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null);
+            // Test write
+            final ContentValues values = new ContentValues();
+            values.put(Calls.CACHED_NAME, "hello world");
+            getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values, "1=0", null);
+        } catch (SecurityException e) {
+            showToast("Permission check failed");
+            return;
+        }
+        showToast("Permission check succeeded");
+    }
+
+    private void showToast(String message) {
+        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+    }
+
+    private void cancelMissedCallNotification() {
+        try {
+            final TelecomManager tm = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
+            tm.cancelMissedCallsNotification();
+        } catch (SecurityException e) {
+            Toast.makeText(this, "Privileged dialer operation failed", Toast.LENGTH_SHORT).show();
+            return;
+        }
+        Toast.makeText(this, "Privileged dialer operation succeeded", Toast.LENGTH_SHORT).show();
+    }
+
+    private Bundle createCallIntentExtras() {
+        Bundle extras = new Bundle();
+        extras.putString("com.android.server.telecom.testapps.CALL_EXTRAS", "Yorke was here");
+
+        Bundle intentExtras = new Bundle();
+        intentExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
+        Log.i("Santos xtr", intentExtras.toString());
+        return intentExtras;
+    }
+}
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallServiceBroadcastReceiver.java b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceBroadcastReceiver.java
new file mode 100644
index 0000000..b6902bf
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceBroadcastReceiver.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * Test in call service broadcast receiver.
+ */
+public class TestInCallServiceBroadcastReceiver extends BroadcastReceiver {
+    private static final String TAG = "TestInCallServiceBR";
+
+    /**
+     * Sends an upgrade to video request for any live calls.
+     */
+    public static final String ACTION_SEND_UPDATE_REQUEST_FROM_TEST_INCALL_SERVICE =
+            "android.server.telecom.testapps.ACTION_SEND_UPDATE_REQUEST_FROM_TEST_INCALL_SERVICE";
+
+    /**
+     * Sends an a response to an upgrade to video request.
+     */
+    public static final String ACTION_SEND_UPGRADE_RESPONSE =
+            "android.server.telecom.testapps.ACTION_SEND_UPGRADE_RESPONSE";
+
+    /**
+     * Handles broadcasts directed at the {@link TestInCallServiceImpl}.
+     *
+     * @param context The Context in which the receiver is running.
+     * @param intent  The Intent being received.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        Log.v(TAG, "onReceive: " + action);
+
+        if (ACTION_SEND_UPDATE_REQUEST_FROM_TEST_INCALL_SERVICE.equals(action)) {
+            final int videoState = Integer.parseInt(intent.getData().getSchemeSpecificPart());
+            TestCallList.getInstance().sendUpgradeToVideoRequest(videoState);
+        } else if (ACTION_SEND_UPGRADE_RESPONSE.equals(action)) {
+            final int videoState = Integer.parseInt(intent.getData().getSchemeSpecificPart());
+            TestCallList.getInstance().sendUpgradeToVideoResponse(videoState);
+        }
+    }
+}
diff --git a/tests/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
similarity index 79%
rename from tests/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
rename to testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
index 1d7e805..68bbac9 100644
--- a/tests/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.testapps;
 
+import android.telecom.Call;
 import android.telecom.InCallService;
 import android.telecom.Phone;
 import android.util.Log;
@@ -34,12 +35,15 @@
 
     private Phone.Listener mPhoneListener = new Phone.Listener() {
         @Override
-        public void onCallAdded(Phone phone, android.telecom.Call call) {
-            Log.i(TAG, "onCallAdded: "+call.toString());
+        public void onCallAdded(Phone phone, Call call) {
+            Log.i(TAG, "onCallAdded: " + call.toString());
+            TestCallList.getInstance().addCall(call);
         }
+
         @Override
-        public void onCallRemoved(Phone phone, android.telecom.Call call) {
+        public void onCallRemoved(Phone phone, Call call) {
             Log.i(TAG, "onCallRemoved: "+call.toString());
+            TestCallList.getInstance().removeCall(call);
         }
     };
 
@@ -48,7 +52,7 @@
         Log.i(TAG, "onPhoneCreated");
         mPhone = phone;
         mPhone.addListener(mPhoneListener);
-
+        TestCallList.getInstance().clearCalls();
     }
 
     @Override
@@ -56,5 +60,6 @@
         Log.i(TAG, "onPhoneDestroyed");
         mPhone.removeListener(mPhoneListener);
         mPhone = null;
+        TestCallList.getInstance().clearCalls();
     }
 }
diff --git a/tests/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java b/testapps/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java
similarity index 73%
rename from tests/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java
rename to testapps/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java
index 649d0c0..10e3b79 100644
--- a/tests/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestManagedVideoProvider.java
@@ -16,33 +16,34 @@
 
 package com.android.server.telecom.testapps;
 
-import android.telecom.CameraCapabilities;
+import android.net.Uri;
 import android.telecom.Connection;
 import android.telecom.RemoteConnection;
 import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
 import android.view.Surface;
 
 public class TestManagedVideoProvider extends Connection.VideoProvider {
 
-    private final RemoteConnection.VideoProvider.Listener mRemoteListener =
-            new RemoteConnection.VideoProvider.Listener() {
+    private final RemoteConnection.VideoProvider.Callback mRemoteCallback =
+            new RemoteConnection.VideoProvider.Callback() {
         @Override
-        public void onReceiveSessionModifyRequest(RemoteConnection.VideoProvider rvp,
+        public void onSessionModifyRequestReceived(RemoteConnection.VideoProvider rvp,
                 VideoProfile videoProfile) {
-            super.onReceiveSessionModifyRequest(rvp, videoProfile);
+            super.onSessionModifyRequestReceived(rvp, videoProfile);
         }
 
         @Override
-        public void onReceiveSessionModifyResponse(RemoteConnection.VideoProvider rvp,
-        int status,
-        VideoProfile requestedProfile, VideoProfile responseProfile) {
-            super.onReceiveSessionModifyResponse(rvp, status, requestedProfile,
+        public void onSessionModifyResponseReceived(RemoteConnection.VideoProvider rvp,
+                int status,
+                VideoProfile requestedProfile, VideoProfile responseProfile) {
+            super.onSessionModifyResponseReceived(rvp, status, requestedProfile,
                     responseProfile);
         }
 
         @Override
-        public void onHandleCallSessionEvent(RemoteConnection.VideoProvider rvp, int event) {
-            super.onHandleCallSessionEvent(rvp, event);
+        public void onCallSessionEvent(RemoteConnection.VideoProvider rvp, int event) {
+            super.onCallSessionEvent(rvp, event);
         }
 
         @Override
@@ -52,7 +53,7 @@
         }
 
         @Override
-        public void onCallDataUsageChanged(RemoteConnection.VideoProvider rvp, int dataUsage) {
+        public void onCallDataUsageChanged(RemoteConnection.VideoProvider rvp, long dataUsage) {
             super.onCallDataUsageChanged(rvp, dataUsage);
         }
 
@@ -67,7 +68,7 @@
 
     public TestManagedVideoProvider(RemoteConnection.VideoProvider remoteVideoProvider) {
         mRemoteVideoProvider = remoteVideoProvider;
-        mRemoteVideoProvider.addListener(mRemoteListener);
+        mRemoteVideoProvider.registerCallback(mRemoteCallback);
     }
 
     @Override
@@ -96,8 +97,9 @@
     }
 
     @Override
-    public void onSendSessionModifyRequest(VideoProfile requestProfile) {
-        mRemoteVideoProvider.sendSessionModifyRequest(requestProfile);
+    public void onSendSessionModifyRequest(VideoProfile fromProfile,
+            VideoProfile requestProfile) {
+        mRemoteVideoProvider.sendSessionModifyRequest(fromProfile, requestProfile);
     }
 
     @Override
@@ -116,7 +118,7 @@
     }
 
     @Override
-    public void onSetPauseImage(String uri) {
+    public void onSetPauseImage(Uri uri) {
         mRemoteVideoProvider.setPauseImage(uri);
     }
 }
diff --git a/tests/src/com/android/server/telecom/testapps/TestVideoProvider.java b/testapps/src/com/android/server/telecom/testapps/TestVideoProvider.java
similarity index 88%
rename from tests/src/com/android/server/telecom/testapps/TestVideoProvider.java
rename to testapps/src/com/android/server/telecom/testapps/TestVideoProvider.java
index 494eacc..e9db5d3 100644
--- a/tests/src/com/android/server/telecom/testapps/TestVideoProvider.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestVideoProvider.java
@@ -19,7 +19,8 @@
 import com.android.ex.camera2.blocking.BlockingCameraManager;
 import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
-import com.android.server.telecom.tests.R;
+import com.android.server.telecom.testapps.R;
+import com.android.server.telecom.testapps.TestConnectionService.TestConnection;
 
 import android.content.Context;
 import android.graphics.SurfaceTexture;
@@ -33,10 +34,11 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.MediaPlayer;
+import android.net.Uri;
 import android.os.Handler;
-import android.telecom.CameraCapabilities;
 import android.telecom.Connection;
 import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Size;
@@ -52,6 +54,7 @@
  * Implements the VideoCallProvider.
  */
 public class TestVideoProvider extends Connection.VideoProvider {
+    private TestConnection mConnection;
     private CameraCapabilities mCameraCapabilities;
     private Random random;
     private Surface mDisplaySurface;
@@ -65,11 +68,14 @@
     private CameraCaptureSession mCameraSession;
     private CameraThread mLooperThread;
 
+    private final Handler mHandler = new Handler();
+
     private String mCameraId;
 
     private static final long SESSION_TIMEOUT_MS = 2000;
 
-    public TestVideoProvider(Context context) {
+    public TestVideoProvider(Context context, TestConnection connection) {
+        mConnection = connection;
         mContext = context;
         random = new Random();
         mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
@@ -140,15 +146,23 @@
      * the response back via the CallVideoClient.
      */
     @Override
-    public void onSendSessionModifyRequest(VideoProfile requestProfile) {
+    public void onSendSessionModifyRequest(final VideoProfile fromProfile,
+            final VideoProfile requestProfile) {
         log("Sent session modify request");
 
-        VideoProfile responseProfile = new VideoProfile(
-                requestProfile.getVideoState(), requestProfile.getQuality());
-        receiveSessionModifyResponse(
-                SESSION_MODIFY_REQUEST_SUCCESS,
-                requestProfile,
-                responseProfile);
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                final VideoProfile responseProfile = new VideoProfile(
+                        requestProfile.getVideoState(), requestProfile.getQuality());
+                mConnection.setVideoState(requestProfile.getVideoState());
+
+                receiveSessionModifyResponse(
+                        SESSION_MODIFY_REQUEST_SUCCESS,
+                        requestProfile,
+                        responseProfile);
+            }
+        }, 2000);
     }
 
     @Override
@@ -171,7 +185,7 @@
     @Override
     public void onRequestConnectionDataUsage() {
         log("Requested connection data usage");
-        int dataUsageKb = (10 *1024) + random.nextInt(50 * 1024);
+        long dataUsageKb = (10 *1024) + random.nextInt(50 * 1024);
         changeCallDataUsage(dataUsageKb);
     }
 
@@ -179,7 +193,7 @@
      * We do not have a need to set a paused image.
      */
     @Override
-    public void onSetPauseImage(String uri) {
+    public void onSetPauseImage(Uri uri) {
         // Not implemented.
     }
 
@@ -327,7 +341,7 @@
                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
             Size previewSize = map.getOutputSizes(SurfaceTexture.class)[0];
 
-            mCameraCapabilities = new CameraCapabilities(true, 1.0f, previewSize.getWidth(),
+            mCameraCapabilities = new CameraCapabilities(previewSize.getWidth(),
                     previewSize.getHeight());
         }
     }
diff --git a/tests/Android.mk b/tests/Android.mk
index f293b80..a802768 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -19,17 +19,29 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
         android-ex-camera2 \
+        android-support-v4 \
         guava \
-        mockito-target \
+        mockito-target
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+        $(call all-java-files-under, src) \
+        $(call all-java-files-under, ../src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_PACKAGE_NAME := TelecomTests
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/res \
+    $(LOCAL_PATH)/../res
+
+LOCAL_JAVA_LIBRARIES := \
+        android.test.runner \
+        telephony-common
+
+LOCAL_AAPT_FLAGS := \
+    --auto-add-overlay \
+    --extra-packages com.android.server.telecom
+
+LOCAL_PACKAGE_NAME := TelecomUnitTests
 LOCAL_CERTIFICATE := platform
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_INSTRUMENTATION_FOR := Telecom
-
 include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index e987dee..6a08c63 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -19,103 +19,17 @@
           package="com.android.server.telecom.tests"
           android:debuggable="true">
 
-    <uses-permission android:name="android.permission.CAMERA" />
-    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
-    <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
-    <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
-    <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
+    <!-- TODO: Needed because we call BluetoothAdapter.getDefaultAdapter() statically, and
+         BluetoothAdapter is a final class. -->
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+
+    <!-- TODO: Needed because we call ActivityManager.getCurrentUser() statically. -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
 
     <application android:label="@string/app_name"
                  android:debuggable="true">
         <uses-library android:name="android.test.runner" />
-
-        <!-- Miscellaneous telecom app-related test activities. -->
-
-        <service android:name="com.android.server.telecom.testapps.TestConnectionService"
-                 android:permission="android.permission.BIND_CONNECTION_SERVICE" >
-            <intent-filter>
-                <action android:name="android.telecom.ConnectionService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="com.android.server.telecom.tests.MockConnectionService"
-                 android:permission="android.permission.BIND_CONNECTION_SERVICE" >
-            <intent-filter>
-                <action android:name="android.telecom.ConnectionService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="com.android.server.telecom.testapps.TestConnectionManager"
-                 android:permission="android.permission.BIND_CONNECTION_SERVICE" >
-            <intent-filter>
-                <action android:name="android.telecom.ConnectionService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="com.android.server.telecom.testapps.TestInCallServiceImpl"
-                 android:process="com.android.server.telecom.testapps.TestInCallService"
-                 android:permission="android.permission.BIND_INCALL_SERVICE" >
-            <intent-filter>
-                <action android:name="android.telecom.InCallService"/>
-            </intent-filter>
-        </service>
-
-        <activity android:name="com.android.server.telecom.testapps.TestCallActivity"
-                android:label="@string/testCallActivityLabel">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.telecom.testapps.ACTION_START_INCOMING_CALL" />
-                <action android:name="android.telecom.testapps.ACTION_NEW_UNKNOWN_CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="tel" />
-                <data android:scheme="sip" />
-            </intent-filter>
-        </activity>
-
-        <receiver android:name="com.android.server.telecom.testapps.CallNotificationReceiver"
-                android:exported="false">
-            <intent-filter>
-                <action android:name="com.android.server.telecom.testapps.ACTION_CALL_SERVICE_EXIT" />
-            </intent-filter>
-        </receiver>
-
-        <activity android:name="com.android.server.telecom.testapps.TestDialerActivity"
-                android:label="@string/testDialerActivityLabel"
-                android:process="com.android.server.telecom.testapps.TestInCallService">
-            <intent-filter>
-                <action android:name="android.intent.action.DIAL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.BROWSABLE" />
-                <data android:mimeType="vnd.android.cursor.item/phone" />
-                <data android:mimeType="vnd.android.cursor.item/person" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.DIAL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.BROWSABLE" />
-                <data android:scheme="voicemail" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.DIAL" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.VIEW" />
-                <action android:name="android.intent.action.DIAL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.BROWSABLE" />
-                <data android:scheme="tel" />
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
     </application>
 
     <!--
@@ -130,7 +44,7 @@
                                 -e com.android.server.telecom.tests.unit.FooUnitTest
     -->
     <instrumentation android:name="android.test.InstrumentationTestRunner"
-            android:targetPackage="com.android.server.telecom"
-            android:label="Telecomm application tests."
+            android:targetPackage="com.android.server.telecom.tests"
+            android:label="Telecomm application tests"
             android:debuggable="true"/>
 </manifest>
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 91d8628..0a6f5c4 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -16,17 +16,5 @@
 
 <resources>
     <!-- Application label -->
-    <string name="app_name">TelecommTests</string>
-
-    <!-- String for the TestCallActivity -->
-    <string name="testCallActivityLabel">Test Connection Service App</string>
-
-    <!-- String for the TestDialerActivity -->
-    <string name="testDialerActivityLabel">Test Dialer</string>
-
-    <!-- String for button in TestDialerActivity that reassigns the default Dialer -->
-    <string name="defaultDialerButton">Default dialer request</string>
-
-    <!-- String for button in TestDialerActivity that places a test call -->
-    <string name="placeCallButton">Place call</string>
+    <string name="app_name">Telecom Unit Tests</string>
 </resources>
diff --git a/tests/src/com/android/server/telecom/testapps/TestDialerActivity.java b/tests/src/com/android/server/telecom/testapps/TestDialerActivity.java
deleted file mode 100644
index 7a9ed3f..0000000
--- a/tests/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.android.server.telecom.testapps;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.EditText;
-
-import com.android.server.telecom.tests.R;
-
-public class TestDialerActivity extends Activity {
-    private EditText mNumberView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.testdialer_main);
-        findViewById(R.id.set_default_button).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setDefault();
-            }
-        });
-        findViewById(R.id.place_call_button).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                placeCall();
-            }
-        });
-
-        mNumberView = (EditText) findViewById(R.id.number);
-        updateEditTextWithNumber();
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        updateEditTextWithNumber();
-    }
-
-    private void updateEditTextWithNumber() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            mNumberView.setText(intent.getDataString());
-        }
-    }
-
-    private void setDefault() {
-        // TODO: Send a request to become the default dialer application
-    }
-
-    private void placeCall() {
-        // TODO: Place a call with the number entered in the number field
-    }
-}
diff --git a/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java b/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java
new file mode 100644
index 0000000..1ebf170
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.CallerInfoAsyncQuery;
+import com.android.server.telecom.CallerInfoAsyncQueryFactory;
+import com.android.server.telecom.Log;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Controls a test {@link CallerInfoAsyncQueryFactory} to abstract away the asynchronous retrieval
+ * of caller information from the Android contacts database.
+ */
+public class CallerInfoAsyncQueryFactoryFixture implements
+        TestFixture<CallerInfoAsyncQueryFactory> {
+
+    static class Request {
+        int mToken;
+        Object mCookie;
+        CallerInfoAsyncQuery.OnQueryCompleteListener mListener;
+        void reply() {
+            mListener.onQueryComplete(mToken, mCookie, new CallerInfo());
+        }
+    }
+
+    CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory = new CallerInfoAsyncQueryFactory() {
+        @Override
+        public CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+                CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
+            Request r = new Request();
+            r.mToken = token;
+            r.mCookie = cookie;
+            r.mListener = listener;
+            mRequests.add(r);
+            return null;
+        }
+    };
+
+    final List<Request> mRequests = new ArrayList<>();
+
+    public CallerInfoAsyncQueryFactoryFixture() throws Exception {
+        Log.i(this, "Creating ...");
+    }
+
+    @Override
+    public CallerInfoAsyncQueryFactory getTestDouble() {
+        return mCallerInfoAsyncQueryFactory;
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
new file mode 100644
index 0000000..9f66f00
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import com.android.internal.telecom.IConnectionService;
+import com.android.internal.telecom.IInCallService;
+import com.android.server.telecom.Log;
+
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IInterface;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.CallAudioState;
+import android.telecom.ConnectionService;
+import android.telecom.InCallService;
+import android.telecom.PhoneAccount;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContext;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+/**
+ * Controls a test {@link Context} as would be provided by the Android framework to an
+ * {@code Activity}, {@code Service} or other system-instantiated component.
+ *
+ * The {@link Context} created by this object is "hollow" but its {@code applicationContext}
+ * property points to an application context implementing all the nontrivial functionality.
+ */
+public class ComponentContextFixture implements TestFixture<Context> {
+
+    public class FakeApplicationContext extends MockContext {
+        @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        @Override
+        public File getFilesDir() {
+            try {
+                return File.createTempFile("temp", "temp").getParentFile();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public boolean bindServiceAsUser(
+                Intent serviceIntent,
+                ServiceConnection connection,
+                int flags,
+                UserHandle userHandle) {
+            // TODO: Implement "as user" functionality
+            return bindService(serviceIntent, connection, flags);
+        }
+
+        @Override
+        public boolean bindService(
+                Intent serviceIntent,
+                ServiceConnection connection,
+                int flags) {
+            if (mServiceByServiceConnection.containsKey(connection)) {
+                throw new RuntimeException("ServiceConnection already bound: " + connection);
+            }
+            IInterface service = mServiceByComponentName.get(serviceIntent.getComponent());
+            if (service == null) {
+                throw new RuntimeException("ServiceConnection not found: "
+                        + serviceIntent.getComponent());
+            }
+            mServiceByServiceConnection.put(connection, service);
+            connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder());
+            return true;
+        }
+
+        @Override
+        public void unbindService(
+                ServiceConnection connection) {
+            IInterface service = mServiceByServiceConnection.remove(connection);
+            if (service == null) {
+                throw new RuntimeException("ServiceConnection not found: " + connection);
+            }
+            connection.onServiceDisconnected(mComponentNameByService.get(service));
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            switch (name) {
+                case Context.AUDIO_SERVICE:
+                    return mAudioManager;
+                case Context.TELEPHONY_SERVICE:
+                    return mTelephonyManager;
+                case Context.APP_OPS_SERVICE:
+                    return mAppOpsManager;
+                case Context.NOTIFICATION_SERVICE:
+                    return mNotificationManager;
+                case Context.STATUS_BAR_SERVICE:
+                    return mStatusBarManager;
+                case Context.USER_SERVICE:
+                    return mUserManager;
+                case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
+                    return mSubscriptionManager;
+                default:
+                    return null;
+            }
+        }
+
+        @Override
+        public int getUserId() {
+            return 0;
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResources;
+        }
+
+        @Override
+        public String getOpPackageName() {
+            return "test";
+        }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return new ContentResolver(mApplicationContextSpy) {
+                @Override
+                protected IContentProvider acquireProvider(Context c, String name) {
+                    Log.i(this, "acquireProvider %s", name);
+                    return mock(IContentProvider.class);
+                }
+
+                @Override
+                public boolean releaseProvider(IContentProvider icp) {
+                    return true;
+                }
+
+                @Override
+                protected IContentProvider acquireUnstableProvider(Context c, String name) {
+                    Log.i(this, "acquireUnstableProvider %s", name);
+                    return mock(IContentProvider.class);
+                }
+
+                @Override
+                public boolean releaseUnstableProvider(IContentProvider icp) {
+                    return false;
+                }
+
+                @Override
+                public void unstableProviderDied(IContentProvider icp) {
+                }
+            };
+        }
+
+        @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+            // TODO -- this is called by WiredHeadsetManager!!!
+            return null;
+        }
+
+        @Override
+        public void sendBroadcast(Intent intent) {
+            // TODO -- need to ensure this is captured
+        }
+
+        @Override
+        public void sendBroadcast(Intent intent, String receiverPermission) {
+            // TODO -- need to ensure this is captured
+        }
+
+        @Override
+        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+                String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
+                int initialCode, String initialData, Bundle initialExtras) {
+            // TODO -- need to ensure this is captured
+        }
+
+        @Override
+        public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+                String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+                Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        }
+
+        @Override
+        public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+                throws PackageManager.NameNotFoundException {
+            return this;
+        }
+    };
+
+    public class FakeAudioManager extends AudioManager {
+
+        private boolean mMute = false;
+        private boolean mSpeakerphoneOn = false;
+        private int mMode = AudioManager.MODE_NORMAL;
+
+        public FakeAudioManager(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void setMicrophoneMute(boolean value) {
+            mMute = value;
+        }
+
+        @Override
+        public boolean isMicrophoneMute() {
+            return mMute;
+        }
+
+        @Override
+        public void setSpeakerphoneOn(boolean value) {
+            mSpeakerphoneOn = value;
+        }
+
+        @Override
+        public boolean isSpeakerphoneOn() {
+            return mSpeakerphoneOn;
+        }
+
+        @Override
+        public void setMode(int mode) {
+            mMode = mode;
+        }
+
+        @Override
+        public int getMode() {
+            return mMode;
+        }
+    }
+
+    private final Multimap<String, ComponentName> mComponentNamesByAction =
+            ArrayListMultimap.create();
+    private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
+    private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
+    private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
+    private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
+
+    private final Context mContext = new MockContext() {
+        @Override
+        public Context getApplicationContext() {
+            return mApplicationContextSpy;
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResources;
+        }
+    };
+
+    // The application context is the most important object this class provides to the system
+    // under test.
+    private final Context mApplicationContext = new FakeApplicationContext();
+
+    // We then create a spy on the application context allowing standard Mockito-style
+    // when(...) logic to be used to add specific little responses where needed.
+
+    private final Resources mResources = mock(Resources.class);
+    private final Context mApplicationContextSpy = spy(mApplicationContext);
+    private final PackageManager mPackageManager = mock(PackageManager.class);
+    private final AudioManager mAudioManager = spy(new FakeAudioManager(mContext));
+    private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
+    private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
+    private final NotificationManager mNotificationManager = mock(NotificationManager.class);
+    private final UserManager mUserManager = mock(UserManager.class);
+    private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
+    private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
+    private final Configuration mResourceConfiguration = new Configuration();
+
+    public ComponentContextFixture() {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
+        mResourceConfiguration.setLocale(Locale.TAIWAN);
+
+        // TODO: Move into actual tests
+        when(mAudioManager.isWiredHeadsetOn()).thenReturn(false);
+
+        doAnswer(new Answer<List<ResolveInfo>>() {
+            @Override
+            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+                return doQueryIntentServices(
+                        (Intent) invocation.getArguments()[0],
+                        (Integer) invocation.getArguments()[1]);
+            }
+        }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt());
+
+        doAnswer(new Answer<List<ResolveInfo>>() {
+            @Override
+            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+                return doQueryIntentServices(
+                        (Intent) invocation.getArguments()[0],
+                        (Integer) invocation.getArguments()[1]);
+            }
+        }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
+
+        when(mTelephonyManager.getSubIdForPhoneAccount((PhoneAccount) any())).thenReturn(1);
+
+        doAnswer(new Answer<Void>(){
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                return null;
+            }
+        }).when(mAppOpsManager).checkPackage(anyInt(), anyString());
+
+        when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
+
+        when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L);
+    }
+
+    @Override
+    public Context getTestDouble() {
+        return mContext;
+    }
+
+    public void addConnectionService(
+            ComponentName componentName,
+            IConnectionService service)
+            throws Exception {
+        addService(ConnectionService.SERVICE_INTERFACE, componentName, service);
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = android.Manifest.permission.BIND_CONNECTION_SERVICE;
+        serviceInfo.packageName = componentName.getPackageName();
+        serviceInfo.name = componentName.getClassName();
+        mServiceInfoByComponentName.put(componentName, serviceInfo);
+    }
+
+    public void addInCallService(
+            ComponentName componentName,
+            IInCallService service)
+            throws Exception {
+        addService(InCallService.SERVICE_INTERFACE, componentName, service);
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = android.Manifest.permission.BIND_INCALL_SERVICE;
+        serviceInfo.packageName = componentName.getPackageName();
+        serviceInfo.name = componentName.getClassName();
+        mServiceInfoByComponentName.put(componentName, serviceInfo);
+    }
+
+    public void putResource(int id, String value) {
+        when(mResources.getString(eq(id))).thenReturn(value);
+    }
+
+    private void addService(String action, ComponentName name, IInterface service) {
+        mComponentNamesByAction.put(action, name);
+        mServiceByComponentName.put(name, service);
+        mComponentNameByService.put(service, name);
+    }
+
+    private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
+        List<ResolveInfo> result = new ArrayList<>();
+        for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
+            ResolveInfo resolveInfo = new ResolveInfo();
+            resolveInfo.serviceInfo = mServiceInfoByComponentName.get(componentName);
+            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
new file mode 100644
index 0000000..964f014
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.internal.telecom.IConnectionService;
+import com.android.internal.telecom.IConnectionServiceAdapter;
+import com.android.internal.telecom.IVideoProvider;
+import com.android.internal.telecom.RemoteServiceCallback;
+import com.android.server.telecom.Log;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.telecom.CallAudioState;
+import android.telecom.Connection;
+import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
+import android.telecom.ParcelableConference;
+import android.telecom.ParcelableConnection;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.StatusHints;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Matchers.any;
+
+/**
+ * Controls a test {@link IConnectionService} as would be provided by a source of connectivity
+ * to the Telecom framework.
+ */
+public class ConnectionServiceFixture implements TestFixture<IConnectionService> {
+
+    public class FakeConnectionService extends IConnectionService.Stub {
+
+        @Override
+        public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter)
+                throws RemoteException {
+            if (!mConnectionServiceAdapters.add(adapter)) {
+                throw new RuntimeException("Adapter already added: " + adapter);
+            }
+        }
+
+        @Override
+        public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)
+                throws RemoteException {
+            if (!mConnectionServiceAdapters.remove(adapter)) {
+                throw new RuntimeException("Adapter never added: " + adapter);
+            }
+        }
+
+        @Override
+        public void createConnection(PhoneAccountHandle connectionManagerPhoneAccount,
+                String id,
+                ConnectionRequest request, boolean isIncoming, boolean isUnknown)
+                throws RemoteException {
+            Log.i(ConnectionServiceFixture.this, "xoxox createConnection --> " + id);
+
+            if (mConnectionById.containsKey(id)) {
+                throw new RuntimeException("Connection already exists: " + id);
+            }
+            mLatestConnectionId = id;
+            ConnectionInfo c = new ConnectionInfo();
+            c.connectionManagerPhoneAccount = connectionManagerPhoneAccount;
+            c.id = id;
+            c.request = request;
+            c.isIncoming = isIncoming;
+            c.isUnknown = isUnknown;
+            c.capabilities |= Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD;
+            mConnectionById.put(id, c);
+        }
+
+        @Override
+        public void abort(String callId) throws RemoteException { }
+
+        @Override
+        public void answerVideo(String callId, int videoState) throws RemoteException { }
+
+        @Override
+        public void answer(String callId) throws RemoteException { }
+
+        @Override
+        public void reject(String callId) throws RemoteException { }
+
+        @Override
+        public void disconnect(String callId) throws RemoteException { }
+
+        @Override
+        public void hold(String callId) throws RemoteException { }
+
+        @Override
+        public void unhold(String callId) throws RemoteException { }
+
+        @Override
+        public void onCallAudioStateChanged(String activeCallId, CallAudioState audioState)
+                throws RemoteException { }
+
+        @Override
+        public void playDtmfTone(String callId, char digit) throws RemoteException { }
+
+        @Override
+        public void stopDtmfTone(String callId) throws RemoteException { }
+
+        @Override
+        public void conference(String conferenceCallId, String callId) throws RemoteException { }
+
+        @Override
+        public void splitFromConference(String callId) throws RemoteException { }
+
+        @Override
+        public void mergeConference(String conferenceCallId) throws RemoteException { }
+
+        @Override
+        public void swapConference(String conferenceCallId) throws RemoteException { }
+
+        @Override
+        public void onPostDialContinue(String callId, boolean proceed) throws RemoteException { }
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public IInterface queryLocalInterface(String descriptor) {
+            return this;
+        }
+    };
+
+    private IConnectionService.Stub mConnectionService = new FakeConnectionService();
+    private IConnectionService.Stub mConnectionServiceSpy = Mockito.spy(mConnectionService);
+
+    public class ConnectionInfo {
+        PhoneAccountHandle connectionManagerPhoneAccount;
+        String id;
+        boolean ringing;
+        ConnectionRequest request;
+        boolean isIncoming;
+        boolean isUnknown;
+        int state;
+        int addressPresentation;
+        int capabilities;
+        StatusHints statusHints;
+        DisconnectCause disconnectCause;
+        String conferenceId;
+        String callerDisplayName;
+        int callerDisplayNamePresentation;
+        final List<String> conferenceableConnectionIds = new ArrayList<>();
+        IVideoProvider videoProvider;
+        int videoState;
+        boolean isVoipAudioMode;
+        Bundle extras;
+    }
+
+    public class ConferenceInfo {
+        PhoneAccountHandle phoneAccount;
+        int state;
+        int capabilities;
+        final List<String> connectionIds = new ArrayList<>();
+        IVideoProvider videoProvider;
+        int videoState;
+        long connectTimeMillis;
+        StatusHints statusHints;
+        Bundle extras;
+    }
+
+    public String mLatestConnectionId;
+    public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>();
+    public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>();
+    public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>();
+    public final List<ComponentName> mRemoteConnectionServiceNames = new ArrayList<>();
+    public final List<IBinder> mRemoteConnectionServices = new ArrayList<>();
+
+    public ConnectionServiceFixture() throws Exception { }
+
+    @Override
+    public IConnectionService getTestDouble() {
+        return mConnectionServiceSpy;
+    }
+
+    public void sendHandleCreateConnectionComplete(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.handleCreateConnectionComplete(
+                    id,
+                    mConnectionById.get(id).request,
+                    parcelable(mConnectionById.get(id)));
+        }
+    }
+
+    public void sendSetActive(String id) throws Exception {
+        mConnectionById.get(id).state = Connection.STATE_ACTIVE;
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setActive(id);
+        }
+    }
+
+    public void sendSetRinging(String id) throws Exception {
+        mConnectionById.get(id).state = Connection.STATE_RINGING;
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setRinging(id);
+        }
+    }
+
+    public void sendSetDialing(String id) throws Exception {
+        mConnectionById.get(id).state = Connection.STATE_DIALING;
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setDialing(id);
+        }
+    }
+
+    public void sendSetDisconnected(String id, int disconnectCause) throws Exception {
+        mConnectionById.get(id).state = Connection.STATE_DISCONNECTED;
+        mConnectionById.get(id).disconnectCause = new DisconnectCause(disconnectCause);
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setDisconnected(id, mConnectionById.get(id).disconnectCause);
+        }
+    }
+
+    public void sendSetOnHold(String id) throws Exception {
+        mConnectionById.get(id).state = Connection.STATE_HOLDING;
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setOnHold(id);
+        }
+    }
+
+    public void sendSetRingbackRequested(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setRingbackRequested(id, mConnectionById.get(id).ringing);
+        }
+    }
+
+    public void sendSetConnectionCapabilities(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setConnectionCapabilities(id, mConnectionById.get(id).capabilities);
+        }
+    }
+
+    public void sendSetIsConferenced(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setIsConferenced(id, mConnectionById.get(id).conferenceId);
+        }
+    }
+
+    public void sendAddConferenceCall(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.addConferenceCall(id, parcelable(mConferenceById.get(id)));
+        }
+    }
+
+    public void sendRemoveCall(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.removeCall(id);
+        }
+    }
+
+    public void sendOnPostDialWait(String id, String remaining) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.onPostDialWait(id, remaining);
+        }
+    }
+
+    public void sendOnPostDialChar(String id, char nextChar) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.onPostDialChar(id, nextChar);
+        }
+    }
+
+    public void sendQueryRemoteConnectionServices() throws Exception {
+        mRemoteConnectionServices.clear();
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
+                @Override
+                public void onError() throws RemoteException {
+                    throw new RuntimeException();
+                }
+
+                @Override
+                public void onResult(
+                        List<ComponentName> names,
+                        List<IBinder> services)
+                        throws RemoteException {
+                    TestCase.assertEquals(names.size(), services.size());
+                    mRemoteConnectionServiceNames.addAll(names);
+                    mRemoteConnectionServices.addAll(services);
+                }
+
+                @Override
+                public IBinder asBinder() {
+                    return this;
+                }
+            });
+        }
+    }
+
+    public void sendSetVideoProvider(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setVideoProvider(id, mConnectionById.get(id).videoProvider);
+        }
+    }
+
+    public void sendSetVideoState(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setVideoState(id, mConnectionById.get(id).videoState);
+        }
+    }
+
+    public void sendSetIsVoipAudioMode(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setIsVoipAudioMode(id, mConnectionById.get(id).isVoipAudioMode);
+        }
+    }
+
+    public void sendSetStatusHints(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setStatusHints(id, mConnectionById.get(id).statusHints);
+        }
+    }
+
+    public void sendSetAddress(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setAddress(
+                    id,
+                    mConnectionById.get(id).request.getAddress(),
+                    mConnectionById.get(id).addressPresentation);
+        }
+    }
+
+    public void sendSetCallerDisplayName(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setCallerDisplayName(
+                    id,
+                    mConnectionById.get(id).callerDisplayName,
+                    mConnectionById.get(id).callerDisplayNamePresentation);
+        }
+    }
+
+    public void sendSetConferenceableConnections(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.setConferenceableConnections(id, mConnectionById.get(id).conferenceableConnectionIds);
+        }
+    }
+
+    public void sendAddExistingConnection(String id) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.addExistingConnection(id, parcelable(mConnectionById.get(id)));
+        }
+    }
+
+    private ParcelableConference parcelable(ConferenceInfo c) {
+        return new ParcelableConference(
+                c.phoneAccount,
+                c.state,
+                c.capabilities,
+                c.connectionIds,
+                c.videoProvider,
+                c.videoState,
+                c.connectTimeMillis,
+                c.statusHints,
+                c.extras);
+    }
+
+    private ParcelableConnection parcelable(ConnectionInfo c) {
+        return new ParcelableConnection(
+                c.request.getAccountHandle(),
+                c.state,
+                c.capabilities,
+                c.request.getAddress(),
+                c.addressPresentation,
+                c.callerDisplayName,
+                c.callerDisplayNamePresentation,
+                c.videoProvider,
+                c.videoState,
+                false, /* ringback requested */
+                false, /* voip audio mode */
+                0, /* Connect Time for conf call on this connection */
+                c.statusHints,
+                c.disconnectCause,
+                c.conferenceableConnectionIds,
+                c.extras);
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
new file mode 100644
index 0000000..2dd4b97
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.internal.telecom.IInCallAdapter;
+import com.android.internal.telecom.IInCallService;
+
+import org.mockito.Mockito;
+
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.telecom.AudioState;
+import android.telecom.CallAudioState;
+import android.telecom.ParcelableCall;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Controls a test {@link IInCallService} as would be provided by an InCall UI on a system.
+ */
+public class InCallServiceFixture implements TestFixture<IInCallService> {
+
+    public String mLatestCallId;
+    public IInCallAdapter mInCallAdapter;
+    public CallAudioState mCallAudioState;
+    public final Map<String, ParcelableCall> mCallById = new HashMap<>();
+    public final Map<String, String> mPostDialById = new HashMap<>();
+    public final Map<String, String> mPostDialWaitById = new HashMap<>();
+    public boolean mBringToForeground;
+    public boolean mShowDialpad;
+    public boolean mCanAddCall;
+
+    public class FakeInCallService extends IInCallService.Stub {
+        @Override
+        public void setInCallAdapter(IInCallAdapter inCallAdapter) throws RemoteException {
+            if (mInCallAdapter != null && inCallAdapter != null) {
+                throw new RuntimeException("Adapter is already set");
+            }
+            if (mInCallAdapter == null && inCallAdapter == null) {
+                throw new RuntimeException("Adapter was never set");
+            }
+            mInCallAdapter = inCallAdapter;
+        }
+
+        @Override
+        public void addCall(ParcelableCall call) throws RemoteException {
+            if (mCallById.containsKey(call.getId())) {
+                throw new RuntimeException("Call " + call.getId() + " already added");
+            }
+            mCallById.put(call.getId(), call);
+            mLatestCallId = call.getId();
+        }
+
+        @Override
+        public void updateCall(ParcelableCall call) throws RemoteException {
+            if (!mCallById.containsKey(call.getId())) {
+                throw new RuntimeException("Call " + call.getId() + " not added yet");
+            }
+            mCallById.put(call.getId(), call);
+            mLatestCallId = call.getId();
+        }
+
+        @Override
+        public void setPostDial(String callId, String remaining) throws RemoteException {
+            mPostDialWaitById.remove(callId);
+            mPostDialById.put(callId, remaining);
+        }
+
+        @Override
+        public void setPostDialWait(String callId, String remaining) throws RemoteException {
+            mPostDialById.remove(callId);
+            mPostDialWaitById.put(callId, remaining);
+        }
+
+        @Override
+        public void onCallAudioStateChanged(CallAudioState audioState) throws RemoteException {
+            mCallAudioState = audioState;
+        }
+
+        @Override
+        public void bringToForeground(boolean showDialpad) throws RemoteException {
+            mBringToForeground = true;
+            mShowDialpad = showDialpad;
+        }
+
+        @Override
+        public void onCanAddCallChanged(boolean canAddCall) throws RemoteException {
+            mCanAddCall = canAddCall;
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public IInterface queryLocalInterface(String descriptor) {
+            return this;
+        }
+    }
+
+    private IInCallService.Stub mInCallServiceFake = new FakeInCallService();
+    private IInCallService.Stub mInCallServiceSpy = Mockito.spy(mInCallServiceFake);
+
+    public InCallServiceFixture() throws Exception { }
+
+    @Override
+    public IInCallService getTestDouble() {
+        return mInCallServiceSpy;
+    }
+
+    public ParcelableCall getCall(String id) {
+        return mCallById.get(id);
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/unit/InCallWakeLockControllerTest.java b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
similarity index 71%
rename from tests/src/com/android/server/telecom/tests/unit/InCallWakeLockControllerTest.java
rename to tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
index 5af9440..bc294aa 100644
--- a/tests/src/com/android/server/telecom/tests/unit/InCallWakeLockControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
@@ -14,27 +14,32 @@
  * limitations under the License.
  */
 
-package com.android.server.telecom;
+package com.android.server.telecom.tests;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.never;
 
 import android.content.Context;
 import android.os.PowerManager;
-import android.telecom.CallState;
-import android.test.AndroidTestCase;
 
 import com.android.server.telecom.Call;
+import com.android.server.telecom.CallState;
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.InCallWakeLockController;
 
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
-public class InCallWakeLockControllerTest extends AndroidTestCase {
+/**
+ * TODO: The tests here are disabled because they depend on classes {@code PowerManager} and
+ * {@code PowerManager.WakeLock}, which are both {@code final} and therefore cannot easily be
+ * mocked.
+ *
+ * At the moment, we are using an {@link com.android.server.telecom.InCallWakeLockControllerFactory}
+ * in the system under test to abstract out this class, and are assuming it's simple enough that it
+ * is not the highest priority to test.
+ */
+public class InCallWakeLockControllerTest extends TelecomTestCase {
 
     @Mock Context mContext;
     @Mock PowerManager mPowerManager;
@@ -46,26 +51,30 @@
 
     @Override
     public void setUp() throws Exception {
+        /*
         super.setUp();
-        MockitoAnnotations.initMocks(this);
 
         when(mContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
         when(mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "InCallWakeLockController"))
                 .thenReturn(mWakeLock);
         mInCallWakeLockController = new InCallWakeLockController(mContext, mCallsManager);
+        */
     }
 
     @Override
-    public void tearDown() {
+    public void tearDown() throws Exception {
+        /*
+        super.tearDown();
+        */
     }
 
-    public void test_RingingCallAdded() throws Exception {
+    public void DONT_test_RingingCallAdded() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(mCall);
         mInCallWakeLockController.onCallAdded(mCall);
         verify(mWakeLock).acquire();
     }
 
-    public void test_NonRingingCallAdded() throws Exception {
+    public void DONT_test_NonRingingCallAdded() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLock.isHeld()).thenReturn(false);
 
@@ -73,13 +82,13 @@
         verify(mWakeLock, never()).acquire();
     }
 
-    public void test_RingingCallTransition() throws Exception {
+    public void DONT_test_RingingCallTransition() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(mCall);
         mInCallWakeLockController.onCallStateChanged(mCall, CallState.NEW, CallState.RINGING);
         verify(mWakeLock).acquire();
     }
 
-    public void test_RingingCallRemoved() throws Exception {
+    public void DONT_test_RingingCallRemoved() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLock.isHeld()).thenReturn(false);
 
@@ -87,7 +96,7 @@
         verify(mWakeLock, never()).acquire();
     }
 
-    public void test_WakeLockReleased() throws Exception {
+    public void DONT_test_WakeLockReleased() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLock.isHeld()).thenReturn(true);
 
diff --git a/tests/src/com/android/server/telecom/tests/MockConnectionService.java b/tests/src/com/android/server/telecom/tests/MockConnectionService.java
deleted file mode 100644
index 62448cd..0000000
--- a/tests/src/com/android/server/telecom/tests/MockConnectionService.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2014 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.telecom.ConnectionService;
-
-/**
- * A non-functional {@link android.telecom.ConnectionService} to use for unit tests.
- */
-public class MockConnectionService extends ConnectionService {
-
-}
diff --git a/tests/src/com/android/server/telecom/tests/MockitoHelper.java b/tests/src/com/android/server/telecom/tests/MockitoHelper.java
new file mode 100644
index 0000000..5193bba
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/MockitoHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.server.telecom.Log;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Looper;
+
+/**
+ * Helper for Mockito-based test cases.
+ */
+public final class MockitoHelper {
+    private static final String DEXCACHE = "dexmaker.dexcache";
+
+    private Thread mRequestThread;
+    private ClassLoader mRequestThreadOriginalClassLoader;
+    private ClassLoader mMainThreadOriginalClassLoader;
+
+    /**
+     * Creates a new helper, which in turn will set the context classloader so
+     * it can load Mockito resources.
+     *
+     * @param packageClass test case class
+     */
+    public void setUp(Context context, Class<?> packageClass) throws Exception {
+        // makes a copy of the context classloader
+        mRequestThread = Thread.currentThread();
+        mRequestThreadOriginalClassLoader = mRequestThread.getContextClassLoader();
+        mMainThreadOriginalClassLoader = Looper.getMainLooper().getThread().getContextClassLoader();
+
+        ClassLoader newClassLoader = packageClass.getClassLoader();
+
+        Log.v(this, "Changing context classloader for thread %s from %s to %s",
+                mRequestThread.getName(),
+                mRequestThreadOriginalClassLoader,
+                newClassLoader);
+        mRequestThread.setContextClassLoader(newClassLoader);
+
+        Log.v(this, "Changing context classloader for MAIN thread from %s to %s",
+                mMainThreadOriginalClassLoader,
+                newClassLoader);
+        Looper.getMainLooper().getThread().setContextClassLoader(newClassLoader);
+
+        String dexCache = context.getCacheDir().toString();
+        Log.v(this, "Setting property %s to %s", DEXCACHE, dexCache);
+        System.setProperty(DEXCACHE, dexCache);
+    }
+
+    /**
+     * Restores the context classloader to the previous value.
+     */
+    public void tearDown() throws Exception {
+        Log.v(this, "Restoring context classloaders");
+        mRequestThread.setContextClassLoader(mRequestThreadOriginalClassLoader);
+        Log.v(this, "Clearing property %s", DEXCACHE);
+        System.clearProperty(DEXCACHE);
+    }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
similarity index 65%
rename from tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java
rename to tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index e63e79f..f815fed 100644
--- a/tests/src/com/android/server/telecom/tests/unit/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -14,26 +14,27 @@
  * limitations under the License.
  */
 
-package com.android.server.telecom.tests.unit;
+package com.android.server.telecom.tests;
 
-import android.os.UserHandle;
+import android.os.Binder;
+
+import com.android.internal.telecom.IConnectionService;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.telecom.Log;
 import com.android.server.telecom.PhoneAccountRegistrar;
-import com.android.server.telecom.tests.R;
 
+import org.mockito.Mockito;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Parcel;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
-import android.test.AndroidTestCase;
 import android.util.Xml;
 
 import java.io.BufferedInputStream;
@@ -43,21 +44,34 @@
 import java.io.File;
 import java.util.Arrays;
 
-public class PhoneAccountRegistrarTest extends AndroidTestCase {
+public class PhoneAccountRegistrarTest extends TelecomTestCase {
 
     private static final int MAX_VERSION = Integer.MAX_VALUE;
-    private static final String FILE_NAME = "phone-account-registrar-test.xml";
+    private static final String FILE_NAME = "phone-account-registrar-test-1223.xml";
     private PhoneAccountRegistrar mRegistrar;
 
     @Override
-    public void setUp() {
-        mRegistrar = new PhoneAccountRegistrar(getContext(), FILE_NAME);
+    public void setUp() throws Exception {
+        super.setUp();
+        mComponentContextFixture = new ComponentContextFixture();
+        new File(
+                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
+                FILE_NAME)
+                .delete();
+        mRegistrar = new PhoneAccountRegistrar(
+                mComponentContextFixture.getTestDouble().getApplicationContext(),
+                FILE_NAME);
     }
 
     @Override
-    public void tearDown() {
+    public void tearDown() throws Exception {
         mRegistrar = null;
-        new File(getContext().getFilesDir(), FILE_NAME).delete();
+        new File(
+                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
+                FILE_NAME)
+                .delete();
+        mComponentContextFixture = null;
+        super.tearDown();
     }
 
     public void testPhoneAccountHandle() throws Exception {
@@ -80,6 +94,7 @@
                 .build();
         PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
                 mContext);
+
         assertPhoneAccountEquals(input, result);
     }
 
@@ -91,102 +106,85 @@
         assertStateEquals(input, result);
     }
 
+    private void registerAndEnableAccount(PhoneAccount account) {
+        mRegistrar.registerPhoneAccount(account);
+        mRegistrar.enablePhoneAccount(account.getAccountHandle(), true);
+    }
+
     public void testAccounts() throws Exception {
         int i = 0;
-        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+
+        mComponentContextFixture.addConnectionService(
+                makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
                         | PhoneAccount.CAPABILITY_CALL_PROVIDER)
                 .build());
-        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
                         | PhoneAccount.CAPABILITY_CALL_PROVIDER)
                 .build());
-        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
                         | PhoneAccount.CAPABILITY_CALL_PROVIDER)
                 .build());
-        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
+        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
                 .build());
 
         assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
-        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts().size());
+        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts(null, false).size());
         assertEquals(null, mRegistrar.getSimCallManager());
-        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+        assertEquals(null, mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL));
     }
 
     public void testSimCallManager() throws Exception {
-        PhoneAccountHandle simManager = makeQuickAccountHandle("sim_mgr");
-        PhoneAccount simManagerAccount = new PhoneAccount.Builder(simManager, "sim_mgr")
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
-                        | PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
-                .build();
-        mRegistrar.registerPhoneAccount(simManagerAccount);
-        assertNull(mRegistrar.getSimCallManager());
-
-        // Test the basic case
-        mRegistrar.setSimCallManager(simManager);
-        assertEquals(simManager, mRegistrar.getSimCallManager());
-
-        // Make sure clearing it works, too
-        mRegistrar.unregisterPhoneAccount(simManager);
-        assertNull(mRegistrar.getSimCallManager());
-
-        // Re-registering it makes the setting come back
-        mRegistrar.registerPhoneAccount(simManagerAccount);
-        assertEquals(simManager, mRegistrar.getSimCallManager());
-
-        // Make sure that the manager has CAPABILITY_CONNECTION_MANAGER
-        PhoneAccountHandle simManagerImposter = makeQuickAccountHandle("imposter");
-        PhoneAccount simManagerImposterAccount =
-                new PhoneAccount.Builder(simManagerImposter, "imposter")
-                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .build();
-        mRegistrar.registerPhoneAccount(simManagerImposterAccount);
-
-        mRegistrar.setSimCallManager(null);
-        assertNull(mRegistrar.getSimCallManager());
-        mRegistrar.setSimCallManager(simManagerImposter);
-        assertNull(mRegistrar.getSimCallManager());
+        // TODO
     }
 
-    public void testDefaultOutgoing() {
+    public void testDefaultOutgoing() throws Exception {
+        mComponentContextFixture.addConnectionService(
+                makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
         // By default, there is no default outgoing account (nothing has been registered)
-        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+        assertNull(mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL));
 
         // Register one tel: account
         PhoneAccountHandle telAccount = makeQuickAccountHandle("tel_acct");
-        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(telAccount, "tel_acct")
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount, "tel_acct")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                 .build());
         PhoneAccountHandle defaultAccount =
-                mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+                mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL);
         assertEquals(telAccount, defaultAccount);
 
         // Add a SIP account, make sure tel: doesn't change
         PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
-        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
+        registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
                 .build());
-        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_SIP);
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_SIP);
         assertEquals(sipAccount, defaultAccount);
-        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL);
         assertEquals(telAccount, defaultAccount);
 
         // Add a connection manager, make sure tel: doesn't change
         PhoneAccountHandle connectionManager = makeQuickAccountHandle("mgr_acct");
-        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct")
+        registerAndEnableAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct")
                 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                 .build());
-        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL);
         assertEquals(telAccount, defaultAccount);
 
         // Unregister the tel: account, make sure there is no tel: default now.
         mRegistrar.unregisterPhoneAccount(telAccount);
-        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
+        assertNull(mRegistrar.getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL));
     }
 
     public void testPhoneAccountParceling() throws Exception {
@@ -198,10 +196,9 @@
                         .setAddress(Uri.parse("tel:123456"))
                         .setCapabilities(23)
                         .setHighlightColor(0xf0f0f0)
-                        .setIcon(
-                                "com.android.server.telecom.tests",
-                                R.drawable.stat_sys_phone_call,
-                                0xfefefe)
+                        .setIcon(Icon.createWithResource(
+                                "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
+                        // TODO: set icon tint (0xfefefe)
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
@@ -211,24 +208,27 @@
                         .setAddress(Uri.parse("tel:123456"))
                         .setCapabilities(23)
                         .setHighlightColor(0xf0f0f0)
-                        .setIcon(
+                        .setIcon(Icon.createWithBitmap(
                                 BitmapFactory.decodeResource(
                                         getContext().getResources(),
-                                        R.drawable.stat_sys_phone_call))
+                                        R.drawable.stat_sys_phone_call)))
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
                         .build());
     }
 
+    private static ComponentName makeQuickConnectionServiceComponentName() {
+        return new ComponentName(
+                "com.android.server.telecom.tests",
+                "com.android.server.telecom.tests.MockConnectionService");
+    }
+
     private static PhoneAccountHandle makeQuickAccountHandle(String id) {
         return new PhoneAccountHandle(
-                new ComponentName(
-                        "com.android.server.telecom.tests",
-                        "com.android.server.telecom.tests.MockConnectionService"
-                ),
+                makeQuickConnectionServiceComponentName(),
                 id,
-                new UserHandle(5));
+                Binder.getCallingUserHandle());
     }
 
     private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
@@ -242,8 +242,10 @@
                 .setAddress(Uri.parse("http://foo.com/" + idx))
                 .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
                 .setCapabilities(idx)
-                .setIcon("com.android.server.telecom.tests", R.drawable.stat_sys_phone_call)
+                .setIcon(Icon.createWithResource(
+                            "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
                 .setShortDescription("desc" + idx)
+                .setIsEnabled(true)
                 .build();
     }
 
@@ -279,7 +281,7 @@
             data = baos.toByteArray();
         }
 
-        Log.d(self, "====== XML data ======\n%s", new String(data));
+        Log.i(self, "====== XML data ======\n%s", new String(data));
 
         T result = null;
         {
@@ -289,7 +291,7 @@
             result = xml.readFromXml(parser, MAX_VERSION, context);
         }
 
-        Log.d(self, "result = " + result);
+        Log.i(self, "result = " + result);
 
         return result;
     }
@@ -306,34 +308,30 @@
         }
     }
 
-    private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
+    private static void assertIconEquals(Icon a, Icon b) {
         if (a != b) {
-            assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle());
-            assertEquals(a.getAddress(), b.getAddress());
-            assertEquals(a.getSubscriptionAddress(), b.getSubscriptionAddress());
-            assertEquals(a.getCapabilities(), b.getCapabilities());
-            assertEquals(a.getIconResId(), b.getIconResId());
-            assertEquals(a.getIconPackageName(), b.getIconPackageName());
-            assertBitmapEquals(a.getIconBitmap(), b.getIconBitmap());
-            assertEquals(a.getIconTint(), b.getIconTint());
-            assertEquals(a.getHighlightColor(), b.getHighlightColor());
-            assertEquals(a.getLabel(), b.getLabel());
-            assertEquals(a.getShortDescription(), b.getShortDescription());
-            assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes());
+            if (a != null && b != null) {
+                assertEquals(a.toString(), b.toString());
+            } else {
+                fail("Icons not equal: " + a + ", " + b);
+            }
         }
     }
 
-    private static void assertBitmapEquals(Bitmap a, Bitmap b) {
-        if (a == null || b == null) {
-            assertEquals(null, a);
-            assertEquals(null, b);
-        } else {
-            assertEquals(a.getWidth(), b.getWidth());
-            assertEquals(a.getHeight(), b.getHeight());
-            for (int x = 0; x < a.getWidth(); x++) {
-                for (int y = 0; y < a.getHeight(); y++) {
-                    assertEquals(a.getPixel(x, y), b.getPixel(x, y));
-                }
+    private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
+        if (a != b) {
+            if (a != null && b != null) {
+                assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle());
+                assertEquals(a.getAddress(), b.getAddress());
+                assertEquals(a.getSubscriptionAddress(), b.getSubscriptionAddress());
+                assertEquals(a.getCapabilities(), b.getCapabilities());
+                assertIconEquals(a.getIcon(), b.getIcon());
+                assertEquals(a.getHighlightColor(), b.getHighlightColor());
+                assertEquals(a.getLabel(), b.getLabel());
+                assertEquals(a.getShortDescription(), b.getShortDescription());
+                assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes());
+            } else {
+                fail("Phone accounts not equal: " + a + ", " + b);
             }
         }
     }
@@ -341,7 +339,6 @@
     private static void assertStateEquals(
             PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) {
         assertPhoneAccountHandleEquals(a.defaultOutgoing, b.defaultOutgoing);
-        assertPhoneAccountHandleEquals(a.simCallManager, b.simCallManager);
         assertEquals(a.accounts.size(), b.accounts.size());
         for (int i = 0; i < a.accounts.size(); i++) {
             assertPhoneAccountEquals(a.accounts.get(i), b.accounts.get(i));
@@ -354,7 +351,6 @@
         s.accounts.add(makeQuickAccount("id1", 1));
         s.accounts.add(makeQuickAccount("id2", 2));
         s.defaultOutgoing = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
-        s.simCallManager = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1");
         return s;
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/server/telecom/tests/TODO b/tests/src/com/android/server/telecom/tests/TODO
new file mode 100644
index 0000000..f412b4a
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/TODO
@@ -0,0 +1,14 @@
+* Implement acquireProvider("settings")
+* Implement acquireUnstableProvider("com.android.contacts")
+* ComponentContextFixture to have "setUp/tearDown" to check for things like un-released providers
+
+Bluetooth
+Speakerphone and audio modes
+Video calling
+Connection managers
+DTMF tones
+Call logging
+Ringback
+Missed calls
+Respond via SMS
+Permissions in registering PhoneAccounts
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
new file mode 100644
index 0000000..4f96cc7
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.google.common.base.Predicate;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.telecom.Call;
+import android.telecom.CallAudioState;
+import android.telecom.Connection;
+import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
+import android.telecom.ParcelableCall;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telecom.IInCallAdapter;
+import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.HeadsetMediaButton;
+import com.android.server.telecom.HeadsetMediaButtonFactory;
+import com.android.server.telecom.InCallWakeLockController;
+import com.android.server.telecom.InCallWakeLockControllerFactory;
+import com.android.server.telecom.Log;
+import com.android.server.telecom.MissedCallNotifier;
+import com.android.server.telecom.ProximitySensorManager;
+import com.android.server.telecom.ProximitySensorManagerFactory;
+import com.android.server.telecom.TelecomSystem;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+
+public class TelecomSystemTest extends TelecomTestCase {
+
+    static final int TEST_POLL_INTERVAL = 10;  // milliseconds
+    static final int TEST_TIMEOUT = 1000;  // milliseconds
+
+    @Mock MissedCallNotifier mMissedCallNotifier;
+    @Mock HeadsetMediaButton mHeadsetMediaButton;
+    @Mock ProximitySensorManager mProximitySensorManager;
+    @Mock InCallWakeLockController mInCallWakeLockController;
+
+    final ComponentName mInCallServiceComponentNameX =
+            new ComponentName(
+                    "incall-service-package-X",
+                    "incall-service-class-X");
+    final ComponentName mInCallServiceComponentNameY =
+            new ComponentName(
+                    "incall-service-package-Y",
+                    "incall-service-class-Y");
+
+    InCallServiceFixture mInCallServiceFixtureX;
+    InCallServiceFixture mInCallServiceFixtureY;
+
+    final ComponentName mConnectionServiceComponentNameA =
+            new ComponentName(
+                    "connection-service-package-A",
+                    "connection-service-class-A");
+    final ComponentName mConnectionServiceComponentNameB =
+            new ComponentName(
+                    "connection-service-package-B",
+                    "connection-service-class-B");
+
+    final PhoneAccount mPhoneAccountA0 =
+            PhoneAccount.builder(
+                    new PhoneAccountHandle(
+                            mConnectionServiceComponentNameA,
+                            "id A 0"),
+                    "Phone account service A ID 0")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                    .build();
+    final PhoneAccount mPhoneAccountA1 =
+            PhoneAccount.builder(
+                    new PhoneAccountHandle(
+                            mConnectionServiceComponentNameA,
+                            "id A 1"),
+                    "Phone account service A ID 1")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                    .build();
+    final PhoneAccount mPhoneAccountB0 =
+            PhoneAccount.builder(
+                    new PhoneAccountHandle(
+                            mConnectionServiceComponentNameB,
+                            "id B 0"),
+                    "Phone account service B ID 0")
+                    .addSupportedUriScheme("tel")
+                    .setCapabilities(
+                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                    .build();
+
+    ConnectionServiceFixture mConnectionServiceFixtureA;
+    ConnectionServiceFixture mConnectionServiceFixtureB;
+
+    CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture;
+
+    TelecomSystem mTelecomSystem;
+
+    class IdPair {
+        final String mConnectionId;
+        final String mCallId;
+
+        public IdPair(String connectionId, String callId) {
+            this.mConnectionId = connectionId;
+            this.mCallId = callId;
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // 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();
+
+        // Next, create the TelecomSystem, our system under test
+        setupTelecomSystem();
+
+        // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
+        // now-running TelecomSystem
+        setupConnectionServices();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mTelecomSystem = null;
+        super.tearDown();
+    }
+
+    private void setupTelecomSystem() throws Exception {
+        HeadsetMediaButtonFactory headsetMediaButtonFactory =
+                mock(HeadsetMediaButtonFactory.class);
+        ProximitySensorManagerFactory proximitySensorManagerFactory =
+                mock(ProximitySensorManagerFactory.class);
+        InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
+                mock(InCallWakeLockControllerFactory.class);
+
+        mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture();
+
+        when(headsetMediaButtonFactory.create(
+                any(Context.class),
+                any(CallsManager.class),
+                any(TelecomSystem.SyncRoot.class)))
+                .thenReturn(mHeadsetMediaButton);
+        when(proximitySensorManagerFactory.create(
+                any(Context.class),
+                any(CallsManager.class)))
+                .thenReturn(mProximitySensorManager);
+        when(inCallWakeLockControllerFactory.create(
+                any(Context.class),
+                any(CallsManager.class)))
+                .thenReturn(mInCallWakeLockController);
+
+        mTelecomSystem = new TelecomSystem(
+                mComponentContextFixture.getTestDouble(),
+                mMissedCallNotifier,
+                mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
+                headsetMediaButtonFactory,
+                proximitySensorManagerFactory,
+                inCallWakeLockControllerFactory);
+
+        verify(headsetMediaButtonFactory).create(
+                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
+                any(CallsManager.class),
+                any(TelecomSystem.SyncRoot.class));
+        verify(proximitySensorManagerFactory).create(
+                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
+                any(CallsManager.class));
+        verify(inCallWakeLockControllerFactory).create(
+                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
+                any(CallsManager.class));
+    }
+
+    private void setupConnectionServices() throws Exception {
+        mConnectionServiceFixtureA = new ConnectionServiceFixture();
+        mConnectionServiceFixtureB = new ConnectionServiceFixture();
+
+        mComponentContextFixture.addConnectionService(
+                mConnectionServiceComponentNameA,
+                mConnectionServiceFixtureA.getTestDouble());
+        mComponentContextFixture.addConnectionService(
+                mConnectionServiceComponentNameB,
+                mConnectionServiceFixtureB.getTestDouble());
+
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
+        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
+
+        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
+                mPhoneAccountA0.getAccountHandle());
+    }
+
+    private void setupInCallServices() throws Exception {
+        mComponentContextFixture.putResource(
+                com.android.server.telecom.R.string.ui_default_package,
+                mInCallServiceComponentNameX.getPackageName());
+        mComponentContextFixture.putResource(
+                com.android.server.telecom.R.string.incall_default_class,
+                mInCallServiceComponentNameX.getClassName());
+
+        mInCallServiceFixtureX = new InCallServiceFixture();
+        mInCallServiceFixtureY = new InCallServiceFixture();
+
+        mComponentContextFixture.addInCallService(
+                mInCallServiceComponentNameX,
+                mInCallServiceFixtureX.getTestDouble());
+        mComponentContextFixture.addInCallService(
+                mInCallServiceComponentNameY,
+                mInCallServiceFixtureY.getTestDouble());
+    }
+
+    private IdPair startOutgoingPhoneCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        reset(
+                connectionServiceFixture.getTestDouble(),
+                mInCallServiceFixtureX.getTestDouble(),
+                mInCallServiceFixtureY.getTestDouble());
+
+        assertEquals(
+                mInCallServiceFixtureX.mCallById.size(),
+                mInCallServiceFixtureY.mCallById.size());
+        assertEquals(
+                (mInCallServiceFixtureX.mInCallAdapter != null),
+                (mInCallServiceFixtureY.mInCallAdapter != null));
+
+        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
+        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
+
+        Intent actionCallIntent = new Intent();
+        actionCallIntent.setData(Uri.parse("tel:" + number));
+        actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
+        actionCallIntent.setAction(Intent.ACTION_CALL);
+        if (phoneAccountHandle != null) {
+            actionCallIntent.putExtra(
+                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                    phoneAccountHandle);
+        }
+
+        mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent);
+
+        if (!hasInCallAdapter) {
+            verify(mInCallServiceFixtureX.getTestDouble())
+                    .setInCallAdapter(
+                            any(IInCallAdapter.class));
+            verify(mInCallServiceFixtureY.getTestDouble())
+                    .setInCallAdapter(
+                            any(IInCallAdapter.class));
+        }
+
+        ArgumentCaptor<Intent> newOutgoingCallIntent =
+                ArgumentCaptor.forClass(Intent.class);
+        ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+        verify(mComponentContextFixture.getTestDouble().getApplicationContext())
+                .sendOrderedBroadcastAsUser(
+                        newOutgoingCallIntent.capture(),
+                        any(UserHandle.class),
+                        anyString(),
+                        anyInt(),
+                        newOutgoingCallReceiver.capture(),
+                        any(Handler.class),
+                        anyInt(),
+                        anyString(),
+                        any(Bundle.class));
+
+        // Pass on the new outgoing call Intent
+        // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
+        newOutgoingCallReceiver.getValue().setPendingResult(
+                new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
+        newOutgoingCallReceiver.getValue().setResultData(
+                newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
+        newOutgoingCallReceiver.getValue().onReceive(
+                mComponentContextFixture.getTestDouble(),
+                newOutgoingCallIntent.getValue());
+
+        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+
+        verify(connectionServiceFixture.getTestDouble()).createConnection(
+                eq(phoneAccountHandle),
+                anyString(),
+                any(ConnectionRequest.class),
+                anyBoolean(),
+                anyBoolean());
+
+        connectionServiceFixture.sendHandleCreateConnectionComplete(
+                connectionServiceFixture.mLatestConnectionId);
+
+        assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
+        assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
+
+        assertEquals(
+                mInCallServiceFixtureX.mLatestCallId,
+                mInCallServiceFixtureY.mLatestCallId);
+
+        return new IdPair(
+                connectionServiceFixture.mLatestConnectionId,
+                mInCallServiceFixtureX.mLatestCallId);
+    }
+
+    private IdPair startIncomingPhoneCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            final ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        reset(
+                connectionServiceFixture.getTestDouble(),
+                mInCallServiceFixtureX.getTestDouble(),
+                mInCallServiceFixtureY.getTestDouble());
+
+        assertEquals(
+                mInCallServiceFixtureX.mCallById.size(),
+                mInCallServiceFixtureY.mCallById.size());
+        assertEquals(
+                (mInCallServiceFixtureX.mInCallAdapter != null),
+                (mInCallServiceFixtureY.mInCallAdapter != null));
+
+        final int startingNumConnections = connectionServiceFixture.mConnectionById.size();
+        final int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
+
+        Bundle extras = new Bundle();
+        extras.putParcelable(
+                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
+                Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
+        mTelecomSystem.getTelecomServiceImpl().getBinder()
+                .addNewIncomingCall(phoneAccountHandle, extras);
+
+        verify(connectionServiceFixture.getTestDouble()).createConnection(
+                any(PhoneAccountHandle.class),
+                anyString(),
+                any(ConnectionRequest.class),
+                eq(true),
+                eq(false));
+
+        connectionServiceFixture.sendHandleCreateConnectionComplete(
+                connectionServiceFixture.mLatestConnectionId);
+        connectionServiceFixture.sendSetRinging(
+                connectionServiceFixture.mLatestConnectionId);
+
+        // For the case of incoming calls, Telecom connecting the InCall services and adding the
+        // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
+        // is added, future interactions as triggered by the ConnectionService, through the various
+        // test fixtures, will be synchronous.
+
+        if (!hasInCallAdapter) {
+            verify(
+                    mInCallServiceFixtureX.getTestDouble(),
+                    timeout(TEST_TIMEOUT))
+                    .setInCallAdapter(
+                            any(IInCallAdapter.class));
+            verify(
+                    mInCallServiceFixtureY.getTestDouble(),
+                    timeout(TEST_TIMEOUT))
+                    .setInCallAdapter(
+                            any(IInCallAdapter.class));
+        }
+
+        // Give the InCallService time to respond
+
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void v) {
+                return mInCallServiceFixtureX.mInCallAdapter != null;
+            }
+        });
+
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void v) {
+                return mInCallServiceFixtureY.mInCallAdapter != null;
+            }
+        });
+
+        verify(
+                mInCallServiceFixtureX.getTestDouble(),
+                timeout(TEST_TIMEOUT))
+                .addCall(
+                        any(ParcelableCall.class));
+        verify(
+                mInCallServiceFixtureY.getTestDouble(),
+                timeout(TEST_TIMEOUT))
+                .addCall(
+                        any(ParcelableCall.class));
+
+        // Give the InCallService time to respond
+
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void v) {
+                return startingNumConnections + 1 ==
+                        connectionServiceFixture.mConnectionById.size();
+            }
+        });
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void v) {
+                return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size();
+            }
+        });
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void v) {
+                return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size();
+            }
+        });
+
+        assertEquals(
+                mInCallServiceFixtureX.mLatestCallId,
+                mInCallServiceFixtureY.mLatestCallId);
+
+        return new IdPair(
+                connectionServiceFixture.mLatestConnectionId,
+                mInCallServiceFixtureX.mLatestCallId);
+    }
+
+    private void rapidFire(Runnable... tasks) {
+        final CyclicBarrier barrier = new CyclicBarrier(tasks.length);
+        final CountDownLatch latch = new CountDownLatch(tasks.length);
+        for (int i = 0; i < tasks.length; i++) {
+            final Runnable task = tasks[i];
+            new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        barrier.await();
+                        task.run();
+                    } catch (InterruptedException | BrokenBarrierException e){
+                        Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
+                    } finally {
+                        latch.countDown();
+                    }
+                }
+            }).start();
+        }
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
+        }
+    }
+
+    // A simple outgoing call, verifying that the appropriate connection service is contacted,
+    // the proper lifecycle is followed, and both In-Call Services are updated correctly.
+    private IdPair startAndMakeActiveOutgoingCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
+
+        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        connectionServiceFixture.sendSetActive(ids.mConnectionId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        return ids;
+    }
+
+    public void testSingleOutgoingCallLocalDisconnect() throws Exception {
+        IdPair ids = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+    }
+
+    public void testSingleOutgoingCallRemoteDisconnect() throws Exception {
+        IdPair ids = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+    }
+
+    // A simple incoming call, similar in scope to the previous test
+    private IdPair startAndMakeActiveIncomingCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
+
+        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        mInCallServiceFixtureX.mInCallAdapter
+                .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY);
+
+        verify(connectionServiceFixture.getTestDouble())
+                .answer(ids.mConnectionId);
+
+        connectionServiceFixture.sendSetActive(ids.mConnectionId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        return ids;
+    }
+
+    public void testSingleIncomingCallLocalDisconnect() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+    }
+
+    public void testSingleIncomingCallRemoteDisconnect() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+    }
+
+    public void do_testDeadlockOnOutgoingCall() throws Exception {
+        final IdPair ids = startOutgoingPhoneCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        rapidFire(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) {
+                            mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply();
+                        }
+                    }
+                },
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
+                        } catch (Exception e) {
+                            Log.e(this, e, "");
+                        }
+                    }
+                });
+    }
+
+    public void testDeadlockOnOutgoingCall() throws Exception {
+        for (int i = 0; i < 100; i++) {
+            TelecomSystemTest test = new TelecomSystemTest();
+            test.setContext(getContext());
+            test.setTestContext(getTestContext());
+            test.setName(getName());
+            test.setUp();
+            test.do_testDeadlockOnOutgoingCall();
+            test.tearDown();
+        }
+    }
+
+    public void testIncomingThenOutgoingCalls() throws Exception {
+        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
+        IdPair incoming = startAndMakeActiveIncomingCall(
+                "650-555-2323",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        IdPair outgoing = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+    }
+
+    public void testOutgoingThenIncomingCalls() throws Exception {
+        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
+        IdPair outgoing = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        IdPair incoming = startAndMakeActiveIncomingCall(
+                "650-555-2323",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+        verify(mConnectionServiceFixtureA.getTestDouble())
+                .hold(outgoing.mConnectionId);
+        mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state =
+                Connection.STATE_HOLDING;
+        mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId);
+        assertEquals(
+                Call.STATE_HOLDING,
+                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
+        assertEquals(
+                Call.STATE_HOLDING,
+                mInCallServiceFixtureY.getCall(outgoing.mCallId).getState());
+    }
+
+    public void testAudioManagerOperations() throws Exception {
+        AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
+                .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
+
+        IdPair outgoing = startAndMakeActiveOutgoingCall(
+                "650-555-1212",
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .requestAudioFocusForCall(anyInt(), anyInt());
+        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
+                .setMode(AudioManager.MODE_IN_CALL);
+
+        mInCallServiceFixtureX.mInCallAdapter.mute(true);
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .setMicrophoneMute(true);
+        mInCallServiceFixtureX.mInCallAdapter.mute(false);
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .setMicrophoneMute(false);
+
+        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .setSpeakerphoneOn(true);
+        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .setSpeakerphoneOn(false);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
+
+        verify(audioManager, timeout(TEST_TIMEOUT))
+                .abandonAudioFocusForCall();
+        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
+                .setMode(AudioManager.MODE_NORMAL);
+    }
+
+    protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
+        int elapsed = 0;
+        while (elapsed < TEST_TIMEOUT) {
+            if (predicate.apply(null)) {
+                return;
+            } else {
+                try {
+                    Thread.sleep(TEST_POLL_INTERVAL);
+                    elapsed += TEST_POLL_INTERVAL;
+                } catch (InterruptedException e) {
+                    fail(e.toString());
+                }
+            }
+        }
+        fail("Timeout in assertTrueWithTimeout");
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
new file mode 100644
index 0000000..144ef66
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.server.telecom.Log;
+
+import org.mockito.MockitoAnnotations;
+
+import android.test.AndroidTestCase;
+
+public abstract class TelecomTestCase extends AndroidTestCase {
+    private static final String TESTING_TAG = "Telecom-TEST";
+
+    MockitoHelper mMockitoHelper = new MockitoHelper();
+    ComponentContextFixture mComponentContextFixture;
+
+    @Override
+    public void setUp() throws Exception {
+        Log.setTag(TESTING_TAG);
+        mMockitoHelper.setUp(getContext(), getClass());
+        mComponentContextFixture = new ComponentContextFixture();
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mComponentContextFixture = null;
+        mMockitoHelper.tearDown();
+        Log.setTag(com.android.server.telecom.Log.TAG);
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/TestFixture.java b/tests/src/com/android/server/telecom/tests/TestFixture.java
new file mode 100644
index 0000000..25e0868
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/TestFixture.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+/**
+ * An object that provides supporting methods, fields, and other functionality for configuring
+ * and inspecting the results of operations on a test double (mock, fake or stub). The test double
+ * is an object of type {@code T}.
+ */
+public interface TestFixture<T> {
+
+    /**
+     * Obtain the actual test double provided by this holder. It is a requirement of this API
+     * that the test double as returned from this method be a Mockito mock or spy, so that a test
+     * can use Mockito APIs to directly instrument its behavior where needed.
+     *
+     * @return the test double.
+     */
+    T getTestDouble();
+}