Merge rvc-release RP1A.201105.002 to aosp-master - DO NOT MERGE

Merged-In: I0ff9ff4992dc17879d3cc67ebf3113bee47c1cf9
Change-Id: I46eb801f7b622cc34e117df8e30e6bba0838a93c
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7c57599..327d0a2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,80 +15,75 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-        package="com.android.server.telecom"
-        coreApp="true"
-        android:sharedUserId="android.uid.system">
+     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+     package="com.android.server.telecom"
+     coreApp="true"
+     android:sharedUserId="android.uid.system">
 
-    <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION" />
-    <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT" />
+    <protected-broadcast android:name="android.intent.action.SHOW_MISSED_CALLS_NOTIFICATION"/>
+    <protected-broadcast android:name="com.android.server.telecom.MESSAGE_SENT"/>
 
 
     <!-- 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.HANDLE_CALL_INTENT" />
-    <uses-permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES" />
-    <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.MANAGE_ROLE_HOLDERS" />
-    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <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.HANDLE_CALL_INTENT"/>
+    <uses-permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
+    <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.MANAGE_ROLE_HOLDERS"/>
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <!-- Required to determine source of ongoing audio recordings. -->
-    <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
-    <uses-permission android:name="android.permission.READ_CALL_LOG" />
-    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.SEND_SMS" />
-    <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.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS" />
-    <uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS" />
-    <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.SEND_SMS"/>
+    <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.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS"/>
+    <uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"/>
+    <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
 
-    <permission
-            android:name="android.permission.BROADCAST_CALLLOG_INFO"
-            android:label="Broadcast the call type/duration information"
-            android:protectionLevel="signature|system"/>
+    <permission android:name="android.permission.BROADCAST_CALLLOG_INFO"
+         android:label="Broadcast the call type/duration information"
+         android:protectionLevel="signature|system"/>
 
-    <permission
-            android:name="android.permission.PROCESS_CALLLOG_INFO"
-            android:label="Register to handle the broadcasted call type/duration information"
-            android:protectionLevel="signature|system"/>
+    <permission android:name="android.permission.PROCESS_CALLLOG_INFO"
+         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.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"/>
+    <permission android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION"
+         android:label="Process phone account registration"
+         android:protectionLevel="signature|system"/>
 
-    <permission
-            android:name="android.permission.HANDLE_CALL_INTENT"
-            android:label="Protects handling the call intent via the TelecomManager API."
-            android:protectionLevel="signature|system"/>
+    <permission android:name="android.permission.HANDLE_CALL_INTENT"
+         android:label="Protects handling the call intent via the TelecomManager API."
+         android:protectionLevel="signature|system"/>
 
     <application android:label="@string/telecommAppLabel"
-            android:icon="@mipmap/ic_launcher_phone"
-            android:allowBackup="false"
-            android:supportsRtl="true"
-            android:process="system"
-            android:usesCleartextTraffic="false"
-            android:defaultToDeviceProtectedStorage="true"
-            android:directBootAware="true">
+         android:icon="@mipmap/ic_launcher_phone"
+         android:allowBackup="false"
+         android:supportsRtl="true"
+         android:process="system"
+         android:usesCleartextTraffic="false"
+         android:defaultToDeviceProtectedStorage="true"
+         android:directBootAware="true">
 
         <!-- CALL vs CALL_PRIVILEGED vs CALL_EMERGENCY
              We have three different intents through which a call can be initiated each with its
@@ -104,60 +99,61 @@
 
         <!-- Activity that displays UI for managing blocked numbers. -->
         <activity android:name=".settings.BlockedNumbersActivity"
-                  android:label="@string/blocked_numbers"
-                  android:configChanges="orientation|screenSize|keyboardHidden"
-                  android:theme="@style/Theme.Telecom.BlockedNumbers"
-                  android:process=":ui"
-                  android:exported="true">
+             android:label="@string/blocked_numbers"
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:theme="@style/Theme.Telecom.BlockedNumbers"
+             android:process=":ui"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.telecom.action.MANAGE_BLOCKED_NUMBERS" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="android.telecom.action.MANAGE_BLOCKED_NUMBERS"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
 
         <activity android:name=".settings.CallBlockDisabledActivity"
-                android:configChanges="keyboardHidden|orientation|screenSize"
-                android:excludeFromRecents="true"
-                android:launchMode="singleInstance"
-                android:theme="@style/Theme.Telecomm.Transparent"
-                android:process=":ui">
+             android:configChanges="keyboardHidden|orientation|screenSize"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance"
+             android:theme="@style/Theme.Telecomm.Transparent"
+             android:process=":ui">
         </activity>
 
         <!-- Activity that starts the outgoing call process by listening to CALL intent which
-             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. -->
+                         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=".components.UserCallActivity"
-                android:label="@string/userCallActivityLabel"
-                android:theme="@style/Theme.Telecomm.Transparent"
-                android:permission="android.permission.CALL_PHONE"
-                android:excludeFromRecents="true"
-                android:process=":ui">
+             android:label="@string/userCallActivityLabel"
+             android:theme="@style/Theme.Telecomm.Transparent"
+             android:permission="android.permission.CALL_PHONE"
+             android:excludeFromRecents="true"
+             android:process=":ui"
+             android:exported="true">
             <!-- CALL action intent filters for the various ways of initiating an outgoing call. -->
             <intent-filter>
-                <action android:name="android.intent.action.CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="tel" />
+                <action android:name="android.intent.action.CALL"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="tel"/>
             </intent-filter>
             <!-- Specify an icon for SIP calls so that quick contacts widget shows a special SIP
-                 icon for calls to SIP addresses. -->
+                                 icon for calls to SIP addresses. -->
             <intent-filter android:icon="@drawable/ic_launcher_sip_call">
-                <action android:name="android.intent.action.CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="sip" />
+                <action android:name="android.intent.action.CALL"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="sip"/>
             </intent-filter>
             <intent-filter>
-                <action android:name="android.intent.action.CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="voicemail" />
+                <action android:name="android.intent.action.CALL"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="voicemail"/>
             </intent-filter>
             <!-- Omit default category below so that all Intents sent to this filter must be
-                 explicit. -->
+                                 explicit. -->
             <intent-filter>
-                <action android:name="android.intent.action.CALL" />
-                <data android:mimeType="vnd.android.cursor.item/phone" />
-                <data android:mimeType="vnd.android.cursor.item/phone_v2" />
-                <data android:mimeType="vnd.android.cursor.item/person" />
+                <action android:name="android.intent.action.CALL"/>
+                <data android:mimeType="vnd.android.cursor.item/phone"/>
+                <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+                <data android:mimeType="vnd.android.cursor.item/person"/>
             </intent-filter>
         </activity>
 
@@ -167,30 +163,30 @@
              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=".components.UserCallActivity"
-                android:permission="android.permission.CALL_PRIVILEGED"
-                android:process=":ui">
+             android:targetActivity=".components.UserCallActivity"
+             android:permission="android.permission.CALL_PRIVILEGED"
+             android:process=":ui">
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_PRIVILEGED" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="tel" />
+                <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="tel"/>
             </intent-filter>
             <intent-filter android:priority="1000"
-                    android:icon="@drawable/ic_launcher_sip_call">
-                <action android:name="android.intent.action.CALL_PRIVILEGED" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="sip" />
+                 android:icon="@drawable/ic_launcher_sip_call">
+                <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="sip"/>
             </intent-filter>
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_PRIVILEGED" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="voicemail" />
+                <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="voicemail"/>
             </intent-filter>
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_PRIVILEGED" />
-                <data android:mimeType="vnd.android.cursor.item/phone" />
-                <data android:mimeType="vnd.android.cursor.item/phone_v2" />
-                <data android:mimeType="vnd.android.cursor.item/person" />
+                <action android:name="android.intent.action.CALL_PRIVILEGED"/>
+                <data android:mimeType="vnd.android.cursor.item/phone"/>
+                <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+                <data android:mimeType="vnd.android.cursor.item/person"/>
             </intent-filter>
         </activity-alias>
 
@@ -200,123 +196,129 @@
              1000 is used in all intent filters to prevent anything but the system from processing
              this intent (b/8871505). -->
         <!-- TODO: Is there really a notion of an emergency SIP number? If not, can
-             that scheme be removed from this activity? -->
+                         that scheme be removed from this activity? -->
         <activity-alias android:name="EmergencyCallActivity"
-                android:targetActivity=".components.UserCallActivity"
-                android:permission="android.permission.CALL_PRIVILEGED"
-                android:process=":ui">
+             android:targetActivity=".components.UserCallActivity"
+             android:permission="android.permission.CALL_PRIVILEGED"
+             android:process=":ui">
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_EMERGENCY" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="tel" />
+                <action android:name="android.intent.action.CALL_EMERGENCY"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="tel"/>
             </intent-filter>
             <intent-filter android:priority="1000"
-                    android:icon="@drawable/ic_launcher_sip_call">
-                <action android:name="android.intent.action.CALL_EMERGENCY" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="sip" />
+                 android:icon="@drawable/ic_launcher_sip_call">
+                <action android:name="android.intent.action.CALL_EMERGENCY"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="sip"/>
             </intent-filter>
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_EMERGENCY" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="voicemail" />
+                <action android:name="android.intent.action.CALL_EMERGENCY"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="voicemail"/>
             </intent-filter>
             <intent-filter android:priority="1000">
-                <action android:name="android.intent.action.CALL_EMERGENCY" />
-                <data android:mimeType="vnd.android.cursor.item/phone" />
-                <data android:mimeType="vnd.android.cursor.item/phone_v2" />
-                <data android:mimeType="vnd.android.cursor.item/person" />
+                <action android:name="android.intent.action.CALL_EMERGENCY"/>
+                <data android:mimeType="vnd.android.cursor.item/phone"/>
+                <data android:mimeType="vnd.android.cursor.item/phone_v2"/>
+                <data android:mimeType="vnd.android.cursor.item/person"/>
             </intent-filter>
         </activity-alias>
 
-        <receiver android:name=".components.TelecomBroadcastReceiver" android:exported="false"
-                android:process="system">
+        <receiver android:name=".components.TelecomBroadcastReceiver"
+             android:exported="false"
+             android:process="system">
             <intent-filter>
-                <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" />
-                <action android:name="com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION" />
-                <action android:name="com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION" />
-                <action android:name="com.android.server.telecom.PROCEED_WITH_CALL" />
-                <action android:name="com.android.server.telecom.CANCEL_CALL" />
-                <action android:name="com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL" />
-                <action android:name="com.android.server.telecom.CANCEL_REDIRECTED_CALL" />
+                <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"/>
+                <action android:name="com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION"/>
+                <action android:name="com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION"/>
+                <action android:name="com.android.server.telecom.PROCEED_WITH_CALL"/>
+                <action android:name="com.android.server.telecom.CANCEL_CALL"/>
+                <action android:name="com.android.server.telecom.PROCEED_WITH_REDIRECTED_CALL"/>
+                <action android:name="com.android.server.telecom.CANCEL_REDIRECTED_CALL"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name=".components.AppUninstallBroadcastReceiver"
-                android:process="system">
+             android:process="system"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
-                <data android:scheme="package" />
+                <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
+                <data android:scheme="package"/>
             </intent-filter>
         </receiver>
 
         <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">
+             android:label="@string/respond_via_sms_setting_title"
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:theme="@style/Theme.Telecom.DialerSettings"
+             android:process=":ui"
+             android:exported="true">
             <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" />
+                <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=".settings.EnableAccountPreferenceActivity"
-                  android:label="@string/enable_account_preference_title"
-                  android:configChanges="orientation|screenSize|keyboardHidden"
-                  android:theme="@style/Theme.Telecom.DialerSettings"
-                  android:process=":ui">
+             android:label="@string/enable_account_preference_title"
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:theme="@style/Theme.Telecom.DialerSettings"
+             android:process=":ui"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <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"
-                android:theme="@style/Theme.Telecomm.Transparent"
-                android:process=":ui">
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance"
+             android:theme="@style/Theme.Telecomm.Transparent"
+             android:process=":ui">
         </activity>
 
         <activity android:name=".ui.ConfirmCallDialogActivity"
-                android:configChanges="orientation|screenSize|keyboardHidden"
-                android:excludeFromRecents="true"
-                android:launchMode="singleInstance"
-                android:theme="@style/Theme.Telecomm.Transparent"
-                android:process=":ui">
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance"
+             android:theme="@style/Theme.Telecomm.Transparent"
+             android:process=":ui">
         </activity>
 
         <activity android:name=".ui.CallRedirectionTimeoutDialogActivity"
-                  android:configChanges="orientation|screenSize|keyboardHidden"
-                  android:excludeFromRecents="true"
-                  android:launchMode="singleInstance"
-                  android:theme="@style/Theme.Telecomm.Transparent"
-                  android:process=":ui">
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance"
+             android:theme="@style/Theme.Telecomm.Transparent"
+             android:process=":ui">
         </activity>
 
         <activity android:name=".ui.TelecomDeveloperMenu"
-                  android:label="@string/developer_title"
-                  android:exported="false"
-                  android:process=":ui" />
+             android:label="@string/developer_title"
+             android:exported="false"
+             android:process=":ui"/>
 
         <service android:name=".components.BluetoothPhoneService"
-                android:singleUser="true"
-                android:process="system">
+             android:singleUser="true"
+             android:process="system"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
+                <action android:name="android.bluetooth.IBluetoothHeadsetPhone"/>
             </intent-filter>
         </service>
 
         <service android:name=".components.TelecomService"
-                android:singleUser="true"
-                android:process="system">
+             android:singleUser="true"
+             android:process="system"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.telecom.ITelecomService" />
+                <action android:name="android.telecom.ITelecomService"/>
             </intent-filter>
         </service>
 
diff --git a/OWNERS b/OWNERS
index 94409ef..39be2c1 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,6 @@
 breadley@google.com
 hallliu@google.com
 tgunn@google.com
-paulye@google.com
+xiaotonj@google.com
+shuoq@google.com
+rgreenwalt@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 75feeb6..02bd056 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -15,6 +15,14 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "CtsTelecomTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ]
 }
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 87bde1c..c434ecc 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -47,7 +47,7 @@
     <string name="respond_via_sms_failure_format" msgid="5198680980054596391">"Fehler beim Senden der Nachricht an <xliff:g id="PHONE_NUMBER">%s</xliff:g>"</string>
     <string name="enable_account_preference_title" msgid="6949224486748457976">"Anrufkonten"</string>
     <string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"Es sind nur Notrufe erlaubt."</string>
-    <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Diese App darf ohne die Berechtigung \"Standard-App für Telefonie\" keine ausgehenden Anrufe tätigen."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"Diese App darf ohne die Berechtigung \"Telefon-App\" keine ausgehenden Anrufe tätigen."</string>
     <string name="outgoing_call_error_no_phone_number_supplied" msgid="7665135102566099778">"Gib eine gültige Nummer ein."</string>
     <string name="duplicate_video_call_not_allowed" msgid="5754746140185781159">"Der Anruf kann momentan nicht hinzugefügt werden."</string>
     <string name="no_vm_number" msgid="2179959110602180844">"Fehlende Mailbox-Nummer"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 3acab47..e157655 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -112,7 +112,7 @@
     <string name="phone_settings_private_num_summary_txt" msgid="6755758240544021037">"番号非通知の発信者をブロック"</string>
     <string name="phone_settings_payphone_txt" msgid="5003987966052543965">"公衆電話"</string>
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"公衆電話からの着信をブロック"</string>
-    <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明"</string>
+    <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明な発信者"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"不明な発信者からの着信をブロック"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"着信のブロック"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"着信のブロックを無効にしました"</string>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
index f884ec9..df1a759 100644
--- a/res/xml/activity_blocked_numbers.xml
+++ b/res/xml/activity_blocked_numbers.xml
@@ -75,7 +75,7 @@
                     <TextView
                             android:id="@+id/add_blocked"
                             android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
+                            android:layout_height="48dp"
                             android:text="@string/block_number"
                             android:layout_marginBottom="@dimen/blocked_numbers_button_bottom_margin"
                             android:paddingTop="@dimen/blocked_numbers_button_large_padding"
diff --git a/res/xml/enhanced_call_blocking_settings.xml b/res/xml/enhanced_call_blocking_settings.xml
index 32c4c5d..73ed2af 100644
--- a/res/xml/enhanced_call_blocking_settings.xml
+++ b/res/xml/enhanced_call_blocking_settings.xml
@@ -41,8 +41,4 @@
         android:persistent="false"
         android:defaultValue="false"/>
     <!--Add divider to separate this enhanced call blocking settings from other settings-->
-    <Preference
-        android:key="enhanced_call_blocking_divider"
-        android:persistent="false"
-        android:layout="@xml/layout_divider"/>
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/layout_blocked_number.xml b/res/xml/layout_blocked_number.xml
index 3cdd771..9dbfc2f 100644
--- a/res/xml/layout_blocked_number.xml
+++ b/res/xml/layout_blocked_number.xml
@@ -28,9 +28,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
+        android:layout_toStartOf="@+id/delete_blocked_number"
         android:paddingTop="@dimen/blocked_numbers_delete_icon_padding"
-        android:layout_alignParentLeft="true"
-        android:layout_toLeftOf="@+id/delete_blocked_number"
         android:textDirection="ltr" />
 
     <ImageView
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 9c227a6..8b7c37d 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -208,6 +208,9 @@
 
         public void setCallSource(int callSource) {
         }
+
+        public void setMissedReason(long missedReason) {
+        }
     }
 
     /**
@@ -242,6 +245,7 @@
         public List<TelecomLogClass.InCallServiceInfo> inCallServiceInfos;
         public int callProperties = 0;
         public int callSource = CALL_SOURCE_UNSPECIFIED;
+        public long missedReason;
 
         private long mTimeOfLastVideoEvent = -1;
 
@@ -254,6 +258,7 @@
             connectionService = "";
             videoEvents = new LinkedList<>();
             inCallServiceInfos = new LinkedList<>();
+            missedReason = 0;
         }
 
         CallInfoImpl(CallInfoImpl other) {
@@ -272,6 +277,7 @@
             this.videoEvents = other.videoEvents;
             this.callProperties = other.callProperties;
             this.callSource = other.callSource;
+            this.missedReason = other.missedReason;
 
             if (other.callTerminationReason != null) {
                 this.callTerminationReason = new DisconnectCause(
@@ -342,6 +348,13 @@
         }
 
         @Override
+        public void setMissedReason(long missedReason) {
+            Log.d(TAG, "setting missedReason for call " + callId + ": "
+                    + missedReason);
+            this.missedReason = missedReason;
+        }
+
+        @Override
         public void setCallEvents(EventManager.EventRecord records) {
             this.callEvents = records;
         }
@@ -399,6 +412,7 @@
                     + "    isEmergency: " + isEmergency + '\n'
                     + "    callTechnologies: " + getCallTechnologiesAsString() + '\n'
                     + "    callTerminationReason: " + getCallDisconnectReasonString() + '\n'
+                    + "    missedReason: " + getMissedReasonString() + '\n'
                     + "    connectionService: " + connectionService + '\n'
                     + "    isVideoCall: " + isVideo + '\n'
                     + "    inCallServices: " + getInCallServicesString() + '\n'
@@ -526,6 +540,11 @@
             }
         }
 
+        private String getMissedReasonString() {
+            //TODO: Implement this
+            return null;
+        }
+
         private String getInCallServicesString() {
             StringBuilder s = new StringBuilder();
             s.append("[\n");
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
old mode 100755
new mode 100644
index df6322c..fb4f58d
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom;
 
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -33,6 +35,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.CallLog;
 import android.provider.ContactsContract.Contacts;
 import android.telecom.CallAudioState;
 import android.telecom.CallerInfo;
@@ -545,7 +548,7 @@
     private ParcelFileDescriptor[] mConnectionServiceToInCallStreams;
 
     /**
-     * True if we're supposed to start this call with RTT, either due to the master switch or due
+     * True if we're supposed to start this call with RTT, either due to the settings switch or due
      * to an extra.
      */
     private boolean mDidRequestToStartWithRtt = false;
@@ -588,7 +591,7 @@
 
     /**
      * Indicates whether this call is using one of the
-     * {@link com.android.server.telecom.callfiltering.IncomingCallFilter.CallFilter} modules.
+     * {@link com.android.server.telecom.callfiltering.CallFilter} modules.
      */
     private boolean mIsUsingCallFiltering = false;
 
@@ -611,6 +614,16 @@
     private String mPostCallPackageName;
 
     /**
+     * Call missed information code.
+     */
+    @CallLog.Calls.MissedReason private long mMissedReason;
+
+    /**
+     * Time that this call start ringing or simulated ringing.
+     */
+    private long mStartRingTime;
+
+    /**
      * Persists the specified parameters and initializes the new instance.
      * @param context The context.
      * @param repository The connection service repository.
@@ -692,6 +705,8 @@
         mClockProxy = clockProxy;
         mToastFactory = toastFactory;
         mCreationTimeMillis = mClockProxy.currentTimeMillis();
+        mMissedReason = MISSED_REASON_NOT_MISSED;
+        mStartRingTime = 0;
     }
 
     /**
@@ -855,7 +870,7 @@
         PhoneAccountHandle delegatePhoneAccountHandle = getDelegatePhoneAccountHandle();
         boolean isTargetSameAsRemote = targetPhoneAccountHandle != null
                 && targetPhoneAccountHandle.equals(remotePhoneAccountHandle);
-        if (delegatePhoneAccountHandle.equals(targetPhoneAccountHandle)) {
+        if (Objects.equals(delegatePhoneAccountHandle, targetPhoneAccountHandle)) {
             s.append(">>>");
         }
         s.append("Target");
@@ -1124,6 +1139,12 @@
                 case CallState.ANSWERED:
                     event = LogUtils.Events.SET_ANSWERED;
                     break;
+                case CallState.AUDIO_PROCESSING:
+                    event = LogUtils.Events.SET_AUDIO_PROCESSING;
+                    break;
+                case CallState.SIMULATED_RINGING:
+                    event = LogUtils.Events.SET_SIMULATED_RINGING;
+                    break;
             }
             if (event != null) {
                 // The string data should be just the tag.
@@ -3864,4 +3885,20 @@
     public String getPostCallPackageName() {
         return mPostCallPackageName;
     }
+
+    public long getMissedReason() {
+        return mMissedReason;
+    }
+
+    public void setMissedReason(long missedReason) {
+        mMissedReason = missedReason;
+    }
+
+    public long getStartRingTime() {
+        return mStartRingTime;
+    }
+
+    public void setStartRingTime(long startRingTime) {
+        mStartRingTime = startRingTime;
+    }
 }
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index a562021..69a870f 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -413,6 +413,8 @@
                     return HANDLED;
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
+                    setSpeakerphoneOn(true);
+                    // fall through
                 case SPEAKER_ON:
                     transitionTo(mActiveSpeakerRoute);
                     return HANDLED;
@@ -459,6 +461,8 @@
             switch (msg.what) {
                 case SWITCH_EARPIECE:
                 case USER_SWITCH_EARPIECE:
+                case SPEAKER_ON:
+                    // Ignore speakerphone state changes outside of calls.
                 case SPEAKER_OFF:
                     // Nothing to do here
                     return HANDLED;
@@ -484,7 +488,6 @@
                     return HANDLED;
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
-                case SPEAKER_ON:
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
@@ -533,6 +536,7 @@
                     // This may be sent as a confirmation by the BT stack after switch off BT.
                     return HANDLED;
                 case CONNECT_DOCK:
+                    setSpeakerphoneOn(true);
                     sendInternalMessage(SWITCH_SPEAKER);
                     return HANDLED;
                 case DISCONNECT_DOCK:
@@ -611,6 +615,8 @@
                     return HANDLED;
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
+                    setSpeakerphoneOn(true);
+                    // fall through
                 case SPEAKER_ON:
                     transitionTo(mActiveSpeakerRoute);
                     return HANDLED;
@@ -677,12 +683,13 @@
                     return HANDLED;
                 case SWITCH_HEADSET:
                 case USER_SWITCH_HEADSET:
+                case SPEAKER_ON:
+                    // Ignore speakerphone state changes outside of calls.
                 case SPEAKER_OFF:
                     // Nothing to do
                     return HANDLED;
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
-                case SPEAKER_ON:
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
@@ -725,6 +732,7 @@
                     return HANDLED;
                 case DISCONNECT_WIRED_HEADSET:
                     if (mWasOnSpeaker) {
+                        setSpeakerphoneOn(true);
                         sendInternalMessage(SWITCH_SPEAKER);
                     } else {
                         sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
@@ -796,6 +804,7 @@
                     transitionTo(mActiveHeadsetRoute);
                     break;
                 case SWITCH_SPEAKER:
+                    setSpeakerphoneOn(true);
                     transitionTo(mActiveSpeakerRoute);
                     break;
                 default:
@@ -852,6 +861,8 @@
                     mHasUserExplicitlyLeftBluetooth = true;
                     // fall through
                 case SWITCH_SPEAKER:
+                    setSpeakerphoneOn(true);
+                    // fall through
                 case SPEAKER_ON:
                     setBluetoothOff();
                     transitionTo(mActiveSpeakerRoute);
@@ -947,6 +958,8 @@
                     mHasUserExplicitlyLeftBluetooth = true;
                     // fall through
                 case SWITCH_SPEAKER:
+                    setSpeakerphoneOn(true);
+                    // fall through
                 case SPEAKER_ON:
                     transitionTo(mActiveSpeakerRoute);
                     return HANDLED;
@@ -1012,6 +1025,8 @@
                     return HANDLED;
                 case SWITCH_BLUETOOTH:
                 case USER_SWITCH_BLUETOOTH:
+                case SPEAKER_ON:
+                    // Ignore speakerphone state changes outside of calls.
                 case SPEAKER_OFF:
                     // Nothing to do
                     return HANDLED;
@@ -1025,7 +1040,6 @@
                     return HANDLED;
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
-                case SPEAKER_ON:
                     transitionTo(mQuiescentSpeakerRoute);
                     return HANDLED;
                 case SWITCH_FOCUS:
@@ -1105,8 +1119,9 @@
         @Override
         public void enter() {
             super.enter();
+            // Don't set speakerphone on here -- we might end up in this state by following
+            // the speaker state that some other app commanded.
             mWasOnSpeaker = true;
-            setSpeakerphoneOn(true);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_SPEAKER,
                     mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices());
             setSystemAudioState(newState, true);
@@ -1593,12 +1608,8 @@
     }
 
     private void setSpeakerphoneOn(boolean on) {
-        if (mAudioManager.isSpeakerphoneOn() != on) {
-            Log.i(this, "turning speaker phone %s", on);
-            mAudioManager.setSpeakerphoneOn(on);
-        } else {
-            Log.i(this, "Ignoring speakerphone request -- already %s", on);
-        }
+        Log.i(this, "turning speaker phone %s", on);
+        mAudioManager.setSpeakerphoneOn(on);
         mStatusBarNotifier.notifySpeakerphone(on);
     }
 
diff --git a/src/com/android/server/telecom/CallIdMapper.java b/src/com/android/server/telecom/CallIdMapper.java
index da2c199..2cd5c79 100644
--- a/src/com/android/server/telecom/CallIdMapper.java
+++ b/src/com/android/server/telecom/CallIdMapper.java
@@ -20,6 +20,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.Collection;
 import java.util.Map;
 
 /** Utility to map {@link Call} objects to unique IDs. IDs are generated when a call is added. */
@@ -71,6 +72,10 @@
             return mSecondaryMap.get(value);
         }
 
+        public Collection<V> getValues() {
+            return mPrimaryMap.values();
+        }
+
         public void clear() {
             mPrimaryMap.clear();
             mSecondaryMap.clear();
@@ -132,6 +137,10 @@
         return mCalls.getValue(callId);
     }
 
+    Collection<Call> getCalls() {
+        return mCalls.getValues();
+    }
+
     void clear() {
         mCalls.clear();
     }
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 7a5af14..cedd41c 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
 import static android.telephony.CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL;
 
 import android.annotation.Nullable;
@@ -84,7 +85,8 @@
                 int features, PhoneAccountHandle accountHandle, long creationDate,
                 long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
                 @Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
-                CharSequence callScreeningAppName, String callScreeningComponentName) {
+                CharSequence callScreeningAppName, String callScreeningComponentName,
+                long missedReason) {
             this.context = context;
             this.callerInfo = callerInfo;
             this.number = number;
@@ -103,6 +105,7 @@
             this.callBockReason = callBlockReason;
             this.callScreeningAppName = callScreeningAppName;
             this.callScreeningComponentName = callScreeningComponentName;
+            this.missedReason = missedReason;
         }
         // Since the members are accessed directly, we don't use the
         // mXxxx notation.
@@ -127,6 +130,7 @@
         public final int callBockReason;
         public final CharSequence callScreeningAppName;
         public final String callScreeningComponentName;
+        public final long missedReason;
     }
 
     private static final String TAG = CallLogManager.class.getSimpleName();
@@ -353,20 +357,25 @@
                 call.wasEverRttCall(),
                 call.wasVolte());
 
-        if (callLogType == Calls.BLOCKED_TYPE) {
+        if (result == null) {
+            // Call auto missed before filtered
+            result = new CallFilteringResult.Builder().build();
+        }
+
+        if (callLogType == Calls.BLOCKED_TYPE || callLogType == Calls.MISSED_TYPE) {
             logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
                     call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
                     creationTime, age, callDataUsage, call.isEmergencyCall(),
                     call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
                     result.mCallBlockReason, result.mCallScreeningAppName,
-                    result.mCallScreeningComponentName);
+                    result.mCallScreeningComponentName, call.getMissedReason());
         } else {
             logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
                     call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
                     creationTime, age, callDataUsage, call.isEmergencyCall(),
                     call.getInitiatingUser(), call.isSelfManaged(), logCallCompletedListener,
                     Calls.BLOCK_REASON_NOT_BLOCKED, null /*callScreeningAppName*/,
-                    null /*callScreeningComponentName*/);
+                    null /*callScreeningComponentName*/, call.getMissedReason());
         }
     }
 
@@ -390,6 +399,7 @@
      * @param callBlockReason The reason why the call is blocked.
      * @param callScreeningAppName The call screening application name which block the call.
      * @param callScreeningComponentName The call screening component name which block the call.
+     * @param missedReason The encoded information about reasons for missed call.
      */
     private void logCall(
             CallerInfo callerInfo,
@@ -409,7 +419,8 @@
             @Nullable LogCallCompletedListener logCallCompletedListener,
             int callBlockReason,
             CharSequence callScreeningAppName,
-            String callScreeningComponentName) {
+            String callScreeningComponentName,
+            long missedReason) {
 
         // On some devices, to avoid accidental redialing of emergency numbers, we *never* log
         // emergency calls to the Call Log.  (This behavior is set on a per-product basis, based
@@ -443,7 +454,7 @@
             AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
                     viaNumber, presentation, callType, features, accountHandle, start, duration,
                     dataUsage, initiatingUser, isRead, logCallCompletedListener, callBlockReason,
-                    callScreeningAppName, callScreeningComponentName);
+                    callScreeningAppName, callScreeningComponentName, missedReason);
             logCallAsync(args);
         } else {
           Log.d(TAG, "Not adding emergency call to call log.");
@@ -596,7 +607,7 @@
                     c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
                     c.durationInSec, c.dataUsage, userToBeInserted == null,
                     userToBeInserted, c.isRead, c.callBockReason, c.callScreeningAppName,
-                    c.callScreeningComponentName);
+                    c.callScreeningComponentName, c.missedReason);
         }
 
 
@@ -605,7 +616,8 @@
             for (int i = 0; i < result.length; i++) {
                 Uri uri = result[i];
                 /*
-                 Performs a simple sanity check to make sure the call was written in the database.
+                 Performs a simple correctness check to make sure the call was written in the
+                 database.
                  Typically there is only one result per call so it is easy to identify which one
                  failed.
                  */
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 1c46209..25fd43e 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
 import static android.telecom.TelecomManager.ACTION_POST_CALL;
 import static android.telecom.TelecomManager.DURATION_LONG;
 import static android.telecom.TelecomManager.DURATION_MEDIUM;
@@ -27,6 +28,9 @@
 import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS;
 import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS;
 import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
+import static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -738,6 +742,7 @@
         // Only set the incoming call as ringing if it isn't already disconnected. It is possible
         // that the connection service disconnected the call before it was even added to Telecom, in
         // which case it makes no sense to set it back to a ringing state.
+        Log.i(this, "onCallFilteringComplete");
         mGraphHandlerThreads.clear();
 
         if (incomingCall.getState() != CallState.DISCONNECTED &&
@@ -759,16 +764,17 @@
                 } else {
                     Log.i(this, "onCallFilteringCompleted: Call rejected! " +
                             "Exceeds maximum number of ringing calls.");
-                    rejectCallAndLog(incomingCall, result);
+                    incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+                    autoMissCallAndLog(incomingCall, result);
                 }
             } else if (hasMaximumManagedDialingCalls(incomingCall)) {
                 if (shouldSilenceInsteadOfReject(incomingCall)) {
                     incomingCall.silence();
                 } else {
-
                     Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " +
                             "dialing calls.");
-                    rejectCallAndLog(incomingCall, result);
+                    incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_DIALING);
+                    autoMissCallAndLog(incomingCall, result);
                 }
             } else if (result.shouldScreenViaAudio) {
                 Log.i(this, "onCallFilteringCompleted: starting background audio processing");
@@ -1322,12 +1328,18 @@
             if (isConference) {
                 notifyCreateConferenceFailed(phoneAccountHandle, call);
             } else {
+                if (hasMaximumManagedRingingCalls(call)) {
+                    call.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
+                    mCallLogManager.logCall(call, Calls.MISSED_TYPE,
+                            true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
+                }
                 notifyCreateConnectionFailed(phoneAccountHandle, call);
             }
         } else if (isInEmergencyCall()) {
             // The incoming call is implicitly being rejected so the user does not get any incoming
             // call UI during an emergency call. In this case, log the call as missed instead of
             // rejected since the user did not explicitly reject.
+            call.setMissedReason(AUTO_MISSED_EMERGENCY_CALL);
             mCallLogManager.logCall(call, Calls.MISSED_TYPE,
                     true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
             if (isConference) {
@@ -1573,6 +1585,17 @@
                     // call transitioning into the CONNECTING state.
                     if (isReusedCall) {
                         return CompletableFuture.completedFuture(finalCall);
+                    } else {
+                        Call reusableCall = reuseOutgoingCall(handle);
+                        if (reusableCall != null) {
+                            Log.i(CallsManager.this,
+                                    "reusable call %s came in later; disconnect it.",
+                                    reusableCall.getId());
+                            mPendingCallsToDisconnect.remove(reusableCall);
+                            reusableCall.disconnect();
+                            markCallAsDisconnected(reusableCall,
+                                    new DisconnectCause(DisconnectCause.CANCELED));
+                        }
                     }
 
                     // If we can not supportany more active calls, our options are to move a call
@@ -3424,7 +3447,8 @@
      * Reject an incoming call and manually add it to the Call Log.
      * @param incomingCall Incoming call that has been rejected
      */
-    private void rejectCallAndLog(Call incomingCall, CallFilteringResult result) {
+    private void autoMissCallAndLog(Call incomingCall, CallFilteringResult result) {
+        incomingCall.getAnalytics().setMissedReason(incomingCall.getMissedReason());
         if (incomingCall.getConnectionService() != null) {
             // Only reject the call if it has not already been destroyed.  If a call ends while
             // incoming call filtering is taking place, it is possible that the call has already
@@ -3562,6 +3586,10 @@
                         (newState == CallState.DISCONNECTED)) {
                     maybeSendPostCallScreenIntent(call);
                 }
+                if (((newState == CallState.ABORTED) || (newState == CallState.DISCONNECTED))
+                        && (call.getDisconnectCause().getCode() != DisconnectCause.MISSED)) {
+                    call.setMissedReason(MISSED_REASON_NOT_MISSED);
+                }
                 maybeShowErrorDialogOnDisconnect(call);
 
                 Trace.beginSection("onCallStateChanged");
@@ -3975,7 +4003,7 @@
                 + " livecall = " + liveCall);
 
         if (emergencyCall == liveCall) {
-            // Not likely, but a good sanity check.
+            // Not likely, but a good correctness check.
             return true;
         }
 
@@ -3989,7 +4017,7 @@
                 return true;
             }
             if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
-                // Sanity check: if there is an orphaned emergency call in the
+                // Correctness check: if there is an orphaned emergency call in the
                 // {@link CallState#SELECT_PHONE_ACCOUNT} state, just disconnect it since the user
                 // has explicitly started a new call.
                 emergencyCall.getAnalytics().setCallIsAdditional(true);
@@ -4718,6 +4746,7 @@
      * @param call The {@link Call} which could not be added.
      */
     private void notifyCreateConnectionFailed(PhoneAccountHandle phoneAccountHandle, Call call) {
+        call.getAnalytics().setMissedReason(call.getMissedReason());
         if (phoneAccountHandle == null) {
             return;
         }
@@ -5327,4 +5356,9 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mContext.startActivityAsUser(intent, mCurrentUserHandle);
     }
+
+    @VisibleForTesting
+    public void addToPendingCallsToDisconnect(Call call) {
+        mPendingCallsToDisconnect.add(call);
+    }
 }
diff --git a/src/com/android/server/telecom/CarModeTracker.java b/src/com/android/server/telecom/CarModeTracker.java
index 0ec4917..e64ef5d 100644
--- a/src/com/android/server/telecom/CarModeTracker.java
+++ b/src/com/android/server/telecom/CarModeTracker.java
@@ -28,6 +28,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.PriorityQueue;
 import java.util.stream.Collectors;
 
@@ -144,6 +145,28 @@
     }
 
     /**
+     * Force-removes a package from the car mode tracking list, no matter at which priority.
+     *
+     * This handles the case where packages are disabled or uninstalled. In those case, remove them
+     * from the tracking list so they don't cause a leak.
+     * @param packageName Package name of the app to force-remove
+     */
+    public void forceExitCarMode(@NonNull String packageName) {
+        Optional<CarModeApp> forcedApp = mCarModeApps.stream()
+                .filter(c -> c.getPackageName().equals(packageName))
+                .findAny();
+        if (forcedApp.isPresent()) {
+            String logString = String.format("forceExitCarMode: packageName=%s, was at priority=%s",
+                    packageName, forcedApp.get().getPriority());
+            Log.i(this, logString);
+            mCarModeChangeLog.log(logString);
+            mCarModeApps.removeIf(c -> c.getPackageName().equals(packageName));
+        } else {
+            Log.i(this, "Package %s is not tracked as requesting car mode", packageName);
+        }
+    }
+
+    /**
      * Retrieves a list of the apps which are currently in car mode, ordered by priority such that
      * the highest priority app is first.
      * @return List of apps in car mode.
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 01acdd1..72c3f24 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -91,6 +91,7 @@
                             mServiceInterface.createConnectionComplete(callId,
                                     Log.getExternalSession());
                         } catch (RemoteException e) {
+                            logOutgoing("createConnectionComplete remote exception=%s", e);
                         }
                     }
                 }
@@ -1206,6 +1207,10 @@
                 mPendingResponses.put(callId, response);
 
                 Bundle extras = call.getIntentExtras();
+                if (extras == null) {
+                    extras = new Bundle();
+                }
+                extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
 
                 Log.addEvent(call, LogUtils.Events.START_CONFERENCE,
                         Log.piiHandle(call.getHandle()));
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 700dac7..2e67b08 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -403,6 +403,7 @@
             // When testing emergency calls, we want the calls to go through to the test connection
             // service, not the telephony ConnectionService.
             if (mCall.isTestEmergencyCall()) {
+                Log.i(this, "Processing test emergency call -- special rules");
                 allAccounts = mPhoneAccountRegistrar.filterRestrictedPhoneAccounts(allAccounts);
             }
 
@@ -411,7 +412,7 @@
                     preferredPAH);
             // Next, add all SIM phone accounts which can place emergency calls.
             sortSimPhoneAccountsForEmergency(allAccounts, preferredPA);
-            // and pick the fist one that can place emergency calls.
+            // and pick the first one that can place emergency calls.
             for (PhoneAccount phoneAccount : allAccounts) {
                 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
                         && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
@@ -438,7 +439,10 @@
                             mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
                                     mCall.getHandle() == null
                                             ? null : mCall.getHandle().getScheme()));
-                    if (!mAttemptRecords.contains(callAttemptRecord)) {
+                    // If the target phone account is null, we'll run into a NPE during the retry
+                    // process, so skip it now if it's null.
+                    if (callAttemptRecord.targetPhoneAccount != null
+                            && !mAttemptRecords.contains(callAttemptRecord)) {
                         Log.i(this, "Will try Connection Manager account %s for emergency",
                                 callManager);
                         mAttemptRecords.add(callAttemptRecord);
diff --git a/src/com/android/server/telecom/CreateConnectionTimeout.java b/src/com/android/server/telecom/CreateConnectionTimeout.java
index 399c28a..14e5bf0 100644
--- a/src/com/android/server/telecom/CreateConnectionTimeout.java
+++ b/src/com/android/server/telecom/CreateConnectionTimeout.java
@@ -69,7 +69,7 @@
         }
 
         // Timeout is only supported for SIM call managers that are set by the carrier.
-        if (!Objects.equals(connectionManager.getComponentName(),
+        if (connectionManager != null && !Objects.equals(connectionManager.getComponentName(),
                 mPhoneAccountRegistrar.getSystemSimCallManagerComponent())) {
             Log.d(this, "isTimeoutNeededForCall, not a system sim call manager");
             return false;
diff --git a/src/com/android/server/telecom/DefaultDialerCache.java b/src/com/android/server/telecom/DefaultDialerCache.java
index c2b78ee..a4a0242 100644
--- a/src/com/android/server/telecom/DefaultDialerCache.java
+++ b/src/com/android/server/telecom/DefaultDialerCache.java
@@ -217,6 +217,12 @@
         return mSystemDialerComponentName;
     }
 
+    public ComponentName getDialtactsSystemDialerComponent() {
+        final Resources resources = mContext.getResources();
+        return new ComponentName(getSystemDialerApplication(),
+                resources.getString(R.string.dialer_default_class));
+    }
+
     public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) {
         mRoleManagerAdapter.observeDefaultDialerApp(executor, observer);
     }
@@ -289,4 +295,8 @@
     public ContentObserver getContentObserver() {
         return mDefaultDialerObserver;
     }
+
+    public RoleManagerAdapter getRoleManagerAdapter() {
+        return mRoleManagerAdapter;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/server/telecom/DeviceIdleControllerAdapter.java b/src/com/android/server/telecom/DeviceIdleControllerAdapter.java
new file mode 100644
index 0000000..d3a798a
--- /dev/null
+++ b/src/com/android/server/telecom/DeviceIdleControllerAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.annotation.NonNull;
+import android.content.Context;
+import android.os.PowerWhitelistManager;
+import android.os.RemoteException;
+import android.telecom.Log;
+
+import com.android.internal.telecom.IDeviceIdleControllerAdapter;
+
+/**
+ * Telecom is in the same process as the {@link PowerWhitelistManager}, so we can not make direct
+ * calls to the manager interface, since they will fail in the DeviceIdleController
+ * (see {@link Context#enforceCallingPermission(String, String)}). Instead, we must access it
+ * through SystemService#getLocalService, which is only accessible to the Telecom
+ * core loader service (TelecomLoaderService). Unfortunately, due to the architecture, this means
+ * we must use a Binder to allow services such as this to be accessible.
+ */
+public class DeviceIdleControllerAdapter {
+
+    private static final String TAG = "DeviceIdleControllerAdapter";
+
+    private final IDeviceIdleControllerAdapter mAdapter;
+
+    public DeviceIdleControllerAdapter(IDeviceIdleControllerAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Exempts an application from power restrictions for the duration specified. See
+     * DeviceIdleController for more information on how this works.
+     */
+    public void exemptAppTemporarilyForEvent(@NonNull String packageName, long duration,
+            int userHandle, @NonNull String reason) {
+        try {
+            mAdapter.exemptAppTemporarilyForEvent(packageName, duration, userHandle, reason);
+        } catch (RemoteException e) {
+            Log.w(TAG, "exemptAppTemporarilyForEvent e=" + e.getMessage());
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 228cb3d..982af19 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -16,13 +16,18 @@
 
 package com.android.server.telecom;
 
+import static android.os.Process.myUid;
+
 import android.Manifest;
 import android.annotation.NonNull;
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -43,6 +48,7 @@
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 // TODO: Needed for move to system service: import com.android.internal.R;
@@ -58,6 +64,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -322,7 +329,10 @@
                 String packageName = mInCallServiceInfo.getComponentName().getPackageName();
                 mContext.unbindService(mServiceConnection);
                 mIsConnected = false;
-                if (mIsNullBinding) {
+                if (mIsNullBinding && mInCallServiceInfo.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+                    // Non-UI InCallServices are allowed to return null from onBind if they don't
+                    // want to handle calls at the moment, so don't report them to the user as
+                    // crashed.
                     sendCrashedInCallServiceNotification(packageName);
                 }
                 if (mCall != null) {
@@ -444,7 +454,7 @@
 
         @Override
         public void disconnect() {
-            Log.i(this, "Disconnect forced!");
+            Log.i(this, "Disconnecting from InCallService");
             if (mIsProxying) {
                 mSubConnection.disconnect();
             } else {
@@ -721,6 +731,20 @@
             }
             pw.decreaseIndent();
         }
+
+        public void addConnections(List<InCallServiceBindingConnection> newConnections) {
+            // connect() needs to be called with a Call object. Since we're in the middle of any
+            // possible number of calls right now, choose an arbitrary one from the ones that
+            // InCallController is tracking.
+            if (mCallIdMapper.getCalls().isEmpty()) {
+                Log.w(InCallController.this, "No calls tracked while adding new NonUi incall");
+                return;
+            }
+            Call callToConnectWith = mCallIdMapper.getCalls().iterator().next();
+            for (InCallServiceBindingConnection newConnection : newConnections) {
+                newConnection.connect(callToConnectWith);
+            }
+        }
     }
 
     private final Call.Listener mCallListener = new Call.ListenerBase() {
@@ -847,9 +871,50 @@
         }
     };
 
-    private final SystemStateListener mSystemStateListener =
-            (priority, packageName, isCarMode) -> InCallController.this.handleCarModeChange(
-                    priority, packageName, isCarMode);
+    private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.startSession("ICC.pCR");
+            try {
+                if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
+                    synchronized (mLock) {
+                        String changedPackage = intent.getData().getSchemeSpecificPart();
+                        List<InCallServiceBindingConnection> componentsToBind =
+                                Arrays.stream(intent.getStringArrayExtra(
+                                        Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))
+                                        .map((className) ->
+                                                ComponentName.createRelative(changedPackage,
+                                                        className))
+                                        .filter(mKnownNonUiInCallServices::contains)
+                                        .flatMap(componentName -> getInCallServiceComponents(
+                                                componentName,
+                                                IN_CALL_SERVICE_TYPE_NON_UI).stream())
+                                        .map(InCallServiceBindingConnection::new)
+                                        .collect(Collectors.toList());
+
+                        if (mNonUIInCallServiceConnections != null) {
+                            mNonUIInCallServiceConnections.addConnections(componentsToBind);
+                        }
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+    };
+
+    private final SystemStateListener mSystemStateListener = new SystemStateListener() {
+        @Override
+        public void onCarModeChanged(int priority, String packageName, boolean isCarMode) {
+            InCallController.this.handleCarModeChange(priority, packageName, isCarMode);
+        }
+
+        @Override
+        public void onPackageUninstalled(String packageName) {
+            mCarModeTracker.forceExitCarMode(packageName);
+            updateCarModeForSwitchingConnection();
+        }
+    };
 
     private static final int IN_CALL_SERVICE_TYPE_INVALID = 0;
     private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1;
@@ -864,6 +929,7 @@
     private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
 
     private final Context mContext;
+    private final AppOpsManager mAppOpsManager;
     private final TelecomSystem.SyncRoot mLock;
     private final CallsManager mCallsManager;
     private final SystemStateHelper mSystemStateHelper;
@@ -875,6 +941,11 @@
     private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
     private final ClockProxy mClockProxy;
 
+    // A set of known non-UI in call services on the device, including those that are disabled.
+    // We track this so that we can efficiently bind to them when we're notified that a new
+    // component has been enabled.
+    private Set<ComponentName> mKnownNonUiInCallServices = new ArraySet<>();
+
     // Future that's in a completed state unless we're in the middle of binding to a service.
     // The future will complete with true if binding succeeds, false if it timed out.
     private CompletableFuture<Boolean> mBindingFuture = CompletableFuture.completedFuture(true);
@@ -887,6 +958,7 @@
             EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker,
             ClockProxy clockProxy) {
         mContext = context;
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
         mLock = lock;
         mCallsManager = callsManager;
         mSystemStateHelper = systemStateHelper;
@@ -940,7 +1012,8 @@
                 ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                         true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                         info.isExternalCallsSupported(), includeRttCall,
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+                        info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 try {
                     inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
@@ -1004,7 +1077,8 @@
                 ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                         true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                         info.isExternalCallsSupported(), includeRttCall,
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+                        info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 try {
                     inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
@@ -1034,7 +1108,8 @@
                         false /* supportsExternalCalls */,
                         android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
                         false /* includeRttCall */,
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+                        info.getType() == IN_CALL_SERVICE_TYPE_NON_UI
                         );
 
                 try {
@@ -1227,6 +1302,12 @@
      * Unbinds an existing bound connection to the in-call app.
      */
     private void unbindFromServices() {
+        try {
+            mContext.unregisterReceiver(mPackageChangedReceiver);
+        } catch (IllegalArgumentException e) {
+            // Ignore this -- we may or may not have registered it, but when we bind, we want to
+            // unregister no matter what.
+        }
         if (mInCallServiceConnection != null) {
             mInCallServiceConnection.disconnect();
             mInCallServiceConnection = null;
@@ -1312,6 +1393,10 @@
         }
         mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
         mNonUIInCallServiceConnections.connect(call);
+
+        IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
+        packageChangedFilter.addDataScheme("package");
+        mContext.registerReceiver(mPackageChangedReceiver, packageChangedFilter);
     }
 
     private InCallServiceInfo getDefaultDialerComponent() {
@@ -1387,7 +1472,7 @@
         PackageManager packageManager = mContext.getPackageManager();
         for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
                 serviceIntent,
-                PackageManager.GET_META_DATA,
+                PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
                 mCallsManager.getCurrentUserHandle().getIdentifier())) {
             ServiceInfo serviceInfo = entry.serviceInfo;
             if (serviceInfo != null) {
@@ -1400,14 +1485,13 @@
 
                 int currentType = getInCallServiceType(entry.serviceInfo, packageManager,
                         packageName);
-                if (requestedType == 0 || requestedType == currentType) {
-                    if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
-                        // We enforce the rule that self-managed calls are not supported by non-ui
-                        // InCallServices.
-                        isSelfManageCallsSupported = false;
-                    }
-                    retval.add(new InCallServiceInfo(
-                            new ComponentName(serviceInfo.packageName, serviceInfo.name),
+                ComponentName foundComponentName =
+                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
+                    mKnownNonUiInCallServices.add(foundComponentName);
+                }
+                if (serviceInfo.enabled && (requestedType == 0 || requestedType == currentType)) {
+                    retval.add(new InCallServiceInfo(foundComponentName,
                             isExternalCallsSupported, isSelfManageCallsSupported, requestedType));
                 }
             }
@@ -1546,7 +1630,8 @@
                         mCallsManager.getPhoneAccountRegistrar(),
                         info.isExternalCallsSupported(),
                         includeRttCall,
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+                        info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
             } catch (RemoteException ignored) {
             }
@@ -1556,7 +1641,11 @@
             inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
         } catch (RemoteException ignored) {
         }
-        mBindingFuture.complete(true);
+        // Don't complete the binding future for non-ui incalls
+        if (info.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+            mBindingFuture.complete(true);
+        }
+
         Log.i(this, "%s calls sent to InCallService.", numCallsSent);
         return true;
     }
@@ -1610,7 +1699,8 @@
                         mCallsManager.getPhoneAccountRegistrar(),
                         info.isExternalCallsSupported(),
                         rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()),
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
+                        info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 ComponentName componentName = info.getComponentName();
                 IInCallService inCallService = entry.getValue();
                 componentsUpdated.add(componentName);
@@ -1701,7 +1791,7 @@
 
         if (TextUtils.isEmpty(ringingPackage)) {
             // The current in-call UI returned nothing, so lets use the default dialer.
-            ringingPackage = mDefaultDialerCache.getDefaultDialerApplication(
+            ringingPackage = mDefaultDialerCache.getRoleManagerAdapter().getDefaultDialerApp(
                     mCallsManager.getCurrentUserHandle().getIdentifier());
             if (ringingPackage != null) {
                 Log.d(this, "doesConnectedDialerSupportRinging: notCurentlyConnectedPackage=%s",
@@ -1784,7 +1874,8 @@
     public void handleCarModeChange(int priority, String packageName, boolean isCarMode) {
         Log.i(this, "handleCarModeChange: packageName=%s, priority=%d, isCarMode=%b",
                 packageName, priority, isCarMode);
-        if (!isCarModeInCallService(packageName)) {
+        // Don't ignore the signal if we are disabling car mode; package may be uninstalled.
+        if (isCarMode && !isCarModeInCallService(packageName)) {
             Log.i(this, "handleCarModeChange: not a valid InCallService; packageName=%s",
                     packageName);
             return;
@@ -1796,8 +1887,12 @@
             mCarModeTracker.handleExitCarMode(priority, packageName);
         }
 
+        updateCarModeForSwitchingConnection();
+    }
+
+    public void updateCarModeForSwitchingConnection() {
         if (mInCallServiceConnection != null) {
-            Log.i(this, "handleCarModeChange: car mode apps: %s",
+            Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s",
                     mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
             if (shouldUseCarModeUI()) {
                 mInCallServiceConnection.changeCarModeApp(
diff --git a/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java b/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java
new file mode 100644
index 0000000..4a2c3d1
--- /dev/null
+++ b/src/com/android/server/telecom/InternalServiceRetrieverAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.os.RemoteException;
+
+import com.android.internal.telecom.IInternalServiceRetriever;
+
+/**
+ * Contains all services that Telecom must access that are only accessible as a local service as
+ * part of the SYSTEM process.
+ */
+public class InternalServiceRetrieverAdapter {
+
+    private final IInternalServiceRetriever mRetriever;
+
+    public InternalServiceRetrieverAdapter(IInternalServiceRetriever retriever) {
+        mRetriever = retriever;
+    }
+
+    public DeviceIdleControllerAdapter getDeviceIdleController() {
+        try {
+            return new DeviceIdleControllerAdapter(mRetriever.getDeviceIdleController());
+        } catch (RemoteException e) {
+            // This should not happen - if it does, there is a bad configuration as this should
+            // all be local.
+            throw new IllegalStateException(e);
+        }
+    }
+}
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index 5bb14e6..e4a414b 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -101,6 +101,8 @@
         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 SET_AUDIO_PROCESSING = "SET_AUDIO_PROCESSING";
+        public static final String SET_SIMULATED_RINGING = "SET_SIMULATED_RINGING";
         public static final String REQUEST_HOLD = "REQUEST_HOLD";
         public static final String REQUEST_UNHOLD = "REQUEST_UNHOLD";
         public static final String REQUEST_DISCONNECT = "REQUEST_DISCONNECT";
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index f0efe92..86fedd5 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -21,7 +21,6 @@
 import android.app.Activity;
 import android.app.BroadcastOptions;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -495,9 +494,7 @@
 
     private void launchSystemDialer(Uri handle) {
         Intent systemDialerIntent = new Intent();
-        systemDialerIntent.setComponent(
-                new ComponentName(mDefaultDialerCache.getSystemDialerApplication(),
-                    mContext.getResources().getString(R.string.dialer_default_class)));
+        systemDialerIntent.setComponent(mDefaultDialerCache.getDialtactsSystemDialerComponent());
         systemDialerIntent.setAction(Intent.ACTION_DIAL);
         systemDialerIntent.setData(handle);
         systemDialerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 5c821a4..a5291e7 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -42,9 +42,9 @@
 
     /**
      * A list of extra keys which should be removed from a {@link ParcelableCall} when it is being
-     * generated for the purpose of sending to a dialer other than the system dialer.
+     * generated for the purpose of sending to a incallservice other than the system incallservice.
      * By convention we only pass keys namespaced with android.*, however there are some keys which
-     * should not be passed to non-system dialer apps either.
+     * should not be passed to non-system incallservice apps either.
      */
     private static List<String> EXTRA_KEYS_TO_SANITIZE;
     static {
@@ -90,9 +90,9 @@
      *      {@link InCallService} which supports external calls or not.
      * @param includeRttCall {@code true} if the RTT call should be included, {@code false}
      *      otherwise.
-     * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
-     *      {@code false} otherwise.  When parceling for the system dialer, the entire call extras
-     *      is included.  When parceling for anything other than the system dialer, some extra key
+     * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
+     *      {@code false} otherwise.  When parceling for the system incallservice, the entire call extras
+     *      is included.  When parceling for anything other than the system incallservice, some extra key
      *      values will be stripped for privacy sake.
      */
     public static ParcelableCall toParcelableCall(
@@ -101,10 +101,10 @@
             PhoneAccountRegistrar phoneAccountRegistrar,
             boolean supportsExternalCalls,
             boolean includeRttCall,
-            boolean isForSystemDialer) {
+            boolean isForSystemInCallService) {
         return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
                 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
-                includeRttCall, isForSystemDialer);
+                includeRttCall, isForSystemInCallService);
     }
 
     /**
@@ -120,9 +120,9 @@
      *      {@link InCallService} which supports external calls or not.
      * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
      *      override to whatever is defined in the call.
-     * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
-     *      {@code false} otherwise.  When parceling for the system dialer, the entire call extras
-     *      is included.  When parceling for anything other than the system dialer, some extra key
+     * @param isForSystemInCallService {@code true} if this call is being parcelled for the system incallservice,
+     *      {@code false} otherwise.  When parceling for the system incallservice, the entire call extras
+     *      is included.  When parceling for anything other than the system incallservice, some extra key
      *      values will be stripped for privacy sake.
      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
      */
@@ -133,7 +133,7 @@
             boolean supportsExternalCalls,
             int overrideState,
             boolean includeRttCall,
-            boolean isForSystemDialer) {
+            boolean isForSystemInCallService) {
         int state;
         if (overrideState == CALL_STATE_OVERRIDE_NONE) {
             state = getParcelableState(call, supportsExternalCalls);
@@ -216,7 +216,7 @@
         }
 
         Bundle extras;
-        if (isForSystemDialer) {
+        if (isForSystemInCallService) {
             extras = call.getExtras();
         } else {
             extras = sanitizeExtras(call.getExtras());
@@ -269,9 +269,9 @@
      *     <li>Caller number verification status (verstat)</li>
      * </ul>
      * All other fields are nulled or set to 0 values.
-     * Where the call screening service is part of the system dialer, the
+     * Where the call screening service is part of the system incallservice, the
      * {@link Connection#EXTRA_SIP_INVITE} header information is also sent to the call screening
-     * service (since the system dialer has access to this anyways).
+     * service (since the system incallservice has access to this anyways).
      * @param call The telecom call to send to a call screening service.
      * @param areRestrictedExtrasIncluded {@code true} if the set of restricted extras defined in
      *                                    {@link #RESTRICTED_CALL_SCREENING_EXTRA_KEYS} are to
@@ -333,7 +333,7 @@
 
     /**
      * Sanitize the extras bundle passed in, removing keys which should not be sent to non-system
-     * dialer apps.
+     * incallservice apps.
      * @param oldExtras Extras bundle to sanitize.
      * @return The sanitized extras bundle.
      */
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index ef2840a..9a4f7df 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -485,6 +486,7 @@
      * target phone account.
      * @return phone account handle of sim call manager based on the ongoing call.
      */
+    @Nullable
     public PhoneAccountHandle getSimCallManagerFromCall(Call call) {
         if (call == null) {
             return null;
@@ -1264,11 +1266,11 @@
             // Comparator which places PhoneAccounts with a specified sort order first, followed by
             // those with no sort order.
             Comparator<PhoneAccount> bySortOrder = (p1, p2) -> {
-                String sort1 = p1.getExtras() == null ? null :
-                        p1.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
-                String sort2 = p2.getExtras() == null ? null :
-                        p2.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null);
-                return nullSafeStringComparator.compare(sort1, sort2);
+                int sort1 = p1.getExtras() == null ? Integer.MAX_VALUE:
+                        p1.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
+                int sort2 = p2.getExtras() == null ? Integer.MAX_VALUE:
+                        p2.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
+                return Integer.compare(sort1, sort2);
             };
 
             // Comparator which sorts PhoneAccounts by label.
@@ -1597,10 +1599,16 @@
             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
         }
 
+        @Nullable
         protected Icon readIcon(XmlPullParser parser) throws IOException {
-            byte[] iconByteArray = Base64.decode(parser.getText(), 0);
-            ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
-            return Icon.createFromStream(stream);
+            try {
+                byte[] iconByteArray = Base64.decode(parser.getText(), 0);
+                ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
+                return Icon.createFromStream(stream);
+            } catch (IllegalArgumentException e) {
+                Log.e(this, e, "Bitmap must not be null.");
+                return null;
+            }
         }
     }
 
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index f2531ed..f02f7e8 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -17,8 +17,16 @@
 package com.android.server.telecom;
 
 import android.telecom.Log;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyRegistryManager;
+import android.telephony.emergency.EmergencyNumber;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
 
 /**
  * Send a {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} broadcast when the call state
@@ -52,6 +60,10 @@
             return;
         }
         updateStates(call);
+
+        if (call.isEmergencyCall() && !call.isIncoming()) {
+            sendOutgoingEmergencyCallEvent(call);
+        }
     }
 
     @Override
@@ -113,4 +125,31 @@
             Log.i(this, "Broadcasted state change: %s", mCurrentState);
         }
     }
+
+    private void sendOutgoingEmergencyCallEvent(Call call) {
+        TelephonyManager tm = mCallsManager.getContext().getSystemService(TelephonyManager.class);
+        String strippedNumber =
+                PhoneNumberUtils.stripSeparators(call.getHandle().getSchemeSpecificPart());
+        Optional<EmergencyNumber> emergencyNumber = tm.getEmergencyNumberList().values().stream()
+                .flatMap(List::stream)
+                .filter(numberObj -> Objects.equals(numberObj.getNumber(), strippedNumber))
+                .findFirst();
+
+        int subscriptionId = tm.getSubscriptionId(call.getTargetPhoneAccount());
+        SubscriptionManager subscriptionManager =
+                mCallsManager.getContext().getSystemService(SubscriptionManager.class);
+        int simSlotIndex = SubscriptionManager.DEFAULT_PHONE_INDEX;
+        if (subscriptionManager != null) {
+            SubscriptionInfo subInfo =
+                    subscriptionManager.getActiveSubscriptionInfo(subscriptionId);
+            if (subInfo != null) {
+                simSlotIndex = subInfo.getSimSlotIndex();
+            }
+        }
+
+        if (emergencyNumber.isPresent()) {
+            mRegistry.notifyOutgoingEmergencyCall(
+                    simSlotIndex, subscriptionId, emergencyNumber.get());
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/SystemStateHelper.java b/src/com/android/server/telecom/SystemStateHelper.java
index 073b081..3be3d5e 100644
--- a/src/com/android/server/telecom/SystemStateHelper.java
+++ b/src/com/android/server/telecom/SystemStateHelper.java
@@ -26,6 +26,7 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.net.Uri;
 import android.telecom.Log;
 
 import java.util.Set;
@@ -38,7 +39,7 @@
  * Provides various system states to the rest of the telecom codebase.
  */
 public class SystemStateHelper {
-    public static interface SystemStateListener {
+    public interface SystemStateListener {
         /**
          * Listener method to inform interested parties when a package name requests to enter or
          * exit car mode.
@@ -48,6 +49,12 @@
          *                              otherwise.
          */
         void onCarModeChanged(int priority, String packageName, boolean isCarMode);
+
+        /**
+         * Notifies when a package has been uninstalled.
+         * @param packageName the package name of the uninstalled package
+         */
+        void onPackageUninstalled(String packageName);
     }
 
     private final Context mContext;
@@ -62,7 +69,7 @@
                             UiModeManager.DEFAULT_PRIORITY);
                     String callingPackage = intent.getStringExtra(
                             UiModeManager.EXTRA_CALLING_PACKAGE);
-                    Log.i(SystemStateHelper.this, "ENTER_CAR_MODE_PRIVILEGED; priority=%d, pkg=%s",
+                    Log.i(SystemStateHelper.this, "ENTER_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
                             priority, callingPackage);
                     onEnterCarMode(priority, callingPackage);
                 } else if (UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED.equals(action)) {
@@ -70,11 +77,21 @@
                             UiModeManager.DEFAULT_PRIORITY);
                     String callingPackage = intent.getStringExtra(
                             UiModeManager.EXTRA_CALLING_PACKAGE);
-                    Log.i(SystemStateHelper.this, "EXIT_CAR_MODE_PRIVILEGED; priority=%d, pkg=%s",
+                    Log.i(SystemStateHelper.this, "EXIT_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
                             priority, callingPackage);
                     onExitCarMode(priority, callingPackage);
+                } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                    Uri data = intent.getData();
+                    if (data == null) {
+                        Log.w(SystemStateHelper.this,
+                                "Got null data for package removed, ignoring");
+                        return;
+                    }
+                    mListeners.forEach(
+                            l -> l.onPackageUninstalled(data.getEncodedSchemeSpecificPart()));
                 } else {
-                    Log.w(this, "Unexpected intent received: %s", intent.getAction());
+                    Log.w(SystemStateHelper.this,
+                            "Unexpected intent received: %s", intent.getAction());
                 }
             } finally {
                 Log.endSession();
@@ -88,11 +105,16 @@
     public SystemStateHelper(Context context) {
         mContext = context;
 
-        IntentFilter intentFilter = new IntentFilter(
+        IntentFilter intentFilter1 = new IntentFilter(
                 UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
-        intentFilter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
-        Log.i(this, "Registering car mode receiver: %s", intentFilter);
+        intentFilter1.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+
+        IntentFilter intentFilter2 = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter2.addDataScheme("package");
+        mContext.registerReceiver(mBroadcastReceiver, intentFilter1);
+        mContext.registerReceiver(mBroadcastReceiver, intentFilter2);
+        Log.i(this, "Registering broadcast receiver: %s", intentFilter1);
+        Log.i(this, "Registering broadcast receiver: %s", intentFilter2);
 
         mIsCarMode = getSystemCarMode();
     }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 9ccae9a..1ee77a3 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -727,7 +727,7 @@
         public ComponentName getDefaultPhoneApp() {
             try {
                 Log.startSession("TSI.gDPA");
-                return mDefaultDialerCache.getSystemDialerComponent();
+                return mDefaultDialerCache.getDialtactsSystemDialerComponent();
             } finally {
                 Log.endSession();
             }
@@ -1754,6 +1754,32 @@
             }
         }
 
+        /**
+         * A method intended for use in testing to clean up any calls that get stuck in the
+         * {@link CallState#DISCONNECTED} or {@link CallState#DISCONNECTING} states. Stuck calls
+         * during CTS cause cascading failures, so if the CTS test detects such a state, it should
+         * call this method via a shell command to clean up before moving on to the next test.
+         */
+        @Override
+        public void cleanupStuckCalls() {
+            Log.startSession("TCI.cSC");
+            try {
+                synchronized (mLock) {
+                    enforceShellOnly(Binder.getCallingUid(), "cleanupStuckCalls");
+                    Binder.withCleanCallingIdentity(() -> {
+                        for (Call call : mCallsManager.getCalls()) {
+                            if (call.getState() == CallState.DISCONNECTED
+                                    || call.getState() == CallState.DISCONNECTING) {
+                                mCallsManager.markCallAsRemoved(call);
+                            }
+                        }
+                    });
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+
         @Override
         public void setTestDefaultCallRedirectionApp(String packageName) {
             try {
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 807cc2d..08389b9 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -207,7 +207,8 @@
             ClockProxy clockProxy,
             RoleManagerAdapter roleManagerAdapter,
             IncomingCallFilter.Factory incomingCallFilterFactory,
-            ContactsAsyncHelper.Factory contactsAsyncHelperFactory) {
+            ContactsAsyncHelper.Factory contactsAsyncHelperFactory,
+            DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
         mContext = context.getApplicationContext();
         LogUtils.initLogging(mContext);
         DefaultDialerManagerAdapter defaultDialerAdapter =
@@ -241,7 +242,8 @@
         SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
 
         mMissedCallNotifier = missedCallNotifierImplFactory
-                .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache);
+                .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache,
+                        deviceIdleControllerAdapter);
         DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory =
                 new DisconnectedCallNotifier.Default();
 
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index a701b88..2309596 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -211,4 +211,15 @@
     public static long getCallRecordingToneRepeatIntervalMillis(ContentResolver contentResolver) {
         return get(contentResolver, "call_recording_tone_repeat_interval", 15000L /* 15 seconds */);
     }
+
+    /**
+     * Returns the number of milliseconds for which the system should exempt the default dialer from
+     * power save restrictions due to the dialer needing to handle a missed call notification
+     * (update call log, check VVM, etc...).
+     */
+    public static long getDialerMissedCallPowerSaveExemptionTimeMillis(
+            ContentResolver contentResolver) {
+        return get(contentResolver, "dialer_missed_call_power_save_exemption_time_millis",
+                30000L /*30 seconds*/);
+    }
 }
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 1e52c5a..486cd8d 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -289,7 +289,12 @@
 
     public void unbindCallScreeningService() {
         if (mConnection != null) {
-            mContext.unbindService(mConnection);
+            try {
+                mContext.unbindService(mConnection);
+            } catch (IllegalArgumentException e) {
+                Log.i(this, "Exception when unbind service %s : %s", mConnection,
+                        e.getMessage());
+            }
         }
         mConnection = null;
     }
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index e20da80..b6705f4 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -30,6 +30,10 @@
 import android.telecom.Log;
 
 import android.telecom.CallerInfoAsyncQuery;
+
+import com.android.internal.telecom.IInternalServiceRetriever;
+import com.android.internal.telecom.ITelecomLoader;
+import com.android.internal.telecom.ITelecomService;
 import com.android.server.telecom.AsyncRingtonePlayer;
 import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothPhoneServiceImpl;
@@ -41,16 +45,17 @@
 import com.android.server.telecom.ConnectionServiceFocusManager;
 import com.android.server.telecom.ContactsAsyncHelper;
 import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
 import com.android.server.telecom.HeadsetMediaButton;
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockControllerFactory;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InternalServiceRetrieverAdapter;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
 import com.android.server.telecom.ProximitySensorManagerFactory;
 import com.android.server.telecom.InCallWakeLockController;
 import com.android.server.telecom.ProximitySensorManager;
-import com.android.server.telecom.R;
 import com.android.server.telecom.RoleManagerAdapterImpl;
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.TelecomWakeLock;
@@ -68,10 +73,17 @@
     @Override
     public IBinder onBind(Intent intent) {
         Log.d(this, "onBind");
-        initializeTelecomSystem(this);
-        synchronized (getTelecomSystem().getLock()) {
-            return getTelecomSystem().getTelecomServiceImpl().getBinder();
-        }
+        return new ITelecomLoader.Stub() {
+            @Override
+            public ITelecomService createTelecomService(IInternalServiceRetriever retriever) {
+                InternalServiceRetrieverAdapter adapter =
+                        new InternalServiceRetrieverAdapter(retriever);
+                initializeTelecomSystem(TelecomService.this, adapter);
+                synchronized (getTelecomSystem().getLock()) {
+                    return getTelecomSystem().getTelecomServiceImpl().getBinder();
+                }
+            }
+        };
     }
 
     /**
@@ -84,7 +96,8 @@
      *
      * @param context
      */
-    static void initializeTelecomSystem(Context context) {
+    static void initializeTelecomSystem(Context context,
+            InternalServiceRetrieverAdapter internalServiceRetriever) {
         if (TelecomSystem.getInstance() == null) {
             NotificationChannelManager notificationChannelManager =
                     new NotificationChannelManager();
@@ -98,9 +111,11 @@
                                 public MissedCallNotifierImpl makeMissedCallNotifierImpl(
                                         Context context,
                                         PhoneAccountRegistrar phoneAccountRegistrar,
-                                        DefaultDialerCache defaultDialerCache) {
+                                        DefaultDialerCache defaultDialerCache,
+                                        DeviceIdleControllerAdapter idleControllerAdapter) {
                                     return new MissedCallNotifierImpl(context,
-                                            phoneAccountRegistrar, defaultDialerCache);
+                                            phoneAccountRegistrar, defaultDialerCache,
+                                            idleControllerAdapter);
                                 }
                             },
                             new CallerInfoAsyncQueryFactory() {
@@ -191,7 +206,8 @@
                             new RoleManagerAdapterImpl(context,
                                     (RoleManager) context.getSystemService(Context.ROLE_SERVICE)),
                             new IncomingCallFilter.Factory(),
-                            new ContactsAsyncHelper.Factory()));
+                            new ContactsAsyncHelper.Factory(),
+                            internalServiceRetriever.getDeviceIdleController()));
         }
         if (BluetoothAdapter.getDefaultAdapter() != null) {
             context.startService(new Intent(context, BluetoothPhoneService.class));
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
index 3549db5..1fe7c5f 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -38,6 +38,7 @@
 import android.provider.ContactsContract;
 import android.telephony.PhoneNumberFormattingTextWatcher;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
@@ -285,7 +286,7 @@
      * Add blocked number if it does not exist.
      */
     private void addBlockedNumber(String number) {
-        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+        if (isEmergencyNumber(this, number)) {
             Toast.makeText(
                     this,
                     getString(R.string.blocked_numbers_block_emergency_number_message),
@@ -298,6 +299,16 @@
         }
     }
 
+    private boolean isEmergencyNumber(Context context, String number) {
+        try {
+            TelephonyManager tm = (TelephonyManager) context.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+            return tm.isEmergencyNumber(number);
+        } catch (IllegalStateException ise) {
+            return false;
+        }
+    }
+
     @Override
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         // no-op
diff --git a/src/com/android/server/telecom/ui/IncomingCallNotifier.java b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
index 6e203aa..edea89b 100644
--- a/src/com/android/server/telecom/ui/IncomingCallNotifier.java
+++ b/src/com/android/server/telecom/ui/IncomingCallNotifier.java
@@ -41,6 +41,7 @@
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
 import com.android.server.telecom.components.TelecomBroadcastReceiver;
 
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 
@@ -68,7 +69,7 @@
     public static final int NOTIFICATION_INCOMING_CALL = 1;
     @VisibleForTesting
     public static final String NOTIFICATION_TAG = IncomingCallNotifier.class.getSimpleName();
-
+    private final Object mLock = new Object();
 
     public final Call.ListenerBase mCallListener = new Call.ListenerBase() {
         @Override
@@ -104,8 +105,10 @@
 
     @Override
     public void onCallAdded(Call call) {
-        if (!mCalls.contains(call)) {
-            mCalls.add(call);
+        synchronized (mLock) {
+            if (!mCalls.contains(call)) {
+                mCalls.add(call);
+            }
         }
 
         updateIncomingCall();
@@ -113,10 +116,11 @@
 
     @Override
     public void onCallRemoved(Call call) {
-        if (mCalls.contains(call)) {
-            mCalls.remove(call);
+        synchronized (mLock) {
+            if (mCalls.contains(call)) {
+                mCalls.remove(call);
+            }
         }
-
         updateIncomingCall();
     }
 
@@ -130,11 +134,16 @@
      * UI.
      */
     private void updateIncomingCall() {
-        Optional<Call> incomingCallOp = mCalls.stream()
-                .filter(call -> call.isSelfManaged() && call.isIncoming() &&
-                        call.getState() == CallState.RINGING &&
-                        call.getHandoverState() == HandoverState.HANDOVER_NONE)
-                .findFirst();
+        Optional<Call> incomingCallOp;
+        synchronized (mLock) {
+            incomingCallOp = mCalls.stream()
+                    .filter(Objects::nonNull)
+                    .filter(call -> call.isSelfManaged() && call.isIncoming() &&
+                            call.getState() == CallState.RINGING &&
+                            call.getHandoverState() == HandoverState.HANDOVER_NONE)
+                    .findFirst();
+        }
+
         Call incomingCall = incomingCallOp.orElse(null);
         if (incomingCall != null && mCallsManagerProxy != null &&
                 !mCallsManagerProxy.hasUnholdableCallsForOtherConnectionService(
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index a0eca8f..4e32c9f 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -19,8 +19,10 @@
 import static android.Manifest.permission.READ_PHONE_STATE;
 
 import android.annotation.NonNull;
+import android.app.BroadcastOptions;
 import android.content.ContentProvider;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
 import android.telecom.Logging.Runnable;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -29,11 +31,13 @@
 import com.android.server.telecom.CallsManagerListenerBase;
 import com.android.server.telecom.Constants;
 import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.R;
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
 import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.components.TelecomBroadcastReceiver;
 
 import android.app.Notification;
@@ -86,7 +90,8 @@
     public interface MissedCallNotifierImplFactory {
         MissedCallNotifier makeMissedCallNotifierImpl(Context context,
                 PhoneAccountRegistrar phoneAccountRegistrar,
-                DefaultDialerCache defaultDialerCache);
+                DefaultDialerCache defaultDialerCache,
+                DeviceIdleControllerAdapter deviceIdleControllerAdapter);
     }
 
     public interface NotificationBuilderFactory {
@@ -124,12 +129,14 @@
 
     private static final int MISSED_CALL_NOTIFICATION_ID = 1;
     private static final String NOTIFICATION_TAG = MissedCallNotifierImpl.class.getSimpleName();
+    private static final String MISSED_CALL_POWER_SAVE_REASON = "missed-call";
 
     private final Context mContext;
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final NotificationManager mNotificationManager;
     private final NotificationBuilderFactory mNotificationBuilderFactory;
     private final DefaultDialerCache mDefaultDialerCache;
+    private final DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
     private UserHandle mCurrentUserHandle;
 
     // Used to track the number of missed calls.
@@ -138,19 +145,22 @@
     private List<UserHandle> mUsersToLoadAfterBootComplete = new ArrayList<>();
 
     public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
-            DefaultDialerCache defaultDialerCache) {
+            DefaultDialerCache defaultDialerCache,
+            DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
         this(context, phoneAccountRegistrar, defaultDialerCache,
-                new DefaultNotificationBuilderFactory());
+                new DefaultNotificationBuilderFactory(), deviceIdleControllerAdapter);
     }
 
     public MissedCallNotifierImpl(Context context,
             PhoneAccountRegistrar phoneAccountRegistrar,
             DefaultDialerCache defaultDialerCache,
-            NotificationBuilderFactory notificationBuilderFactory) {
+            NotificationBuilderFactory notificationBuilderFactory,
+            DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
         mContext = context;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mNotificationManager =
                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mDeviceIdleControllerAdapter = deviceIdleControllerAdapter;
         mDefaultDialerCache = defaultDialerCache;
 
         mNotificationBuilderFactory = notificationBuilderFactory;
@@ -162,7 +172,8 @@
     public void clearMissedCalls(UserHandle userHandle) {
         // If the default dialer is showing the missed call notification then it will modify the
         // call log and we don't have to do anything here.
-        if (!shouldManageNotificationThroughDefaultDialer(userHandle)) {
+        String dialerPackage = getDefaultDialerPackage(userHandle);
+        if (!shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
             markMissedCallsAsRead(userHandle);
         }
         cancelMissedCallNotification(userHandle);
@@ -194,6 +205,15 @@
         }.prepare());
     }
 
+    private String getDefaultDialerPackage(UserHandle userHandle) {
+        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
+                userHandle.getIdentifier());
+        if (TextUtils.isEmpty(dialerPackage)) {
+            return null;
+        }
+        return dialerPackage;
+    }
+
     /**
      * Returns the missed-call notification intent to send to the default dialer for the given user.
      * Note, the passed in userHandle is always the non-managed user for SIM calls (multi-user
@@ -204,18 +224,16 @@
      * handle of the phone account. This could be a managed user. In that case we return the default
      * dialer for the given user which could be a managed (work profile) dialer.
      */
-    private Intent getShowMissedCallIntentForDefaultDialer(UserHandle userHandle) {
-        String dialerPackage = mDefaultDialerCache.getDefaultDialerApplication(
-                userHandle.getIdentifier());
-        if (TextUtils.isEmpty(dialerPackage)) {
-            return null;
-        }
+    private Intent getShowMissedCallIntentForDefaultDialer(String dialerPackage) {
         return new Intent(TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION)
             .setPackage(dialerPackage);
     }
 
-    private boolean shouldManageNotificationThroughDefaultDialer(UserHandle userHandle) {
-        Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle);
+    private boolean shouldManageNotificationThroughDefaultDialer(String dialerPackage,
+            UserHandle userHandle) {
+        if (TextUtils.isEmpty(dialerPackage)) return false;
+
+        Intent intent = getShowMissedCallIntentForDefaultDialer(dialerPackage);
         if (intent == null) {
             return false;
         }
@@ -225,9 +243,29 @@
         return receivers.size() > 0;
     }
 
-    private void sendNotificationThroughDefaultDialer(CallInfo callInfo, UserHandle userHandle) {
+    /**
+     * For dialers that manage missed call handling themselves, we must temporarily add them to the
+     * power save exemption list, as they must perform operations such as modifying the call log and
+     * power save restrictions can cause these types of operations to not complete (sometimes
+     * causing ANRs).
+     */
+    private Bundle exemptFromPowerSavingTemporarily(String dialerPackage, UserHandle handle) {
+        if (TextUtils.isEmpty(dialerPackage)) {
+            return null;
+        }
+        BroadcastOptions bopts = BroadcastOptions.makeBasic();
+        long duration = Timeouts.getDialerMissedCallPowerSaveExemptionTimeMillis(
+                mContext.getContentResolver());
+        mDeviceIdleControllerAdapter.exemptAppTemporarilyForEvent(dialerPackage, duration,
+                handle.getIdentifier(), MISSED_CALL_POWER_SAVE_REASON);
+        bopts.setTemporaryAppWhitelistDuration(duration);
+        return bopts.toBundle();
+    }
+
+    private void sendNotificationThroughDefaultDialer(String dialerPackage, CallInfo callInfo,
+            UserHandle userHandle) {
         int count = mMissedCallCounts.get(userHandle).get();
-        Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle)
+        Intent intent = getShowMissedCallIntentForDefaultDialer(dialerPackage)
             .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
             .putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT,
                     createClearMissedCallsPendingIntent(userHandle))
@@ -248,7 +286,8 @@
 
 
         Log.w(this, "Showing missed calls through default dialer.");
-        mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE);
+        Bundle options = exemptFromPowerSavingTemporarily(dialerPackage, userHandle);
+        mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE, options);
     }
 
     /**
@@ -276,8 +315,9 @@
         mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
         int missCallCounts = mMissedCallCounts.get(userHandle).incrementAndGet();
 
-        if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
-            sendNotificationThroughDefaultDialer(callInfo, userHandle);
+        String dialerPackage = getDefaultDialerPackage(userHandle);
+        if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
+            sendNotificationThroughDefaultDialer(dialerPackage, callInfo, userHandle);
             return;
         }
 
@@ -393,8 +433,9 @@
         mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0));
         mMissedCallCounts.get(userHandle).set(0);
 
-        if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
-            sendNotificationThroughDefaultDialer(null, userHandle);
+        String dialerPackage = getDefaultDialerPackage(userHandle);
+        if (shouldManageNotificationThroughDefaultDialer(dialerPackage, userHandle)) {
+            sendNotificationThroughDefaultDialer(dialerPackage, null, userHandle);
             return;
         }
 
@@ -518,7 +559,8 @@
             UserHandle userHandle) {
         Intent intent = new Intent(action, data, mContext, TelecomBroadcastReceiver.class);
         intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_USERHANDLE, userHandle);
-        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getBroadcast(mContext, 0, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
 
     /**
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 4238191..9c461ca 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -15,40 +15,41 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          coreApp="true"
-          package="com.android.server.telecom.testapps">
+     coreApp="true"
+     package="com.android.server.telecom.testapps">
 
-    <uses-sdk
-        android:minSdkVersion="28"
-        android:targetSdkVersion="30" />
+    <uses-sdk android:minSdkVersion="28"
+         android:targetSdkVersion="30"/>
 
-    <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <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.INTERNET" />
-    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
-    <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" />
+    <uses-permission android:name="android.permission.ACCEPT_HANDOVER"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <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.INTERNET"/>
+    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
+    <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" />
+        <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" >
+             android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.telecom.ConnectionService" />
+                <action android:name="android.telecom.ConnectionService"/>
             </intent-filter>
         </service>
 
-        <receiver android:name=".TestConnectionServiceReceiver">
+        <receiver android:name=".TestConnectionServiceReceiver"
+             android:exported="true">
             <intent-filter>
                 <action android:name="android.server.telecom.testapps.ACTION_SWITCH_PHONE_ACCOUNT"/>
                 <action android:name="android.server.telecom.testapps.ACTION_SWITCH_PHONE_ACCOUNT_WRONG"/>
@@ -56,23 +57,27 @@
         </receiver>
 
         <service android:name="com.android.server.telecom.testapps.TestConnectionManager"
-                 android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
+             android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.telecom.ConnectionService" />
+                <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" >
-            <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true"/>
+             android:process="com.android.server.telecom.testapps.TestInCallService"
+             android:permission="android.permission.BIND_INCALL_SERVICE"
+             android:exported="true">
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI"
+                 android:value="true"/>
             <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" >
+             android:process="com.android.server.telecom.testapps.TestInCallService"
+             android:exported="true">
             <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"/>
@@ -84,201 +89,212 @@
 
 
         <activity android:name="com.android.server.telecom.testapps.TestInCallUI"
-                android:process="com.android.server.telecom.testapps.TestInCallService"
-                android:label="@string/inCallUiAppLabel"
-                android:launchMode="singleInstance">
+             android:process="com.android.server.telecom.testapps.TestInCallService"
+             android:label="@string/inCallUiAppLabel"
+             android:launchMode="singleInstance"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.testapps.TestRttActivity"
-                  android:process="com.android.server.telecom.testapps.TestInCallService"
-                  android:label="@string/rttUiLabel"
-                  android:launchMode="singleInstance">
+             android:process="com.android.server.telecom.testapps.TestInCallService"
+             android:label="@string/rttUiLabel"
+             android:launchMode="singleInstance"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.testapps.TestCallActivity"
-                  android:theme="@android:style/Theme.NoDisplay"
-                  android:label="@string/testCallActivityLabel">
+             android:theme="@android:style/Theme.NoDisplay"
+             android:label="@string/testCallActivityLabel"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <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" />
+                <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" />
+                <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" />
+                <action android:name="android.telecom.testapps.ACTION_SEND_UPGRADE_REQUEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="int"/>
             </intent-filter>
             <intent-filter>
-                <action android:name="android.telecom.testapps.ACTION_RTT_CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="tel" />
+                <action android:name="android.telecom.testapps.ACTION_RTT_CALL"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="tel"/>
             </intent-filter>
             <intent-filter>
-                <action android:name="android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="android.telecom.testapps.ACTION_REMOTE_RTT_UPGRADE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
 
         <receiver android:name="com.android.server.telecom.testapps.CallNotificationReceiver"
-                  android:exported="false">
+             android:exported="false">
             <intent-filter>
-                <action android:name="com.android.server.telecom.testapps.ACTION_CALL_SERVICE_EXIT" />
+                <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">
+             android:label="@string/testDialerActivityLabel"
+             android:process="com.android.server.telecom.testapps.TestInCallService"
+             android:exported="true">
             <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" />
+                <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" />
+                <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" />
+                <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" />
+                <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" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.testapps.TestUssdActivity"
-                android:label="@string/UssdUiAppLabel"
-                android:launchMode="singleInstance">
+             android:label="@string/UssdUiAppLabel"
+             android:launchMode="singleInstance"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
           </activity>
 
         <activity android:name="com.android.server.telecom.testapps.TestCertActivity"
-                android:label="@string/KeyUiAppLabel"
-                android:launchMode="singleInstance">
+             android:label="@string/KeyUiAppLabel"
+             android:launchMode="singleInstance"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
           </activity>
 
         <activity android:name="com.android.server.telecom.testapps.SelfManagedCallingActivity"
-                  android:label="@string/selfManagedCallingActivityLabel"
-                  android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
-                  android:theme="@android:style/Theme.Material.Light">
+             android:label="@string/selfManagedCallingActivityLabel"
+             android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+             android:theme="@android:style/Theme.Material.Light"
+             android:exported="true">
           <intent-filter>
-              <action android:name="android.intent.action.MAIN" />
-              <category android:name="android.intent.category.DEFAULT" />
-              <category android:name="android.intent.category.LAUNCHER" />
+              <action android:name="android.intent.action.MAIN"/>
+              <category android:name="android.intent.category.DEFAULT"/>
+              <category android:name="android.intent.category.LAUNCHER"/>
           </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.testapps.IncomingSelfManagedCallActivity"
-                  android:label="@string/selfManagedCallingActivityLabel"
-                  android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+             android:label="@string/selfManagedCallingActivityLabel"
+             android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+             android:exported="true">
           <intent-filter>
-              <action android:name="android.intent.action.MAIN" />
+              <action android:name="android.intent.action.MAIN"/>
           </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.testapps.HandoverActivity"
-                  android:label="@string/selfManagedCallingActivityLabel"
-                  android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+             android:label="@string/selfManagedCallingActivityLabel"
+             android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+             android:exported="true">
           <intent-filter>
-              <action android:name="android.intent.action.MAIN" />
+              <action android:name="android.intent.action.MAIN"/>
           </intent-filter>
         </activity>
 
         <service android:name="com.android.server.telecom.testapps.SelfManagedConnectionService"
-                 android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
-                 android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+             android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+             android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+             android:exported="true">
           <intent-filter>
-              <action android:name="android.telecom.ConnectionService" />
+              <action android:name="android.telecom.ConnectionService"/>
           </intent-filter>
         </service>
 
         <receiver android:exported="false"
-            android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
-            android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver" />
+             android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+             android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver"/>
 
         <receiver android:exported="true"
-                  android:name="com.android.server.telecom.testapps.NuisanceReportReceiver">
+             android:name="com.android.server.telecom.testapps.NuisanceReportReceiver">
             <intent-filter>
-                <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
+                <action android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED"/>
             </intent-filter>
         </receiver>
 
-        <service
-            android:name=".TestCallScreeningService"
-            android:permission="android.permission.BIND_SCREENING_SERVICE">
+        <service android:name=".TestCallScreeningService"
+             android:permission="android.permission.BIND_SCREENING_SERVICE"
+             android:exported="true">
             <intent-filter>
                 <action android:name="android.telecom.CallScreeningService"/>
             </intent-filter>
         </service>
 
         <activity android:name=".CallScreeningActivity"
-                  android:configChanges="orientation|screenSize|keyboardHidden"
-                  android:excludeFromRecents="true"
-                  android:launchMode="singleInstance">
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance">
         </activity>
 
-        <service
-                android:name=".TestCallRedirectionService"
-                android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
+        <service android:name=".TestCallRedirectionService"
+             android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE"
+             android:exported="true">
             <intent-filter>
                 <action android:name="android.telecom.CallRedirectionService"/>
             </intent-filter>
         </service>
 
         <activity android:name=".CallRedirectionActivity"
-                  android:configChanges="orientation|screenSize|keyboardHidden"
-                  android:excludeFromRecents="true"
-                  android:launchMode="singleInstance">
+             android:configChanges="orientation|screenSize|keyboardHidden"
+             android:excludeFromRecents="true"
+             android:launchMode="singleInstance">
         </activity>
 
         <activity android:name=".PostCallActivity"
-                  android:label="@string/postCallActivityLabel">
+             android:label="@string/postCallActivityLabel"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.telecom.action.POST_CALL" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="android.telecom.action.POST_CALL"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
     </application>
diff --git a/testapps/carmodedialer/AndroidManifest.xml b/testapps/carmodedialer/AndroidManifest.xml
index 7f55f7e..f237211 100644
--- a/testapps/carmodedialer/AndroidManifest.xml
+++ b/testapps/carmodedialer/AndroidManifest.xml
@@ -15,75 +15,77 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          coreApp="true"
-          package="com.android.server.telecom.carmodedialer">
+     coreApp="true"
+     package="com.android.server.telecom.carmodedialer">
 
-    <uses-sdk
-        android:minSdkVersion="28"
-        android:targetSdkVersion="29" />
+    <uses-sdk android:minSdkVersion="28"
+         android:targetSdkVersion="29"/>
 
-    <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <uses-permission android:name="android.permission.CALL_PHONE" />
-    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
-    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.READ_CALL_LOG" />
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
-    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
+    <uses-permission android:name="android.permission.ACCEPT_HANDOVER"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.CALL_PHONE"/>
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
 
     <application android:label="Telecom CarMode">
-        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner"/>
 
         <service android:name="com.android.server.telecom.carmodedialer.CarModeInCallServiceImpl"
-                 android:permission="android.permission.BIND_INCALL_SERVICE" >
+             android:permission="android.permission.BIND_INCALL_SERVICE"
+             android:exported="true">
           <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
-                     android:value="true"/>
+               android:value="true"/>
           <intent-filter>
               <action android:name="android.telecom.InCallService"/>
           </intent-filter>
         </service>
 
         <activity android:name="com.android.server.telecom.carmodedialer.CarModeInCallUI"
-                android:label="CarMode Dialer"
-                android:launchMode="singleInstance">
+             android:label="CarMode Dialer"
+             android:launchMode="singleInstance"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
 
         <activity android:name="com.android.server.telecom.carmodedialer.CarModeDialerActivity"
-                  android:label="CarMode Dialer">
+             android:label="CarMode Dialer"
+             android:exported="true">
             <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" />
+                <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" />
+                <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" />
+                <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" />
+                <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" />
+                <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>
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
index abb9108..5c78d52 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionManager.java
@@ -37,7 +37,6 @@
 
 /**
  * Service which acts as a fake ConnectionManager if so configured.
- * TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
  */
 public class TestConnectionManager extends ConnectionService {
     public final class TestManagedConnection extends Connection {
diff --git a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
index f6fa116..3d1bc70 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestConnectionService.java
@@ -53,7 +53,6 @@
 
 /**
  * Service which provides fake calls to test the ConnectionService interface.
- * TODO: Rename all classes in the directory to Dummy* (e.g., DummyConnectionService).
  */
 public class TestConnectionService extends ConnectionService {
     /**
@@ -430,9 +429,9 @@
             int videoState = extras.getInt(EXTRA_START_VIDEO_STATE, VideoProfile.STATE_AUDIO_ONLY);
             Uri providedHandle = extras.getParcelable(EXTRA_HANDLE);
 
-            // Use dummy number for testing incoming calls.
+            // Use test number for testing incoming calls.
             Uri address = providedHandle == null ?
-                    Uri.fromParts(PhoneAccount.SCHEME_TEL, getDummyNumber(
+                    Uri.fromParts(PhoneAccount.SCHEME_TEL, getRandomNumber(
                             VideoProfile.isVideo(videoState)), null)
                     : providedHandle;
             connection.setVideoState(videoState);
@@ -480,7 +479,7 @@
             final Uri providedHandle = extras.getParcelable(EXTRA_HANDLE);
 
             Uri handle = providedHandle == null ?
-                    Uri.fromParts(PhoneAccount.SCHEME_TEL, getDummyNumber(false), null)
+                    Uri.fromParts(PhoneAccount.SCHEME_TEL, getRandomNumber(false), null)
                     : providedHandle;
 
             connection.setAddress(handle,  TelecomManager.PRESENTATION_ALLOWED);
@@ -613,7 +612,7 @@
      * @param isVideo {@code True} if the call is a video call.
      * @return The phone number.
      */
-    private String getDummyNumber(boolean isVideo) {
+    private String getRandomNumber(boolean isVideo) {
         int videoDigit = isVideo ? 1 : 0;
         int number = mRandom.nextInt(999);
         return String.format("555%s%03d", videoDigit, number);
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index 3fb2a84..02b35a4 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -27,4 +27,10 @@
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
+        <option name="screenshot-on-failure" value="false" />
+        <option name="bugreportz-on-failure" value="false" />
+        <option name="logcat-on-failure" value="true" />
+  </object>
 </configuration>
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index ec5f7ba..a64f39d 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.tests;
 
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -127,7 +129,8 @@
         Analytics.dump(ip);
         String dumpResult = sr.toString();
         String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
-                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
+                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService",
+                "missedReason"};
         for (String field : expectedFields) {
             assertTrue(dumpResult.contains(field));
         }
@@ -200,6 +203,8 @@
         assertTrue(callAnalytics2.startTime > 0);
         assertEquals(0, callAnalytics1.endTime);
         assertEquals(0, callAnalytics2.endTime);
+        assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics1.missedReason);
+        assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics2.missedReason);
 
         assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
         assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 6fd53eb..a8e1c00 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -163,6 +163,9 @@
                 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
         telecomManager.acceptRingingCall();
 
+        waitForHandlerAction(mTelecomSystem.getCallsManager()
+                .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
                 .answer(eq(ids.mConnectionId), any());
         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
@@ -219,6 +222,9 @@
                 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
         telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY);
 
+        waitForHandlerAction(mTelecomSystem.getCallsManager()
+                .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
         // The generic answer method on the ConnectionService is used to answer audio-only calls.
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
                 .answer(eq(ids.mConnectionId), any());
@@ -248,6 +254,9 @@
                 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
         telecomManager.acceptRingingCall(999 /* invalid videostate */);
 
+        waitForHandlerAction(mTelecomSystem.getCallsManager()
+                .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
         // Answer video API should be called
         verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
                 .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any());
@@ -626,6 +635,10 @@
         mConnectionServiceFixtureA.
                 sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
 
+        waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+                .getCallAudioModeStateMachine().getHandler(), TEST_TIMEOUT);
+        waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
+                .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
         verify(audioManager, timeout(TEST_TIMEOUT))
                 .abandonAudioFocusForCall();
         verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 58f1ee7..879ed0f 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -384,8 +384,12 @@
         // rest of the system
         verifyNoSystemAudioChanges();
 
+        // Special case for SPEAKER_ON -- we don't expect any route transitions to happen when
+        // there are no calls, so set the expected state to the initial route.
+        int expectedRoute = (mParams.action == CallAudioRouteStateMachine.SPEAKER_ON)
+                ? mParams.initialRoute : mParams.expectedRoute;
         // Verify the end state
-        CallAudioState expectedState = new CallAudioState(false, mParams.expectedRoute,
+        CallAudioState expectedState = new CallAudioState(false, expectedRoute,
                 mParams.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER,
                 mParams.expectedBluetoothDevice, mParams.availableBluetoothDevices);
         assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
@@ -811,7 +815,7 @@
                 "Speakerphone turned off externally during speaker", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
-                NONE, // speakerInteraction
+                OFF, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SPEAKER_OFF, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index 1345c01..c7b3a7e 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -211,6 +212,19 @@
 
     @SmallTest
     @Test
+    public void testUnbindingException() {
+        // Make sure that exceptions when unbinding won't make the device crash.
+        doThrow(new IllegalArgumentException()).when(mContext)
+                .unbindService(nullable(ServiceConnection.class));
+        CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
+                CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+                mAppLabelProxy, mParcelableCallUtilsConverter);
+        filter.startFilterLookup(inputResult);
+        filter.unbindCallScreeningService();
+    }
+
+    @SmallTest
+    @Test
     public void testAllowCall() throws Exception {
         CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
                 CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 4dffe59..3fd5e60 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -42,8 +42,11 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -56,6 +59,7 @@
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
 import android.widget.Toast;
 
 import com.android.server.telecom.AsyncRingtonePlayer;
@@ -116,6 +120,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -1019,7 +1025,7 @@
     @SmallTest
     @Test
     public void testHangupActiveCallWhenHeadsetMediaButtonLongPressDuringTwoCalls() {
-        // GIVEN an  ongoing call
+        // GIVEN an ongoing call
         Call ongoingCall = addSpyCall();
         doReturn(CallState.ACTIVE).when(ongoingCall).getState();
 
@@ -1381,6 +1387,80 @@
     }
 
     /**
+     * This test verifies a race condition seen with the new outgoing call broadcast.
+     * The scenario occurs when an incoming call is handled by an app which receives the
+     * NewOutgoingCallBroadcast.  That app cancels the call by modifying the new outgoing call
+     * broadcast.  Meanwhile, it places that same call again, expecting that Telecom will reuse the
+     * same same.  HOWEVER, if the system delays passing of the new outgoing call broadcast back to
+     * Telecom, the app will have placed a new outgoing call BEFORE telecom is aware that the call
+     * was cancelled.
+     * The consequence of this is that in CallsManager#startOutgoingCall, when we first get the
+     * call to reuse, it will come back empty.  Meanwhile, by the time we get into the various
+     * completable futures, the call WILL be in the list of calls which can be reused.  Since the
+     * reusable call was not found earlier on, we end up aborting the new outgoing call.
+     * @throws Exception
+     */
+    @SmallTest
+    @Test
+    public void testReuseCallConcurrency() throws Exception {
+        // Ensure contact info lookup succeeds
+        doAnswer(invocation -> {
+            Uri handle = invocation.getArgument(0);
+            CallerInfo info = new CallerInfo();
+            CompletableFuture<Pair<Uri, CallerInfo>> callerInfoFuture = new CompletableFuture<>();
+            callerInfoFuture.complete(new Pair<>(handle, info));
+            return callerInfoFuture;
+        }).when(mCallerInfoLookupHelper).startLookup(any(Uri.class));
+
+        // Ensure we have candidate phone account handle info.
+        when(mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(any(), any())).thenReturn(
+                SIM_1_HANDLE);
+        when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
+                any(), anyInt(), anyInt())).thenReturn(
+                new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
+
+        // Let's add an existing call which is in connecting state; this emulates the case where
+        // we have an outgoing call which we have not yet disconnected as a result of the new
+        // outgoing call broadcast cancelling the call.
+        Call outgoingCall = addSpyCall(CallState.CONNECTING);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        // Get the handler for the main looper, which is the same one the CallsManager will use.
+        // We'll post a little something to block up the handler for now.  This prevents
+        // startOutgoingCall from process it's completablefutures.
+        Handler handler = new Handler(Looper.getMainLooper());
+        handler.post(() -> {
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        });
+
+        // Now while the main handler is blocked up we'll start another outgoing call.
+        CompletableFuture<Call> callFuture = mCallsManager.startOutgoingCall(
+                outgoingCall.getHandle(), outgoingCall.getTargetPhoneAccount(), new Bundle(),
+                UserHandle.CURRENT, new Intent(), "com.test.stuff");
+
+        // And we'll add the initial outgoing call to the list of pending disconnects; this
+        // emulates a scenario where the pending disconnect call came in AFTER this call began.
+        mCallsManager.addToPendingCallsToDisconnect(outgoingCall);
+
+        // And we'll unblock the handler; this will let all the startOutgoingCall futures to happen.
+        latch.countDown();
+
+        // Wait for the future to become the present.
+        callFuture.join();
+
+        // We should have gotten a call out of this; if we did not then it means the call was
+        // aborted.
+        assertNotNull(callFuture.get());
+
+        // And the original call should be disconnected now.
+        assertEquals(CallState.DISCONNECTED, outgoingCall.getState());
+    }
+
+    /**
      * Ensures that if we have two calls hosted by the same connection manager, but with
      * different target phone accounts, we can swap between them.
      * @throws Exception
@@ -1460,7 +1540,6 @@
         // Mocks some methods to not call the real method.
         doNothing().when(callSpy).unhold();
         doNothing().when(callSpy).hold();
-        doNothing().when(callSpy).disconnect();
         doNothing().when(callSpy).answer(Matchers.anyInt());
         doNothing().when(callSpy).setStartWithSpeakerphoneOn(Matchers.anyBoolean());
 
diff --git a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
index 4ef4596..dbfcdb1 100644
--- a/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CarModeTrackerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.assertNull;
 
@@ -104,6 +105,17 @@
     }
 
     /**
+     * Ensure that we don't keep a package around after it's been removed from the device
+     */
+    @Test
+    public void testForceExitCarMode() {
+        testEnterCarModeBasic();
+        mCarModeTracker.forceExitCarMode(CAR_MODE_APP1_PACKAGE_NAME);
+        assertFalse(mCarModeTracker.isInCarMode());
+        assertNull(mCarModeTracker.getCurrentCarModePackage());
+    }
+
+    /**
      * Verifies only the first app at the default priority gets tracked.
      */
     @Test
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 7effc47..af062d7 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -39,6 +39,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -52,6 +53,7 @@
 import android.os.Handler;
 import android.os.IInterface;
 import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.CallAudioState;
@@ -320,6 +322,12 @@
         }
 
         @Override
+        public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+                Bundle options) {
+            // Override so that this can be verified via spy.
+        }
+
+        @Override
         public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
                 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
                 int initialCode, String initialData, Bundle initialExtras) {
@@ -434,6 +442,7 @@
             ArrayListMultimap.create();
     private final Map<ComponentName, IInterface> mServiceByComponentName = new HashMap<>();
     private final Map<ComponentName, ServiceInfo> mServiceInfoByComponentName = new HashMap<>();
+    private final Map<ComponentName, ActivityInfo> mActivityInfoByComponentName = new HashMap<>();
     private final Map<IInterface, ComponentName> mComponentNameByService = new HashMap<>();
     private final Map<ServiceConnection, IInterface> mServiceByServiceConnection = new HashMap<>();
 
@@ -507,6 +516,24 @@
             }
         }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
 
+        doAnswer(new Answer<List<ResolveInfo>>() {
+            @Override
+            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+                return doQueryIntentReceivers(
+                        (Intent) invocation.getArguments()[0],
+                        (Integer) invocation.getArguments()[1]);
+            }
+        }).when(mPackageManager).queryBroadcastReceivers((Intent) any(), anyInt());
+
+        doAnswer(new Answer<List<ResolveInfo>>() {
+            @Override
+            public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
+                return doQueryIntentReceivers(
+                        (Intent) invocation.getArguments()[0],
+                        (Integer) invocation.getArguments()[1]);
+            }
+        }).when(mPackageManager).queryBroadcastReceiversAsUser((Intent) any(), anyInt(), anyInt());
+
         // By default, tests use non-ui apps instead of 3rd party companion apps.
         when(mPackageManager.checkPermission(
                 matches(Manifest.permission.CALL_COMPANION_APP), anyString()))
@@ -585,6 +612,14 @@
                 eq(componentName.getPackageName()))).thenReturn(PackageManager.PERMISSION_GRANTED);
     }
 
+    public void addIntentReceiver(String action, ComponentName name) {
+        mComponentNamesByAction.put(action, name);
+        ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.packageName = name.getPackageName();
+        activityInfo.name = name.getClassName();
+        mActivityInfoByComponentName.put(name, activityInfo);
+    }
+
     public void putResource(int id, final String value) {
         when(mResources.getText(eq(id))).thenReturn(value);
         when(mResources.getString(eq(id))).thenReturn(value);
@@ -635,4 +670,14 @@
         }
         return result;
     }
+
+    private List<ResolveInfo> doQueryIntentReceivers(Intent intent, int flags) {
+        List<ResolveInfo> result = new ArrayList<>();
+        for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
+            ResolveInfo resolveInfo = new ResolveInfo();
+            resolveInfo.activityInfo = mActivityInfoByComponentName.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
index 46b1522..26f24ef 100755
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -249,6 +249,7 @@
 
         @Override
         public void createConnectionComplete(String id, Session.Info info) throws RemoteException {
+            Log.i(ConnectionServiceFixture.this, "createConnectionComplete: %s", id);
             mConnectionServiceDelegateAdapter.createConnectionComplete(id, null /*Session.Info*/);
         }
 
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index e16b598..9edbf05 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.matches;
 import static org.mockito.ArgumentMatchers.nullable;
@@ -34,11 +35,13 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.UiModeManager;
@@ -59,12 +62,12 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.telecom.InCallService;
-import android.telecom.Log;
 import android.telecom.ParcelableCall;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 
 import com.android.internal.telecom.IInCallAdapter;
@@ -98,6 +101,7 @@
 
 import java.util.Collections;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 @RunWith(JUnit4.class)
@@ -109,6 +113,7 @@
     @Mock PackageManager mMockPackageManager;
     @Mock Call mMockCall;
     @Mock Resources mMockResources;
+    @Mock AppOpsManager mMockAppOpsManager;
     @Mock MockContext mMockContext;
     @Mock Timeouts.Adapter mTimeoutsAdapter;
     @Mock DefaultDialerCache mDefaultDialerCache;
@@ -133,6 +138,10 @@
     private static final String CAR2_CLASS = "carcls";
     private static final int CAR_UID = 4;
     private static final int CAR2_UID = 5;
+    private static final String NONUI_PKG = "nonui_pkg";
+    private static final String NONUI_CLASS = "nonui_cls";
+    private static final int NONUI_UID = 6;
+
     private static final PhoneAccountHandle PA_HANDLE =
             new PhoneAccountHandle(new ComponentName("pa_pkg", "pa_cls"), "pa_id");
 
@@ -140,6 +149,8 @@
     private InCallController mInCallController;
     private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {};
     private EmergencyCallHelper mEmergencyCallHelper;
+    private SystemStateHelper.SystemStateListener mSystemStateListener;
+    private CarModeTracker mCarModeTracker = spy(new CarModeTracker());
 
     @Override
     @Before
@@ -148,6 +159,7 @@
         MockitoAnnotations.initMocks(this);
         when(mMockCall.getAnalytics()).thenReturn(new Analytics.CallInfo());
         doReturn(mMockResources).when(mMockContext).getResources();
+        doReturn(mMockAppOpsManager).when(mMockContext).getSystemService(AppOpsManager.class);
         doReturn(SYS_PKG).when(mMockResources).getString(
                 com.android.internal.R.string.config_defaultDialer);
         doReturn(SYS_CLASS).when(mMockResources).getString(R.string.incall_default_class);
@@ -160,7 +172,13 @@
         when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
         mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
                 mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
-                mEmergencyCallHelper, new CarModeTracker(), mClockProxy);
+                mEmergencyCallHelper, mCarModeTracker, mClockProxy);
+
+        ArgumentCaptor<SystemStateHelper.SystemStateListener> systemStateListenerArgumentCaptor
+                = ArgumentCaptor.forClass(SystemStateHelper.SystemStateListener.class);
+        verify(mMockSystemStateHelper).addListener(systemStateListenerArgumentCaptor.capture());
+        mSystemStateListener = systemStateListenerArgumentCaptor.getValue();
+
         when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);
         // Companion Apps don't have CONTROL_INCALL_EXPERIENCE permission.
@@ -177,6 +195,8 @@
                     return new String[] { CAR_PKG };
                 case CAR2_UID:
                     return new String[] { CAR2_PKG };
+                case NONUI_UID:
+                    return new String[] { NONUI_PKG };
             }
             return null;
         }).when(mMockPackageManager).getPackagesForUid(anyInt());
@@ -189,6 +209,9 @@
         when(mMockPackageManager.checkPermission(
                 matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
                 matches(CAR2_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mMockPackageManager.checkPermission(
+                matches(Manifest.permission.CONTROL_INCALL_EXPERIENCE),
+                matches(NONUI_PKG))).thenReturn(PackageManager.PERMISSION_GRANTED);
     }
 
     @Override
@@ -199,6 +222,24 @@
         super.tearDown();
     }
 
+    @SmallTest
+    @Test
+    public void testCarModeAppRemoval() {
+        setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+        when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
+        when(mMockSystemStateHelper.isCarMode()).thenReturn(true);
+
+        mSystemStateListener.onCarModeChanged(666, CAR_PKG, true);
+        verify(mCarModeTracker).handleEnterCarMode(666, CAR_PKG);
+        assertTrue(mCarModeTracker.isInCarMode());
+
+        mSystemStateListener.onPackageUninstalled(CAR_PKG);
+        verify(mCarModeTracker).forceExitCarMode(CAR_PKG);
+        assertFalse(mCarModeTracker.isInCarMode());
+    }
+
     @MediumTest
     @Test
     public void testBindToService_NoServicesFound_IncomingCall() throws Exception {
@@ -291,7 +332,8 @@
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
-                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+                eq(CURRENT_USER_ID));
 
         // Verify call for default dialer InCallService
         assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -350,7 +392,8 @@
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
-                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+                eq(CURRENT_USER_ID));
 
         // Verify call for default dialer InCallService
         assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -428,7 +471,8 @@
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
-                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+                eq(CURRENT_USER_ID));
 
         // Verify call for default dialer InCallService
         assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -510,7 +554,8 @@
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
-                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+                eq(CURRENT_USER_ID));
 
         // Verify call for default dialer InCallService
         assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -634,7 +679,8 @@
         ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
                 queryIntentCaptor.capture(),
-                eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+                eq(CURRENT_USER_ID));
 
         // Verify call for default dialer InCallService
         assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -884,13 +930,15 @@
                 nullable(ContentResolver.class))).thenReturn(500L);
 
         when(mMockCallsManager.getCalls()).thenReturn(Collections.singletonList(mMockCall));
-        setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
+        setupMockPackageManager(true /* default */, true /* nonui */, true /* system */,
+                false /* external calls */,
+                false /* self mgd in default*/, false /* self mgd in car*/);
         mInCallController.bindToServices(mMockCall);
 
         ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
                 ArgumentCaptor.forClass(ServiceConnection.class);
-        verify(mMockContext, times(1)).bindServiceAsUser(
+        verify(mMockContext, times(2)).bindServiceAsUser(
                 bindIntentCaptor.capture(),
                 serviceConnectionCaptor.capture(),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
@@ -903,13 +951,39 @@
 
         // Start the connection, make sure we don't unbind, and make sure that we don't send
         // anything to the in-call service yet.
-        ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
+        List<ServiceConnection> serviceConnections = serviceConnectionCaptor.getAllValues();
+        List<Intent> intents = bindIntentCaptor.getAllValues();
+
+        // Find the non-ui service and have it connect first.
+        int nonUiIdx = findFirstIndexMatching(intents,
+                i -> NONUI_PKG.equals(i.getComponent().getPackageName()));
+        if (nonUiIdx < 0) {
+            fail("Did not bind to non-ui incall");
+        }
+
+        {
+            ComponentName nonUiComponentName = new ComponentName(NONUI_PKG, NONUI_CLASS);
+            IBinder mockBinder = mock(IBinder.class);
+            IInCallService mockInCallService = mock(IInCallService.class);
+            when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+            serviceConnections.get(nonUiIdx).onServiceConnected(nonUiComponentName, mockBinder);
+
+            // Make sure the non-ui binding didn't trigger the future.
+            assertFalse(bindTimeout.isDone());
+        }
+
+        int defDialerIdx = findFirstIndexMatching(intents,
+                i -> DEF_PKG.equals(i.getComponent().getPackageName()));
+        if (defDialerIdx < 0) {
+            fail("Did not bind to default dialer incall");
+        }
+
         ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
         IBinder mockBinder = mock(IBinder.class);
         IInCallService mockInCallService = mock(IInCallService.class);
         when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
 
-        serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
+        serviceConnections.get(defDialerIdx).onServiceConnected(defDialerComponentName, mockBinder);
         verify(mockInCallService).setInCallAdapter(nullable(IInCallAdapter.class));
 
         // Make sure that the future completed without timing out.
@@ -1038,6 +1112,7 @@
             serviceInfo.applicationInfo = new ApplicationInfo();
             serviceInfo.applicationInfo.uid = DEF_UID;
             serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+            serviceInfo.enabled = true;
             serviceInfo.metaData = new Bundle();
             serviceInfo.metaData.putBoolean(
                     TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
@@ -1065,6 +1140,7 @@
                 serviceInfo.applicationInfo.uid = CAR2_UID;
             }
             serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+            serviceInfo.enabled = true;
             serviceInfo.metaData = new Bundle();
             serviceInfo.metaData.putBoolean(
                     TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI, true);
@@ -1086,6 +1162,7 @@
             serviceInfo.name = SYS_CLASS;
             serviceInfo.applicationInfo = new ApplicationInfo();
             serviceInfo.applicationInfo.uid = SYS_UID;
+            serviceInfo.enabled = true;
             serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
         }};
     }
@@ -1097,13 +1174,26 @@
             serviceInfo.name = COMPANION_CLASS;
             serviceInfo.applicationInfo = new ApplicationInfo();
             serviceInfo.applicationInfo.uid = COMPANION_UID;
+            serviceInfo.enabled = true;
+            serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+        }};
+    }
+
+    private ResolveInfo getNonUiResolveinfo() {
+        return new ResolveInfo() {{
+            serviceInfo = new ServiceInfo();
+            serviceInfo.packageName = NONUI_PKG;
+            serviceInfo.name = NONUI_CLASS;
+            serviceInfo.applicationInfo = new ApplicationInfo();
+            serviceInfo.applicationInfo.uid = NONUI_UID;
+            serviceInfo.enabled = true;
             serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
         }};
     }
 
     private void setupMockPackageManager(final boolean useDefaultDialer,
             final boolean useSystemDialer, final boolean includeExternalCalls) {
-        setupMockPackageManager(useDefaultDialer, useSystemDialer, includeExternalCalls,
+        setupMockPackageManager(useDefaultDialer, false, useSystemDialer, includeExternalCalls,
                 false /* self mgd */, false /* self mgd */);
     }
 
@@ -1111,6 +1201,16 @@
             final boolean useSystemDialer, final boolean includeExternalCalls,
             final boolean includeSelfManagedCallsInDefaultDialer,
             final boolean includeSelfManagedCallsInCarModeDialer) {
+        setupMockPackageManager(useDefaultDialer, false /* nonui */, useSystemDialer,
+                includeExternalCalls, includeSelfManagedCallsInDefaultDialer,
+                includeSelfManagedCallsInCarModeDialer);
+    }
+
+    private void setupMockPackageManager(final boolean useDefaultDialer,
+            final boolean useNonUiInCalls,
+            final boolean useSystemDialer, final boolean includeExternalCalls,
+            final boolean includeSelfManagedCallsInDefaultDialer,
+            final boolean includeSelfManagedCallsInCarModeDialer) {
         doAnswer(new Answer() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
@@ -1145,11 +1245,17 @@
                         resolveInfo.add(getCarModeResolveinfo(CAR2_PKG, CAR2_CLASS,
                                 includeExternalCalls, includeSelfManagedCallsInCarModeDialer));
                     }
+                } else {
+                    // InCallController uses a blank package name when querying for non-ui incalls
+                    if (useNonUiInCalls) {
+                        resolveInfo.add(getNonUiResolveinfo());
+                    }
                 }
+
                 return resolveInfo;
             }
         }).when(mMockPackageManager).queryIntentServicesAsUser(
-                any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+                any(Intent.class), anyInt(), eq(CURRENT_USER_ID));
     }
 
     private void setupMockPackageManagerLocationPermission(final String pkg,
diff --git a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
index 10a0194..db44dcd 100644
--- a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
@@ -16,6 +16,10 @@
 
 package com.android.server.telecom.tests;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.BroadcastOptions;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -43,6 +47,7 @@
 import com.android.server.telecom.CallerInfoLookupHelper;
 import com.android.server.telecom.Constants;
 import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
@@ -67,6 +72,8 @@
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
@@ -143,6 +150,9 @@
     private static final UserHandle SECONARY_USER = UserHandle.of(12);
     private static final int NO_CAPABILITY = 0;
     private static final int TEST_TIMEOUT = 1000;
+    private static final long TEST_POWER_EXEMPT_TIME_MS = 1000;
+    private static final ComponentName COMPONENT_NAME = new ComponentName(
+            "com.anything", "com.whatever");
 
     @Mock
     private NotificationManager mNotificationManager;
@@ -155,6 +165,7 @@
 
     @Mock TelecomSystem mTelecomSystem;
     @Mock private DefaultDialerCache mDefaultDialerCache;
+    @Mock private DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
 
     @Override
     @Before
@@ -246,7 +257,8 @@
                 makeNotificationBuilderFactory(builders);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
 
         missedCallNotifier.showMissedCallNotification(fakeCall);
         missedCallNotifier.showMissedCallNotification(fakeCall);
@@ -388,9 +400,9 @@
                 TelecomBroadcastReceiver.class);
 
         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
-                callBackIntent, PendingIntent.FLAG_NO_CREATE));
+                callBackIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
-                smsIntent, PendingIntent.FLAG_NO_CREATE));
+                smsIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
     }
 
     @SmallTest
@@ -401,7 +413,8 @@
                 makeNotificationBuilderFactory(builder1);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
 
         MissedCallNotifier.CallInfo fakeCall =
@@ -424,9 +437,9 @@
                 TelecomBroadcastReceiver.class);
 
         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
-                callBackIntent, PendingIntent.FLAG_NO_CREATE));
+                callBackIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
         assertNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
-                smsIntent, PendingIntent.FLAG_NO_CREATE));
+                smsIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE));
     }
 
     @SmallTest
@@ -461,7 +474,8 @@
                 makeNotificationBuilderFactory(builder1);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
 
         // AsyncQueryHandler used in reloadFromDatabase interacts poorly with the below
         // timeout-verify, so run this in a new handler to mitigate that.
@@ -530,7 +544,8 @@
                 makeNotificationBuilderFactory(builder1);
 
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
 
         // AsyncQueryHandler used in reloadFromDatabase interacts poorly with the below
         // timeout-verify, so run this in a new handler to mitigate that.
@@ -560,6 +575,49 @@
                 nullable(Notification.class), eq(PRIMARY_USER));
     }
 
+    @SmallTest
+    @Test
+    public void testDialerHandleMissedCall() {
+        // Configure Notifier to send missed call intent and let dialer handle
+        enableDialerHandlesMissedCall();
+
+        Notification.Builder builder1 = makeNotificationBuilder("builder1");
+        MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
+                makeNotificationBuilderFactory(builder1);
+
+        MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
+        PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
+
+        MissedCallNotifier.CallInfo fakeCall =
+                makeFakeCallInfo(SIP_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
+                        phoneAccount.getAccountHandle());
+        missedCallNotifier.showMissedCallNotification(fakeCall);
+
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        ArgumentCaptor<Bundle> bundleCaptor =
+                ArgumentCaptor.forClass(Bundle.class);
+        verify(mDeviceIdleControllerAdapter).exemptAppTemporarilyForEvent(
+                eq(COMPONENT_NAME.getPackageName()), anyLong(), anyInt(), any());
+        verify(mContext).sendBroadcastAsUser(
+                intentCaptor.capture(),
+                any(),
+                eq(android.Manifest.permission.READ_PHONE_STATE), bundleCaptor.capture());
+        assertNotNull("Not expecting null intent", intentCaptor.getValue());
+        assertEquals("Incorrect intent received",
+                TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION,
+                intentCaptor.getValue().getAction());
+        assertNotNull("Not expecting null options bundle", bundleCaptor.getValue());
+        BroadcastOptions options = new BroadcastOptions(bundleCaptor.getValue());
+        assertTrue("App must have a temporary exemption set.",
+                options.getTemporaryAppWhitelistDuration() > 0);
+
+        // A notification should never be posted by Telecom
+        verify(mNotificationManager, never()).notifyAsUser(nullable(String.class), anyInt(),
+                nullable(Notification.class), eq(PRIMARY_USER));
+    }
+
     private Notification.Builder makeNotificationBuilder(String label) {
         Notification.Builder builder = spy(new Notification.Builder(mContext));
         Notification notification = mock(Notification.class);
@@ -592,14 +650,14 @@
     private MissedCallNotifier makeMissedCallNotifier(
             NotificationBuilderFactory fakeBuilderFactory, UserHandle currentUser) {
         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
-                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory);
+                mPhoneAccountRegistrar, mDefaultDialerCache, fakeBuilderFactory,
+                mDeviceIdleControllerAdapter);
         missedCallNotifier.setCurrentUserHandle(currentUser);
         return missedCallNotifier;
     }
 
     private PhoneAccount makePhoneAccount(UserHandle userHandle, int capability) {
-        ComponentName componentName = new ComponentName("com.anything", "com.whatever");
-        PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "id",
+        PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(COMPONENT_NAME, "id",
                 userHandle);
         PhoneAccount.Builder builder = new PhoneAccount.Builder(phoneAccountHandle, "test");
         builder.setCapabilities(capability);
@@ -609,6 +667,13 @@
         return phoneAccount;
     }
 
+    private void enableDialerHandlesMissedCall() {
+        doReturn(COMPONENT_NAME.getPackageName()).when(mDefaultDialerCache).
+                getDefaultDialerApplication(anyInt());
+        mComponentContextFixture.addIntentReceiver(
+                TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION, COMPONENT_NAME);
+    }
+
     private IContentProvider getContentProviderForUser(int userId) {
         return mContext.getContentResolver().acquireProvider(userId + "@call_log");
     }
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
new file mode 100644
index 0000000..d2c832a
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import static android.provider.CallLog.Calls.AUTO_MISSED_EMERGENCY_CALL;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_DIALING;
+import static android.provider.CallLog.Calls.AUTO_MISSED_MAXIMUM_RINGING;
+import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.telecom.DisconnectCause;
+import android.telecom.TelecomManager;
+
+import com.android.server.telecom.Analytics;
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallIntentProcessor;
+import com.android.server.telecom.CallState;
+import com.android.server.telecom.CallsManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.Map;
+
+public class MissedInformationTest extends TelecomSystemTest {
+    private static final int TEST_TIMEOUT_MILLIS = 1000;
+    private static final String TEST_NUMBER = "650-555-1212";
+    private static final String TEST_NUMBER_1 = "7";
+    private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
+    @Mock ContentResolver mContentResolver;
+    @Mock IContentProvider mContentProvider;
+    @Mock Call mEmergencyCall;
+    @Mock Analytics.CallInfo mCallInfo;
+    private CallsManager mCallsManager;
+    private CallIntentProcessor.AdapterImpl mAdapter;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mCallsManager = mTelecomSystem.getCallsManager();
+        mAdapter = new CallIntentProcessor.AdapterImpl(mCallsManager.getDefaultDialerCache());
+        when(mContentResolver.getPackageName()).thenReturn(PACKAGE_NAME);
+        when(mContentResolver.acquireProvider(any(String.class))).thenReturn(mContentProvider);
+        when(mContentProvider.call(any(String.class), any(String.class),
+                any(String.class), any(Bundle.class))).thenReturn(new Bundle());
+        doReturn(mContentResolver).when(mSpyContext).getContentResolver();
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testNotMissedCall() throws Exception {
+        IdPair testCall = startAndMakeActiveIncomingCall(
+                TEST_NUMBER,
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.
+                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.LOCAL);
+        ContentValues values = verifyInsertionWithCapture();
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
+        assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics.missedReason);
+        assertEquals(MISSED_REASON_NOT_MISSED, (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+    }
+
+    @Test
+    public void testEmergencyCallPlacing() throws Exception {
+        Analytics.dumpToParcelableAnalytics();
+        setUpEmergencyCall();
+        mCallsManager.addCall(mEmergencyCall);
+        assertTrue(mCallsManager.isInEmergencyCall());
+
+        Intent intent = new Intent();
+        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+               mPhoneAccountA0.getAccountHandle());
+        mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+        ContentValues values = verifyInsertionWithCapture();
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        for (Analytics.CallInfoImpl ci : analyticsMap.values()) {
+            assertEquals(AUTO_MISSED_EMERGENCY_CALL, ci.missedReason);
+        }
+        assertEquals(AUTO_MISSED_EMERGENCY_CALL,
+                (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+    }
+
+    @Test
+    public void testMaximumDialingCalls() throws Exception {
+        Analytics.dumpToParcelableAnalytics();
+        IdPair testDialingCall = startAndMakeDialingOutgoingCall(
+                TEST_NUMBER,
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        Intent intent = new Intent();
+        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                mPhoneAccountA0.getAccountHandle());
+        mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+        ContentValues values = verifyInsertionWithCapture();
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        for (String callId : analyticsMap.keySet()) {
+            if (callId.equals(testDialingCall.mCallId)) {
+                continue;
+            }
+            assertEquals(AUTO_MISSED_MAXIMUM_DIALING, analyticsMap.get(callId).missedReason);
+        }
+        assertEquals(AUTO_MISSED_MAXIMUM_DIALING,
+                (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+    }
+
+    @Test
+    public void testMaximumRingingCalls() throws Exception {
+        Analytics.dumpToParcelableAnalytics();
+        IdPair testRingingCall = startAndMakeRingingIncomingCall(
+                TEST_NUMBER,
+                mPhoneAccountA0.getAccountHandle(),
+                mConnectionServiceFixtureA);
+
+        Intent intent = new Intent();
+        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                mPhoneAccountA0.getAccountHandle());
+        mAdapter.processIncomingCallIntent(mCallsManager, intent);
+
+        ContentValues values = verifyInsertionWithCapture();
+
+        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        for (String callId : analyticsMap.keySet()) {
+            if (callId.equals(testRingingCall.mCallId)) {
+                continue;
+            }
+            assertEquals(AUTO_MISSED_MAXIMUM_RINGING, analyticsMap.get(callId).missedReason);
+        }
+        assertEquals(AUTO_MISSED_MAXIMUM_RINGING,
+                (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+    }
+
+    private ContentValues verifyInsertionWithCapture() {
+        ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
+        verify(mContentResolver, timeout(TEST_TIMEOUT_MILLIS))
+                .insert(any(Uri.class), captor.capture());
+        return captor.getValue();
+    }
+
+    private void setUpEmergencyCall() {
+        when(mEmergencyCall.isEmergencyCall()).thenReturn(true);
+        when(mEmergencyCall.getIntentExtras()).thenReturn(new Bundle());
+        when(mEmergencyCall.getAnalytics()).thenReturn(mCallInfo);
+        when(mEmergencyCall.getState()).thenReturn(CallState.ACTIVE);
+        when(mEmergencyCall.getContext()).thenReturn(mSpyContext);
+        when(mEmergencyCall.getHandle()).thenReturn(Uri.parse("tel:" + TEST_NUMBER));
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index 9470008..a5b78b7 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -229,7 +229,7 @@
         mComponentContextFixture.putResource(R.string.dialer_default_class,
                 dialer_default_class_string);
         when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(ui_package_string);
-        when(mDefaultDialerCache.getSystemDialerComponent()).thenReturn(
+        when(mDefaultDialerCache.getDialtactsSystemDialerComponent()).thenReturn(
                 new ComponentName(ui_package_string, dialer_default_class_string));
 
         int result = processIntent(intent, false).disconnectCause;
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 00ef87c..a56036a 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -725,16 +725,20 @@
         mComponentContextFixture.addConnectionService(componentC,
                 Mockito.mock(IConnectionService.class));
 
+        Bundle account1Extras = new Bundle();
+        account1Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 1);
         PhoneAccount account1 = new PhoneAccount.Builder(
                 makeQuickAccountHandle(componentA, "c"), "c")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "A"))
+                .setExtras(account1Extras)
                 .build();
 
+        Bundle account2Extras = new Bundle();
+        account2Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 2);
         PhoneAccount account2 = new PhoneAccount.Builder(
                 makeQuickAccountHandle(componentB, "b"), "b")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
-                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "B"))
+                .setExtras(account2Extras)
                 .build();
 
         PhoneAccount account3 = new PhoneAccount.Builder(
@@ -814,18 +818,23 @@
                 Mockito.mock(IConnectionService.class));
         mComponentContextFixture.addConnectionService(componentZ,
                 Mockito.mock(IConnectionService.class));
+
+        Bundle account1Extras = new Bundle();
+        account1Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 2);
         PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(
                 makeQuickConnectionServiceComponentName(), "y"), "y")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
                         PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
-                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "2"))
+                .setExtras(account1Extras)
                 .build();
 
+        Bundle account2Extras = new Bundle();
+        account2Extras.putInt(PhoneAccount.EXTRA_SORT_ORDER, 1);
         PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(
                 makeQuickConnectionServiceComponentName(), "z"), "z")
                 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
                         PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
-                .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "1"))
+                .setExtras(account2Extras)
                 .build();
 
         PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(
diff --git a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
index 2de3c83..893ae3d 100644
--- a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.tests;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -23,9 +25,11 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -39,6 +43,7 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.SystemStateHelper;
@@ -53,11 +58,10 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.internal.util.reflection.FieldSetter;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Unit tests for SystemStateHelper
@@ -128,16 +132,53 @@
 
     @SmallTest
     @Test
-    public void testReceiverAndIntentFilter() {
-        ArgumentCaptor<IntentFilter> intentFilter = ArgumentCaptor.forClass(IntentFilter.class);
-        new SystemStateHelper(mContext);
-        verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
+    public void testPackageRemoved() {
+        ArgumentCaptor<BroadcastReceiver> receiver =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        new SystemStateHelper(mContext).addListener(mSystemStateListener);
+        verify(mContext, atLeastOnce())
+                .registerReceiver(receiver.capture(), any(IntentFilter.class));
+        Intent packageRemovedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+        packageRemovedIntent.setData(Uri.fromParts("package", "com.android.test", null));
+        receiver.getValue().onReceive(mContext, packageRemovedIntent);
+        verify(mSystemStateListener).onPackageUninstalled("com.android.test");
+    }
 
-        assertEquals(2, intentFilter.getValue().countActions());
-        assertEquals(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED,
-                intentFilter.getValue().getAction(0));
-        assertEquals(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED,
-                intentFilter.getValue().getAction(1));
+    @SmallTest
+    @Test
+    public void testReceiverAndIntentFilter() {
+        ArgumentCaptor<IntentFilter> intentFilterCaptor =
+                ArgumentCaptor.forClass(IntentFilter.class);
+        new SystemStateHelper(mContext);
+        verify(mContext, times(2)).registerReceiver(
+                any(BroadcastReceiver.class), intentFilterCaptor.capture());
+
+        Predicate<IntentFilter> carModeFilterTest = (intentFilter) ->
+                2 == intentFilter.countActions()
+                        && intentFilter.hasAction(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED)
+                        && intentFilter.hasAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+
+        Predicate<IntentFilter> packageRemovedFilterTest = (intentFilter) ->
+                1 == intentFilter.countActions()
+                        && intentFilter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+                        && intentFilter.hasDataScheme("package");
+
+        List<IntentFilter> capturedFilters = intentFilterCaptor.getAllValues();
+        assertEquals(2, capturedFilters.size());
+        for (IntentFilter filter : capturedFilters) {
+            if (carModeFilterTest.test(filter)) {
+                carModeFilterTest = (i) -> false;
+                continue;
+            }
+            if (packageRemovedFilterTest.test(filter)) {
+                packageRemovedFilterTest = (i) -> false;
+                continue;
+            }
+            String failString = String.format("Registered intent filters not correct. Got %s",
+                    capturedFilters.stream().map(IntentFilter::toString)
+                            .collect(Collectors.joining("\n")));
+            fail(failString);
+        }
     }
 
     @SmallTest
@@ -147,7 +188,8 @@
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         new SystemStateHelper(mContext).addListener(mSystemStateListener);
 
-        verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
+        verify(mContext, atLeastOnce())
+                .registerReceiver(receiver.capture(), any(IntentFilter.class));
 
         when(mIntentEnter.getAction()).thenReturn(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
         receiver.getValue().onReceive(mContext, mIntentEnter);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 442c310..aeb68c5 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -78,6 +79,7 @@
 import com.android.server.telecom.ClockProxy;
 import com.android.server.telecom.ConnectionServiceFocusManager;
 import com.android.server.telecom.ContactsAsyncHelper;
+import com.android.server.telecom.DeviceIdleControllerAdapter;
 import com.android.server.telecom.HeadsetMediaButton;
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockController;
@@ -207,6 +209,7 @@
     @Mock ClockProxy mClockProxy;
     @Mock RoleManagerAdapter mRoleManagerAdapter;
     @Mock ToneGenerator mToneGenerator;
+    @Mock DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
 
     final ComponentName mInCallServiceComponentNameX =
             new ComponentName(
@@ -348,6 +351,8 @@
         doReturn(mSpyContext).when(mSpyContext).getApplicationContext();
         doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any());
 
+        doReturn(mock(AppOpsManager.class)).when(mSpyContext).getSystemService(AppOpsManager.class);
+
         mHandlerThread = new HandlerThread("TelecomHandlerThread");
         mHandlerThread.start();
 
@@ -475,7 +480,8 @@
         when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null);
         mTelecomSystem = new TelecomSystem(
                 mComponentContextFixture.getTestDouble(),
-                (context, phoneAccountRegistrar, defaultDialerCache) -> mMissedCallNotifier,
+                (context, phoneAccountRegistrar, defaultDialerCache, mDeviceIdleControllerAdapter)
+                        -> mMissedCallNotifier,
                 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
                 headsetMediaButtonFactory,
                 proximitySensorManagerFactory,
@@ -535,7 +541,7 @@
                             ContactsAsyncHelper.ContentResolverAdapter adapter) {
                         return new ContactsAsyncHelper(adapter, mHandlerThread.getLooper());
                     }
-                });
+                }, mDeviceIdleControllerAdapter);
 
         mComponentContextFixture.setTelecomManager(new TelecomManager(
                 mComponentContextFixture.getTestDouble(),
@@ -925,7 +931,12 @@
         // Wait for the handler to start the CallerInfo lookup
         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
 
+        // Wait a few more times to address flakiness due to timing issues.
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+
         // Ensure callback to CS on successful creation happened.
+
         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
                 .createConnectionComplete(anyString(), any());
 
@@ -1111,6 +1122,54 @@
         return ids;
     }
 
+    protected IdPair startAndMakeDialingOutgoingCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
+                Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
+
+        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+        if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+            assertEquals(Call.STATE_DIALING,
+                    mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+            assertEquals(Call.STATE_DIALING,
+                    mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+        }
+
+        return ids;
+    }
+
+    protected IdPair startAndMakeRingingIncomingCall(
+            String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+        IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
+
+        if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
+            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);
+
+            waitForHandlerAction(mTelecomSystem.getCallsManager()
+                    .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
+
+            if (!VideoProfile.isVideo(VideoProfile.STATE_AUDIO_ONLY)) {
+                verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+                        .answer(eq(ids.mConnectionId), any());
+            } else {
+                verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+                        .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_AUDIO_ONLY),
+                                any());
+            }
+        }
+        return ids;
+    }
+
     protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
         int elapsed = 0;
         while (elapsed < TEST_TIMEOUT) {
diff --git a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
index b0b1ec0..264e087 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
@@ -25,8 +25,10 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
 public abstract class TelecomTestCase {
     protected static final String TESTING_TAG = "Telecom-TEST";
@@ -75,4 +77,13 @@
             }
         }
     }
+
+    protected static <T> int findFirstIndexMatching(List<T> items, Predicate<T> matcher) {
+        for (int i = 0; i < items.size(); i++) {
+            if (matcher.test(items.get(i))) {
+                return i;
+            }
+        }
+        return -1;
+    }
 }