Merge ab/7061308 into stage.

Bug: 180401296
Merged-In: I1f3c96de396b9bfbdee7496ae8e4e6691b7f9a8a
Change-Id: I47955dade0e6fa63283bfea5ef28e563a3fdcf44
diff --git a/Android.bp b/Android.bp
index 0d89b00..b7eb450 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 genrule {
     name: "statslog-telecom-java-gen",
     tools: ["stats-log-api-gen"],
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 8b7c37d..d6780ed 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -548,17 +548,19 @@
         private String getInCallServicesString() {
             StringBuilder s = new StringBuilder();
             s.append("[\n");
-            for (TelecomLogClass.InCallServiceInfo service : inCallServiceInfos) {
-                s.append("    ");
-                s.append("name: ");
-                s.append(service.getInCallServiceName());
-                s.append(" type: ");
-                s.append(service.getInCallServiceType());
-                s.append(" is crashed: ");
-                s.append(service.getIsNullBinding());
-                s.append(" service last time in ms: ");
-                s.append(service.getBoundDurationMillis());
-                s.append("\n");
+            if (inCallServiceInfos != null) {
+                for (TelecomLogClass.InCallServiceInfo service : inCallServiceInfos) {
+                    s.append("    ");
+                    s.append("name: ");
+                    s.append(service.getInCallServiceName());
+                    s.append(" type: ");
+                    s.append(service.getInCallServiceType());
+                    s.append(" is crashed: ");
+                    s.append(service.getIsNullBinding());
+                    s.append(" service last time in ms: ");
+                    s.append(service.getBoundDurationMillis());
+                    s.append("\n");
+                }
             }
             s.append("]");
             return s.toString();
@@ -631,7 +633,7 @@
     }
 
     public static CallInfo initiateCallAnalytics(String callId, int direction) {
-        Log.d(TAG, "Starting analytics for call " + callId);
+        Log.i(TAG, "Starting analytics for call " + callId);
         CallInfoImpl callInfo = new CallInfoImpl(callId, direction);
         synchronized (sLock) {
             while (sActiveCallIds.size() >= MAX_NUM_CALLS_TO_STORE) {
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index ffcdca9..c5f3bde 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -44,6 +44,7 @@
 import android.telecom.ConnectionService;
 import android.telecom.DisconnectCause;
 import android.telecom.GatewayInfo;
+import android.telecom.InCallService;
 import android.telecom.Log;
 import android.telecom.Logging.EventManager;
 import android.telecom.ParcelableConference;
@@ -58,6 +59,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -510,6 +512,15 @@
     private boolean mIsSelfManaged = false;
 
     /**
+     * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to
+     * expose the call to an {@link android.telecom.InCallService} which declares the metadata
+     * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS},
+     * For calls that {@link #mIsSelfManaged} is {@code false}, this value should be {@code false}
+     * as well.
+     */
+    private boolean mVisibleToInCallService = false;
+
+    /**
      * Indicates whether the {@link PhoneAccount} associated with this call supports video calling.
      * {@code True} if the phone account supports video calling, {@code false} otherwise.
      */
@@ -624,6 +635,18 @@
     private long mStartRingTime;
 
     /**
+     * The package name of the call screening service that silence this call. If the call is not
+     * silenced, this field will be null.
+     */
+    private CharSequence mCallScreeningAppName;
+
+    /**
+     * The component name of the call screening service that silence this call. If the call is not
+     * silenced, this field will be null.
+     */
+    private String mCallScreeningComponentName;
+
+    /**
      * Persists the specified parameters and initializes the new instance.
      * @param context The context.
      * @param repository The connection service repository.
@@ -1616,6 +1639,14 @@
         setConnectionProperties(getConnectionProperties());
     }
 
+    public boolean visibleToInCallService() {
+        return mVisibleToInCallService;
+    }
+
+    public void setVisibleToInCallService(boolean visibleToInCallService) {
+        mVisibleToInCallService = visibleToInCallService;
+    }
+
     public void markFinishedHandoverStateAndCleanup(int handoverState) {
         if (mHandoverSourceCall != null) {
             mHandoverSourceCall.setHandoverState(handoverState);
@@ -3906,6 +3937,10 @@
         mMissedReason = missedReason;
     }
 
+    public void setUserMissed(long code) {
+        mMissedReason |= code;
+    }
+
     public long getStartRingTime() {
         return mStartRingTime;
     }
@@ -3913,4 +3948,33 @@
     public void setStartRingTime(long startRingTime) {
         mStartRingTime = startRingTime;
     }
+
+    public CharSequence getCallScreeningAppName() {
+        return mCallScreeningAppName;
+    }
+
+    public void setCallScreeningAppName(CharSequence callScreeningAppName) {
+        mCallScreeningAppName = callScreeningAppName;
+    }
+
+    public String getCallScreeningComponentName() {
+        return mCallScreeningComponentName;
+    }
+
+    public void setCallScreeningComponentName(String callScreeningComponentName) {
+        mCallScreeningComponentName = callScreeningComponentName;
+    }
+
+    public void maybeOnInCallServiceTrackingChanged(boolean isTracking, boolean hasUi) {
+        if (mConnectionService == null) {
+            Log.w(this, "maybeOnInCallServiceTrackingChanged() request on a call"
+                    + " without a connection service.");
+        } else {
+            if (hasUi) {
+                mConnectionService.onUsingAlternativeUi(this, isTracking);
+            } else if (isTracking) {
+                mConnectionService.onTrackedByNonUiService(this, isTracking);
+            }
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 69a870f..bcfdedf 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -1272,6 +1272,7 @@
                     return HANDLED;
                 case SWITCH_FOCUS:
                     if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
+                        setSpeakerphoneOn(true);
                         transitionTo(mActiveSpeakerRoute);
                     }
                     return HANDLED;
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 7305ab9..7f864b8 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -141,6 +141,23 @@
             clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);
         }
 
+        if (intent.hasExtra(android.telecom.TelecomManager.EXTRA_PRIORITY)) {
+            clientExtras.putInt(android.telecom.TelecomManager.EXTRA_PRIORITY, intent.getIntExtra(
+                    android.telecom.TelecomManager.EXTRA_PRIORITY,
+                            android.telecom.TelecomManager.PRIORITY_NORMAL));
+        }
+
+        if (intent.hasExtra(android.telecom.TelecomManager.EXTRA_LOCATION)) {
+            clientExtras.putParcelable(android.telecom.TelecomManager.EXTRA_LOCATION,
+                    intent.getParcelableExtra(android.telecom.TelecomManager.EXTRA_LOCATION));
+        }
+
+        if (intent.hasExtra(android.telecom.TelecomManager.EXTRA_OUTGOING_PICTURE)) {
+            clientExtras.putParcelable(android.telecom.TelecomManager.EXTRA_OUTGOING_PICTURE,
+                    intent.getParcelableExtra(
+                            android.telecom.TelecomManager.EXTRA_OUTGOING_PICTURE));
+        }
+
         final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                 VideoProfile.STATE_AUDIO_ONLY);
         clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index cedd41c..3cec618 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -358,8 +358,10 @@
                 call.wasVolte());
 
         if (result == null) {
-            // Call auto missed before filtered
-            result = new CallFilteringResult.Builder().build();
+            result = new CallFilteringResult.Builder()
+                    .setCallScreeningAppName(call.getCallScreeningAppName())
+                    .setCallScreeningComponentName(call.getCallScreeningComponentName())
+                    .build();
         }
 
         if (callLogType == Calls.BLOCKED_TYPE || callLogType == Calls.MISSED_TYPE) {
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 6b99633..5b3c2f7 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -31,6 +31,8 @@
 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.USER_MISSED_CALL_FILTERS_TIMEOUT;
+import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -106,7 +108,6 @@
 import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
 import com.android.server.telecom.callfiltering.DirectToVoicemailFilter;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
 import com.android.server.telecom.callfiltering.IncomingCallFilterGraph;
 import com.android.server.telecom.callredirection.CallRedirectionProcessor;
 import com.android.server.telecom.components.ErrorDialogActivity;
@@ -356,7 +357,6 @@
     private final DisconnectedCallNotifier mDisconnectedCallNotifier;
     private IncomingCallNotifier mIncomingCallNotifier;
     private final CallerInfoLookupHelper mCallerInfoLookupHelper;
-    private final IncomingCallFilter.Factory mIncomingCallFilterFactory;
     private final DefaultDialerCache mDefaultDialerCache;
     private final Timeouts.Adapter mTimeoutsAdapter;
     private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
@@ -488,7 +488,6 @@
             CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory,
             InCallControllerFactory inCallControllerFactory,
             RoleManagerAdapter roleManagerAdapter,
-            IncomingCallFilter.Factory incomingCallFilterFactory,
             ToastFactory toastFactory) {
         mContext = context;
         mLock = lock;
@@ -506,7 +505,6 @@
         mTimeoutsAdapter = timeoutsAdapter;
         mEmergencyCallHelper = emergencyCallHelper;
         mCallerInfoLookupHelper = callerInfoLookupHelper;
-        mIncomingCallFilterFactory = incomingCallFilterFactory;
 
         mDtmfLocalTonePlayer =
                 new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy());
@@ -673,7 +671,7 @@
                     .setShouldReject(false)
                     .setShouldAddToCallLog(true)
                     .setShouldShowNotification(true)
-                    .build());
+                    .build(), false);
             incomingCall.setIsUsingCallFiltering(false);
             return;
         }
@@ -739,13 +737,19 @@
     }
 
     @Override
-    public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
+    public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result,
+            boolean timeout) {
         // 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 (timeout) {
+            Log.i(this, "onCallFilteringCompleted: Call filters timeout!");
+            incomingCall.setUserMissed(USER_MISSED_CALL_FILTERS_TIMEOUT);
+        }
+
         if (incomingCall.getState() != CallState.DISCONNECTED &&
                 incomingCall.getState() != CallState.DISCONNECTING) {
             setCallState(incomingCall, CallState.RINGING,
@@ -759,6 +763,7 @@
             incomingCall.setPostCallPackageName(
                     getRoleManagerAdapter().getDefaultCallScreeningApp());
 
+            Log.i(this, "onCallFilteringComplete: allow call.");
             if (hasMaximumManagedRingingCalls(incomingCall)) {
                 if (shouldSilenceInsteadOfReject(incomingCall)) {
                     incomingCall.silence();
@@ -767,6 +772,7 @@
                             "Exceeds maximum number of ringing calls.");
                     incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_RINGING);
                     autoMissCallAndLog(incomingCall, result);
+                    return;
                 }
             } else if (hasMaximumManagedDialingCalls(incomingCall)) {
                 if (shouldSilenceInsteadOfReject(incomingCall)) {
@@ -776,6 +782,7 @@
                             "dialing calls.");
                     incomingCall.setMissedReason(AUTO_MISSED_MAXIMUM_DIALING);
                     autoMissCallAndLog(incomingCall, result);
+                    return;
                 }
             } else if (result.shouldScreenViaAudio) {
                 Log.i(this, "onCallFilteringCompleted: starting background audio processing");
@@ -784,6 +791,9 @@
             } else if (result.shouldSilence) {
                 Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state");
                 incomingCall.setSilentRingingRequested(true);
+                incomingCall.setUserMissed(USER_MISSED_CALL_SCREENING_SERVICE_SILENCED);
+                incomingCall.setCallScreeningAppName(result.mCallScreeningAppName);
+                incomingCall.setCallScreeningComponentName(result.mCallScreeningComponentName);
                 addCall(incomingCall);
             } else {
                 addCall(incomingCall);
@@ -1227,10 +1237,14 @@
         PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
                 phoneAccountHandle);
         if (phoneAccount != null) {
+            Bundle phoneAccountExtras = phoneAccount.getExtras();
             call.setIsSelfManaged(phoneAccount.isSelfManaged());
             if (call.isSelfManaged()) {
                 // Self managed calls will always be voip audio mode.
                 call.setIsVoipAudioMode(true);
+                call.setVisibleToInCallService(phoneAccountExtras != null
+                        && phoneAccountExtras.getBoolean(
+                        PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true));
             } else {
                 // Incoming call is managed, the active call is self-managed and can't be held.
                 // We need to set extras on it to indicate whether answering will cause a 
@@ -1249,7 +1263,6 @@
                 }
             }
 
-            Bundle phoneAccountExtras = phoneAccount.getExtras();
             if (phoneAccountExtras != null
                     && phoneAccountExtras.getBoolean(
                             PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) {
@@ -1353,6 +1366,7 @@
             // 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);
+            call.getAnalytics().setMissedReason(call.getMissedReason());
             mCallLogManager.logCall(call, Calls.MISSED_TYPE,
                     true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/);
             if (isConference) {
@@ -1463,6 +1477,7 @@
 
         PhoneAccount account =
                 mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser);
+        Bundle phoneAccountExtra = account != null ? account.getExtras() : null;
         boolean isSelfManaged = account != null && account.isSelfManaged();
 
         // Create a call with original handle. The handle may be changed when the call is attached
@@ -1493,6 +1508,9 @@
             if (isSelfManaged) {
                 // Self-managed calls will ALWAYS use voip audio mode.
                 call.setIsVoipAudioMode(true);
+                call.setVisibleToInCallService(phoneAccountExtra != null
+                        && phoneAccountExtra.getBoolean(
+                                PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true));
             }
             call.setInitiatingUser(initiatingUser);
             isReusedCall = false;
@@ -3017,9 +3035,10 @@
      *
      * @param disconnectCause The disconnect cause, see {@link android.telecom.DisconnectCause}.
      */
-    void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
-      int oldState = call.getState();
-      if (call.getState() == CallState.SIMULATED_RINGING
+    @VisibleForTesting
+    public void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) {
+        int oldState = call.getState();
+        if (call.getState() == CallState.SIMULATED_RINGING
                 && disconnectCause.getCode() == DisconnectCause.REMOTE) {
             // If the remote end hangs up while in SIMULATED_RINGING, the call should
             // be marked as missed.
@@ -3487,7 +3506,7 @@
     @VisibleForTesting
     public void addCall(Call call) {
         Trace.beginSection("addCall");
-        Log.v(this, "addCall(%s)", call);
+        Log.i(this, "addCall(%s)", call);
         call.addListener(this);
         mCalls.add(call);
 
@@ -3599,10 +3618,14 @@
                         (newState == CallState.DISCONNECTED)) {
                     maybeSendPostCallScreenIntent(call);
                 }
-                if (((newState == CallState.ABORTED) || (newState == CallState.DISCONNECTED))
-                        && (call.getDisconnectCause().getCode() != DisconnectCause.MISSED)) {
+                int disconnectCode = call.getDisconnectCause().getCode();
+                if ((newState == CallState.ABORTED || newState == CallState.DISCONNECTED)
+                        && ((disconnectCode != DisconnectCause.MISSED)
+                        && (disconnectCode != DisconnectCause.CANCELED))) {
                     call.setMissedReason(MISSED_REASON_NOT_MISSED);
                 }
+                call.getAnalytics().setMissedReason(call.getMissedReason());
+
                 maybeShowErrorDialogOnDisconnect(call);
 
                 Trace.beginSection("onCallStateChanged");
@@ -4724,6 +4747,9 @@
         extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS,
               SystemClock.elapsedRealtime());
 
+        if (call.visibleToInCallService()) {
+            extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
+        }
         call.setIntentExtras(extras);
     }
 
@@ -4759,7 +4785,6 @@
      * @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;
         }
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 72c3f24..1cb3957 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1573,6 +1573,34 @@
         }
     }
 
+    /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */
+    @VisibleForTesting
+    public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) {
+        final String callId = mCallIdMapper.getCallId(activeCall);
+        if (callId != null && isServiceValid("onUsingAlternativeUi")) {
+            try {
+                logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi);
+                mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi,
+                        Log.getExternalSession(TELECOM_ABBREVIATION));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */
+    @VisibleForTesting
+    public void onTrackedByNonUiService(Call activeCall, boolean isTracked) {
+        final String callId = mCallIdMapper.getCallId(activeCall);
+        if (callId != null && isServiceValid("onTrackedByNonUiService")) {
+            try {
+                logOutgoing("onTrackedByNonUiService %s", isTracked);
+                mServiceInterface.onTrackedByNonUiService(callId, isTracked,
+                        Log.getExternalSession(TELECOM_ABBREVIATION));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     /** @see IConnectionService#disconnect(String, Session.Info) */
     void disconnect(Call call) {
         final String callId = mCallIdMapper.getCallId(call);
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 954aa44..e46d377 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -113,7 +113,7 @@
         public Call mCall;
     }
 
-    private class InCallServiceInfo {
+    public static class InCallServiceInfo {
         private final ComponentName mComponentName;
         private boolean mIsExternalCallsSupported;
         private boolean mIsSelfManagedCallsSupported;
@@ -279,7 +279,8 @@
             }
 
             if (call != null && call.isSelfManaged() &&
-                    !mInCallServiceInfo.isSelfManagedCallsSupported()) {
+                    (!mInCallServiceInfo.isSelfManagedCallsSupported()
+                            || !call.visibleToInCallService())) {
                 Log.i(this, "Skipping binding to %s - doesn't support self-mgd calls",
                         mInCallServiceInfo);
                 mIsConnected = false;
@@ -342,6 +343,7 @@
                             mInCallServiceInfo.getType(),
                             mInCallServiceInfo.getDisconnectTime()
                                     - mInCallServiceInfo.getBindingStartTime(), mIsNullBinding);
+                    updateCallTracking(mCall, mInCallServiceInfo, false /* isAdd */);
                 }
 
                 InCallController.this.onDisconnected(mInCallServiceInfo);
@@ -748,6 +750,10 @@
                 newConnection.connect(callToConnectWith);
             }
         }
+
+        public List<InCallServiceBindingConnection> getSubConnections() {
+            return mSubConnections;
+        }
     }
 
     private final Call.Listener mCallListener = new Call.ListenerBase() {
@@ -915,12 +921,12 @@
         @Override
         public void onPackageUninstalled(String packageName) {
             mCarModeTracker.forceExitCarMode(packageName);
-            updateCarModeForSwitchingConnection();
+            updateCarModeForConnections();
         }
     };
 
     private static final int IN_CALL_SERVICE_TYPE_INVALID = 0;
-    private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1;
+    private static final int IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI = 1;
     private static final int IN_CALL_SERVICE_TYPE_SYSTEM_UI = 2;
     private static final int IN_CALL_SERVICE_TYPE_CAR_MODE_UI = 3;
     private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4;
@@ -967,10 +973,9 @@
     private boolean mIsCallUsingMicrophone = false;
 
     public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
-            SystemStateHelper systemStateHelper,
-            DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
-            EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker,
-            ClockProxy clockProxy) {
+            SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
+            Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
+            CarModeTracker carModeTracker, ClockProxy clockProxy) {
         mContext = context;
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
         mLock = lock;
@@ -1013,12 +1018,16 @@
                     continue;
                 }
 
-                if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+                if (call.isSelfManaged() && (!call.visibleToInCallService()
+                        || !info.isSelfManagedCallsSupported())) {
                     continue;
                 }
 
                 // Only send the RTT call if it's a UI in-call service
-                boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+                boolean includeRttCall = false;
+                if (mInCallServiceConnection != null) {
+                    includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+                }
 
                 componentsUpdated.add(info.getComponentName());
                 IInCallService inCallService = entry.getValue();
@@ -1030,6 +1039,7 @@
                         info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 try {
                     inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+                    updateCallTracking(call, info, true /* isAdd */);
                 } catch (RemoteException ignored) {
                 }
             }
@@ -1079,7 +1089,8 @@
                     continue;
                 }
 
-                if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+                if (call.isSelfManaged() && !call.visibleToInCallService()
+                        && !info.isSelfManagedCallsSupported()) {
                     continue;
                 }
 
@@ -1096,6 +1107,7 @@
                         info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 try {
                     inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+                    updateCallTracking(call, info, true /* isAdd */);
                 } catch (RemoteException ignored) {
                 }
             }
@@ -1356,7 +1368,8 @@
 
     /**
      * Binds to all the UI-providing InCallService as well as system-implemented non-UI
-     * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} before invoking.
+     * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()}
+     * before invoking.
      *
      * @param call The newly added call that triggered the binding to the in-call services.
      */
@@ -1393,11 +1406,12 @@
 
         mInCallServiceConnection.chooseInitialInCallService(shouldUseCarModeUI());
 
-        // Actually try binding to the UI InCallService.  If the response
+        // Actually try binding to the UI InCallService.
         if (mInCallServiceConnection.connect(call) ==
-                InCallServiceConnection.CONNECTION_SUCCEEDED) {
+                InCallServiceConnection.CONNECTION_SUCCEEDED || call.isSelfManaged()) {
             // Only connect to the non-ui InCallServices if we actually connected to the main UI
-            // one.
+            // one, or if the call is self-managed (in which case we'd still want to keep Wear, BT,
+            // etc. informed.
             connectToNonUiInCallServices(call);
             mBindingFuture = new CompletableFuture<Boolean>().completeOnTimeout(false,
                     mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
@@ -1408,7 +1422,7 @@
         }
     }
 
-    private void connectToNonUiInCallServices(Call call) {
+    private void updateNonUiInCallServices() {
         List<InCallServiceInfo> nonUIInCallComponents =
                 getInCallServiceComponents(IN_CALL_SERVICE_TYPE_NON_UI);
         List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>();
@@ -1418,7 +1432,7 @@
         List<String> callCompanionApps = mCallsManager
                 .getRoleManagerAdapter().getCallCompanionApps();
         if (callCompanionApps != null && !callCompanionApps.isEmpty()) {
-            for(String pkg : callCompanionApps) {
+            for (String pkg : callCompanionApps) {
                 InCallServiceInfo info = getInCallServiceComponent(pkg,
                         IN_CALL_SERVICE_TYPE_COMPANION);
                 if (info != null) {
@@ -1426,7 +1440,14 @@
                 }
             }
         }
-        mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
+        mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(
+                nonUIInCalls);
+    }
+
+    private void connectToNonUiInCallServices(Call call) {
+        if (mNonUIInCallServiceConnections == null) {
+            updateNonUiInCallServices();
+        }
         mNonUIInCallServiceConnections.connect(call);
 
         IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
@@ -1443,7 +1464,7 @@
         InCallServiceInfo defaultDialerComponent =
                 (systemPackageName != null && systemPackageName.equals(packageName))
                 ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI)
-                : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI);
+                : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI);
         /* TODO: in Android 12 re-enable this an InCallService is required by the dialer role.
             if (packageName != null && defaultDialerComponent == null) {
                 // The in call service of default phone app is disabled, send notification.
@@ -1493,7 +1514,6 @@
 
     private List<InCallServiceInfo> getInCallServiceComponents(String packageName,
             ComponentName componentName, int requestedType) {
-
         List<InCallServiceInfo> retval = new LinkedList<>();
 
         Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
@@ -1525,13 +1545,19 @@
                 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));
+
+                boolean isRequestedType;
+                if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) {
+                    isRequestedType = true;
+                } else {
+                    isRequestedType = requestedType == currentType;
+                }
+                if (serviceInfo.enabled && isRequestedType) {
+                    retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported,
+                            isSelfManageCallsSupported, requestedType));
                 }
             }
         }
-
         return retval;
     }
 
@@ -1597,7 +1623,7 @@
                 mDefaultDialerCache.getDefaultDialerApplication(
                     mCallsManager.getCurrentUserHandle().getIdentifier()));
         if (isDefaultDialerPackage && isUIService) {
-            return IN_CALL_SERVICE_TYPE_DIALER_UI;
+            return IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI;
         }
 
         // Also allow any in-call service that has the control-experience permission (to ensure
@@ -1636,7 +1662,7 @@
 
         if (info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
                 || info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
-                || info.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+                || info.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) {
             trackCallingUserInterfaceStarted(info);
         }
         IInCallService inCallService = IInCallService.Stub.asInterface(service);
@@ -1662,13 +1688,17 @@
         int numCallsSent = 0;
         for (Call call : calls) {
             try {
-                if ((call.isSelfManaged() && !info.isSelfManagedCallsSupported()) ||
+                if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported()
+                        || !call.visibleToInCallService())) ||
                         (call.isExternalCall() && !info.isExternalCallsSupported())) {
                     continue;
                 }
 
                 // Only send the RTT call if it's a UI in-call service
-                boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+                boolean includeRttCall = false;
+                if (mInCallServiceConnection != null) {
+                    includeRttCall = info.equals(mInCallServiceConnection.getInfo());
+                }
 
                 // Track the call if we don't already know about it.
                 addCall(call);
@@ -1682,6 +1712,7 @@
                         info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI ||
                         info.getType() == IN_CALL_SERVICE_TYPE_NON_UI);
                 inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
+                updateCallTracking(call, info, true /* isAdd */);
             } catch (RemoteException ignored) {
             }
         }
@@ -1708,7 +1739,7 @@
         Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName());
         if (disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
                 || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
-                || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) {
+                || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) {
             trackCallingUserInterfaceStopped(disconnectedInfo);
         }
         mInCallServices.remove(disconnectedInfo);
@@ -1742,7 +1773,8 @@
                     continue;
                 }
 
-                if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+                if (call.isSelfManaged() && (!call.visibleToInCallService()
+                        || !info.isSelfManagedCallsSupported())) {
                     continue;
                 }
 
@@ -1823,7 +1855,7 @@
      */
     private ComponentName getConnectedUi() {
         InCallServiceInfo connectedUi = mInCallServices.keySet().stream().filter(
-                i -> i.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI
+                i -> i.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI
                         || i.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI)
                 .findAny()
                 .orElse(null);
@@ -1941,13 +1973,13 @@
             mCarModeTracker.handleExitCarMode(priority, packageName);
         }
 
-        updateCarModeForSwitchingConnection();
+        updateCarModeForConnections();
     }
 
-    public void updateCarModeForSwitchingConnection() {
+    public void updateCarModeForConnections() {
+        Log.i(this, "updateCarModeForConnections: car mode apps: %s",
+                mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
         if (mInCallServiceConnection != null) {
-            Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s",
-                    mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", ")));
             if (shouldUseCarModeUI()) {
                 mInCallServiceConnection.changeCarModeApp(
                         mCarModeTracker.getCurrentCarModePackage());
@@ -2057,4 +2089,11 @@
         notificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID,
                 builder.build());
     }
+
+    private void updateCallTracking(Call call, InCallServiceInfo info, boolean isAdd) {
+        int type = info.getType();
+        boolean hasUi = type == IN_CALL_SERVICE_TYPE_CAR_MODE_UI
+                || type == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI;
+        call.maybeOnInCallServiceTrackingChanged(isAdd, hasUi);
+    }
 }
diff --git a/src/com/android/server/telecom/RoleManagerAdapterImpl.java b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
index eb216d0..4a98d7b 100644
--- a/src/com/android/server/telecom/RoleManagerAdapterImpl.java
+++ b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
@@ -85,8 +85,11 @@
 
     @Override
     public void observeDefaultDialerApp(Executor executor, IntConsumer observer) {
-        mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, (roleName, user) ->
-                observer.accept(user.getIdentifier()), UserHandle.ALL);
+        mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, (roleName, user) -> {
+                    if (ROLE_DIALER.equals(roleName)) {
+                        observer.accept(user.getIdentifier());
+                    }
+                }, UserHandle.ALL);
     }
 
     @Override
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 72c372a..8928e76 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -20,7 +20,6 @@
 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
 import com.android.server.telecom.components.UserCallIntentProcessor;
 import com.android.server.telecom.components.UserCallIntentProcessorFactory;
 import com.android.server.telecom.ui.AudioProcessingNotification;
@@ -202,7 +201,6 @@
             CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory,
             ClockProxy clockProxy,
             RoleManagerAdapter roleManagerAdapter,
-            IncomingCallFilter.Factory incomingCallFilterFactory,
             ContactsAsyncHelper.Factory contactsAsyncHelperFactory,
             DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
         mContext = context.getApplicationContext();
@@ -306,7 +304,6 @@
                 callAudioModeStateMachineFactory,
                 inCallControllerFactory,
                 roleManagerAdapter,
-                incomingCallFilterFactory,
                 toastFactory);
 
         mIncomingCallNotifier = incomingCallNotifier;
diff --git a/src/com/android/server/telecom/callfiltering/CallFilterResultCallback.java b/src/com/android/server/telecom/callfiltering/CallFilterResultCallback.java
index 052ce57..1043774 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilterResultCallback.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilterResultCallback.java
@@ -18,5 +18,5 @@
 import com.android.server.telecom.Call;
 
 public interface CallFilterResultCallback {
-    void onCallFilteringComplete(Call call, CallFilteringResult result);
+    void onCallFilteringComplete(Call call, CallFilteringResult result, boolean timeout);
 }
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
deleted file mode 100644
index 860de1f..0000000
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom.callfiltering;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.telecom.Log;
-import android.telecom.Logging.Runnable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.telecom.Call;
-import com.android.server.telecom.LogUtils;
-import com.android.server.telecom.TelecomSystem;
-import com.android.server.telecom.Timeouts;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-
-import java.util.List;
-
-public class IncomingCallFilter implements CallFilterResultCallback {
-
-    public static class Factory {
-        public IncomingCallFilter create(Context context, CallFilterResultCallback listener,
-                Call call, TelecomSystem.SyncRoot lock, Timeouts.Adapter timeoutsAdapter,
-                List<CallFilter> filters) {
-            return new IncomingCallFilter(context, listener, call, lock, timeoutsAdapter, filters,
-                    new Handler(Looper.getMainLooper()));
-        }
-    }
-
-    public interface CallFilter {
-        void startFilterLookup(Call call, CallFilterResultCallback listener);
-    }
-
-    private final TelecomSystem.SyncRoot mTelecomLock;
-    private final Context mContext;
-    private final Handler mHandler;
-    private final List<CallFilter> mFilters;
-    private final Call mCall;
-    private final CallFilterResultCallback mListener;
-    private final Timeouts.Adapter mTimeoutsAdapter;
-
-    private CallFilteringResult mResult = new Builder()
-            .setShouldAllowCall(true)
-            .setShouldReject(false)
-            .setShouldAddToCallLog(true)
-            .setShouldShowNotification(true)
-            .build();
-
-    private boolean mIsPending = true;
-    private int mNumPendingFilters;
-
-    public IncomingCallFilter(Context context, CallFilterResultCallback listener, Call call,
-            TelecomSystem.SyncRoot lock, Timeouts.Adapter timeoutsAdapter,
-            List<CallFilter> filters, Handler handler) {
-        mContext = context;
-        mListener = listener;
-        mCall = call;
-        mTelecomLock = lock;
-        mFilters = filters;
-        mNumPendingFilters = filters.size();
-        mTimeoutsAdapter = timeoutsAdapter;
-        mHandler = handler;
-    }
-
-    public void performFiltering() {
-        Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);
-        for (CallFilter filter : mFilters) {
-            filter.startFilterLookup(mCall, this);
-        }
-        // synchronized to prevent a race on mResult and to enter into Telecom.
-        mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { // performFiltering time-out
-            @Override
-            public void loggedRun() {
-                if (mIsPending) {
-                    Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
-                    Log.addEvent(mCall, LogUtils.Events.FILTERING_TIMED_OUT);
-                    mListener.onCallFilteringComplete(mCall, mResult);
-                    mIsPending = false;
-                }
-            }
-        }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
-    }
-
-    public void onCallFilteringComplete(Call call, CallFilteringResult result) {
-        synchronized (mTelecomLock) { // synchronizing to prevent race on mResult
-            mNumPendingFilters--;
-            mResult = result.combine(mResult);
-            if (mNumPendingFilters == 0) {
-                // synchronized on mTelecomLock to enter into Telecom.
-                mHandler.post(new Runnable("ICF.oCFC", mTelecomLock) {
-                    @Override
-                    public void loggedRun() {
-                        if (mIsPending) {
-                            Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, mResult);
-                            mListener.onCallFilteringComplete(mCall, mResult);
-                            mIsPending = false;
-                        }
-                    }
-                }.prepare());
-            }
-        }
-    }
-
-    /**
-     * Returns the handler, for testing purposes.
-     */
-    @VisibleForTesting
-    public Handler getHandler() {
-        return mHandler;
-    }
-}
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
index 1543270..e3c68c9 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
@@ -73,7 +73,7 @@
             if (mFilter.equals(mDummyComplete)) {
                 synchronized (mLock) {
                     mFinished = true;
-                    mListener.onCallFilteringComplete(mCall, result);
+                    mListener.onCallFilteringComplete(mCall, result, false);
                     Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, result);
                 }
                 mHandlerThread.quit();
@@ -122,7 +122,7 @@
                 if (!mFinished) {
                     Log.i(this, "Graph timed out when performing filtering.");
                     Log.addEvent(mCall, LogUtils.Events.FILTERING_TIMED_OUT);
-                    mListener.onCallFilteringComplete(mCall, mCurrentResult);
+                    mListener.onCallFilteringComplete(mCall, mCurrentResult, true);
                     mFinished = true;
                     mHandlerThread.quit();
                 }
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 682990f..9ad0da4 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -57,7 +57,6 @@
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.TelecomWakeLock;
 import com.android.server.telecom.Timeouts;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
 import com.android.server.telecom.ui.IncomingCallNotifier;
 import com.android.server.telecom.ui.MissedCallNotifierImpl;
 import com.android.server.telecom.ui.NotificationChannelManager;
@@ -191,7 +190,6 @@
                             },
                             new RoleManagerAdapterImpl(context,
                                     (RoleManager) context.getSystemService(Context.ROLE_SERVICE)),
-                            new IncomingCallFilter.Factory(),
                             new ContactsAsyncHelper.Factory(),
                             internalServiceRetriever.getDeviceIdleController()));
         }
diff --git a/testapps/Android.bp b/testapps/Android.bp
index 26347fe..11ea474 100644
--- a/testapps/Android.bp
+++ b/testapps/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 android_test {
     name: "TelecomTestApps",
     static_libs: [
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 9c461ca..891a7a7 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -70,6 +70,8 @@
              android:exported="true">
             <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI"
                  android:value="true"/>
+            <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+                 android:value="true" />
             <intent-filter>
                 <action android:name="android.telecom.InCallService"/>
             </intent-filter>
diff --git a/testapps/carmodedialer/Android.bp b/testapps/carmodedialer/Android.bp
index 7179b1f..9f65b8c 100644
--- a/testapps/carmodedialer/Android.bp
+++ b/testapps/carmodedialer/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 android_test {
     name: "TelecomCarModeApp",
     static_libs: [
diff --git a/testapps/carmodedialer/AndroidManifest.xml b/testapps/carmodedialer/AndroidManifest.xml
index f237211..239726c 100644
--- a/testapps/carmodedialer/AndroidManifest.xml
+++ b/testapps/carmodedialer/AndroidManifest.xml
@@ -37,8 +37,10 @@
         <service android:name="com.android.server.telecom.carmodedialer.CarModeInCallServiceImpl"
              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"/>
+            <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+                       android:value="true"/>
+            <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+                       android:value="true"/>
           <intent-filter>
               <action android:name="android.telecom.InCallService"/>
           </intent-filter>
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index 28f4473..d26d629 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -90,7 +90,6 @@
     <LinearLayout android:orientation="horizontal"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content">
-
         <Button
             android:id="@+id/placeOutgoingCallButton"
             android:layout_width="wrap_content"
@@ -113,6 +112,35 @@
             android:text="Req CallScreen Role"/>
     </LinearLayout>
 
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content">
+        <Button
+            android:id="@+id/placeSelfManagedOutgoingCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="SelfManagedOutgoing"/>
+        <Button
+            android:id="@+id/placeSelfManagedIncomingCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="SelfManagedIncoming"/>
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content">
+        <Button
+            android:id="@+id/enableCarMode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Enable car mode"/>
+        <Button
+            android:id="@+id/disableCarMode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Disable car mode"/>
+    </LinearLayout>
     <ListView
         android:id="@+id/callList"
         android:layout_width="match_parent"
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index 4b5fa57..d4661ff 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -46,8 +46,10 @@
 
     public static String SELF_MANAGED_ACCOUNT_1 = "1";
     public static String SELF_MANAGED_ACCOUNT_2 = "2";
+    public static String SELF_MANAGED_ACCOUNT_3 = "3";
     public static String SELF_MANAGED_NAME_1 = "SuperCall";
     public static String SELF_MANAGED_NAME_2 = "Mega Call";
+    public static String SELF_MANAGED_NAME_3 = "SM Call";
     public static String CUSTOM_URI_SCHEME = "custom";
 
     private static SelfManagedCallList sInstance;
@@ -99,6 +101,8 @@
                 SELF_MANAGED_NAME_1, true /* areCallsLogged */);
         registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_2, SELF_MANAGED_ADDRESS_2,
                 SELF_MANAGED_NAME_2, false /* areCallsLogged */);
+        registerPhoneAccount(context, SELF_MANAGED_ACCOUNT_3, SELF_MANAGED_ADDRESS_1,
+                SELF_MANAGED_NAME_3, true /* areCallsLogged */);
     }
 
     public void registerPhoneAccount(Context context, String id, Uri address, String name,
@@ -110,6 +114,9 @@
         if (areCallsLogged) {
             extras.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true);
         }
+        if (id.equals(SELF_MANAGED_ACCOUNT_3)) {
+            extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
+        }
         PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index fd12a2e..44410d2 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -16,9 +16,12 @@
 
 package com.android.server.telecom.testapps;
 
+import static android.app.UiModeManager.DEFAULT_PRIORITY;
+
 import android.app.Activity;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.UiModeManager;
 import android.app.role.RoleManager;
 import android.content.Intent;
 import android.media.AudioAttributes;
@@ -54,9 +57,13 @@
     private SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
     private CheckBox mCheckIfPermittedBeforeCalling;
     private Button mPlaceOutgoingCallButton;
+    private Button mPlaceSelfManagedOutgoingCallButton;
+    private Button mPlaceSelfManagedIncomingCallButton;
     private Button mPlaceIncomingCallButton;
     private Button mHandoverFrom;
     private Button mRequestCallScreeningRole;
+    private Button mEnableCarMode;
+    private Button mDisableCarMode;
     private RadioButton mUseAcct1Button;
     private RadioButton mUseAcct2Button;
     private CheckBox mHoldableCheckbox;
@@ -119,6 +126,20 @@
                 placeOutgoingCall();
             }
         });
+        mPlaceSelfManagedOutgoingCallButton = (Button) findViewById(
+                R.id.placeSelfManagedOutgoingCallButton);
+        mPlaceSelfManagedOutgoingCallButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                placeSelfManagedOutgoingCall();
+            }
+        });
+        mPlaceSelfManagedIncomingCallButton = (Button) findViewById(
+                R.id.placeSelfManagedIncomingCallButton);
+        mPlaceSelfManagedIncomingCallButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) { placeSelfManagedIncomingCall(); }
+        });
         mPlaceIncomingCallButton = (Button) findViewById(R.id.placeIncomingCallButton);
         mPlaceIncomingCallButton.setOnClickListener(new View.OnClickListener() {
             @Override
@@ -134,7 +155,14 @@
         mRequestCallScreeningRole.setOnClickListener((v -> {
             requestCallScreeningRole();
         }));
-
+        mEnableCarMode = (Button) findViewById(R.id.enableCarMode);
+        mEnableCarMode.setOnClickListener((v -> {
+            enableCarMode();
+        }));
+        mDisableCarMode = (Button) findViewById(R.id.disableCarMode);
+        mDisableCarMode.setOnClickListener((v -> {
+            disableCarMode();
+        }));
         mUseAcct1Button = findViewById(R.id.useAcct1Button);
         mUseAcct2Button = findViewById(R.id.useAcct2Button);
         mHasFocus = findViewById(R.id.hasFocus);
@@ -184,6 +212,25 @@
         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
     }
 
+    private void placeSelfManagedOutgoingCall() {
+        TelecomManager tm = TelecomManager.from(this);
+        PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
+                SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
+
+        if (mCheckIfPermittedBeforeCalling.isChecked()) {
+            Toast.makeText(this, R.string.outgoingCallNotPermitted, Toast.LENGTH_SHORT).show();
+            return;
+        }
+
+        Bundle extras = new Bundle();
+        extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+        if (mVideoCallCheckbox.isChecked()) {
+            extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                    VideoProfile.STATE_BIDIRECTIONAL);
+        }
+        tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
+    }
+
     private void initiateHandover() {
         TelecomManager tm = TelecomManager.from(this);
         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
@@ -214,6 +261,37 @@
         tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
     }
 
+    private void placeSelfManagedIncomingCall() {
+        TelecomManager tm = TelecomManager.from(this);
+        PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
+                SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
+
+        if (mCheckIfPermittedBeforeCalling.isChecked()) {
+            if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
+                Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
+                return;
+            }
+        }
+
+        Bundle extras = new Bundle();
+        extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
+                Uri.parse(mNumber.getText().toString()));
+        tm.addNewIncomingCall(phoneAccountHandle, extras);
+    }
+
+    private void enableCarMode() {
+        UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+        uiModeManager.enableCarMode(0);
+        Toast.makeText(this, "Enabling car mode with priority " + DEFAULT_PRIORITY,
+                Toast.LENGTH_LONG).show();
+    }
+
+    private void disableCarMode() {
+        UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+        uiModeManager.disableCarMode(0);
+        Toast.makeText(this, "Disabling car mode", Toast.LENGTH_LONG).show();
+    }
+
     private void configureNotificationChannel() {
         NotificationChannel channel = new NotificationChannel(
                 SelfManagedConnection.INCOMING_CALL_CHANNEL_ID, "Incoming Calls",
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 24476f0..5592cf4 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -455,6 +455,37 @@
 
     @SmallTest
     @Test
+    public void testFocusChangeFromQuiescentSpeaker() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+                mThreadHandler.getLooper());
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
+        stateMachine.initialize(initState);
+
+        // Switch to active, pretending that a call came in.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+
+        // Make sure that we've successfully switched to the active speaker route and that we've
+        // called setSpeakerOn
+        assertTrue(stateMachine.isInActiveState());
+        verify(mockAudioManager).setSpeakerphoneOn(true);
+    }
+
+    @SmallTest
+    @Test
     public void testFocusChangeWithAlreadyActiveBtDevice() {
         CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
                 mContext,
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index 953c711..dfc3258 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -60,6 +60,7 @@
 
 import androidx.test.filters.FlakyTest;
 
+import com.android.server.telecom.Analytics;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallLogManager;
 import com.android.server.telecom.CallState;
@@ -89,6 +90,7 @@
     private PhoneAccountHandle mOtherUserAccountHandle;
     private PhoneAccountHandle mManagedProfileAccountHandle;
     private PhoneAccountHandle mSelfManagedAccountHandle;
+    private Analytics.CallInfo mCallInfo;
 
     private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234");
 
@@ -148,6 +150,7 @@
                 TEST_SELF_MGD_PHONE_ACCOUNT_ID,
                 UserHandle.of(CURRENT_USER_ID)
         );
+        mCallInfo = new Analytics.CallInfo();
 
         // Since we can't mock ContentResolver directly, use a ContentProvider
         when(mContext.getContentResolver()).thenReturn(ContentResolver.wrap(mContentProvider));
@@ -1006,6 +1009,7 @@
         when(fakeCall.getParentCall()).thenReturn(null);
         when(fakeCall.hadChildren()).thenReturn(true);
         when(fakeCall.hasProperty(eq(Connection.PROPERTY_REMOTELY_HOSTED))).thenReturn(false);
+        when(fakeCall.getAnalytics()).thenReturn(mCallInfo);
         return fakeCall;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallTest.java b/tests/src/com/android/server/telecom/tests/CallTest.java
index 541d278..d326a29 100644
--- a/tests/src/com/android/server/telecom/tests/CallTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallTest.java
@@ -19,13 +19,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.content.ComponentName;
 import android.net.Uri;
@@ -34,6 +38,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
 import android.widget.Toast;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -44,6 +49,8 @@
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.ClockProxy;
 import com.android.server.telecom.ConnectionServiceWrapper;
+import com.android.server.telecom.InCallController;
+import com.android.server.telecom.InCallController.InCallServiceInfo;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneNumberUtilsAdapter;
 import com.android.server.telecom.TelecomSystem;
@@ -54,17 +61,23 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 
 @RunWith(AndroidJUnit4.class)
 public class CallTest extends TelecomTestCase {
     private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
+    private static final ComponentName COMPONENT_NAME_1 = ComponentName
+            .unflattenFromString("com.foo/.Blah");
+    private static final ComponentName COMPONENT_NAME_2 = ComponentName
+            .unflattenFromString("com.bar/.Blah");
     private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
-            ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
+            COMPONENT_NAME_1, "Sim1");
     private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
             .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
                     | PhoneAccount.CAPABILITY_CALL_PROVIDER)
             .setIsEnabled(true)
             .build();
+    private static final long TIMEOUT_MILLIS = 1000;
 
     @Mock private CallsManager mMockCallsManager;
     @Mock private CallerInfoLookupHelper mMockCallerInfoLookupHelper;
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 3fd5e60..8378e3b 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -96,7 +96,6 @@
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
 import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
 import com.android.server.telecom.ui.AudioProcessingNotification;
 import com.android.server.telecom.ui.DisconnectedCallNotifier;
 import com.android.server.telecom.ui.ToastFactory;
@@ -111,8 +110,6 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -201,8 +198,6 @@
     @Mock private CallAudioModeStateMachine.Factory mCallAudioModeStateMachineFactory;
     @Mock private BluetoothStateReceiver mBluetoothStateReceiver;
     @Mock private RoleManagerAdapter mRoleManagerAdapter;
-    @Mock private IncomingCallFilter.Factory mIncomingCallFilterFactory;
-    @Mock private IncomingCallFilter mIncomingCallFilter;
     @Mock private ToastFactory mToastFactory;
     @Mock private Toast mToast;
 
@@ -225,8 +220,6 @@
                 anyInt())).thenReturn(mCallAudioRouteStateMachine);
         when(mCallAudioModeStateMachineFactory.create(any(), any()))
                 .thenReturn(mCallAudioModeStateMachine);
-        when(mIncomingCallFilterFactory.create(any(), any(), any(), any(), any(), any()))
-                .thenReturn(mIncomingCallFilter);
         when(mClockProxy.currentTimeMillis()).thenReturn(System.currentTimeMillis());
         when(mClockProxy.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
         when(mConnSvrFocusManagerFactory.create(any())).thenReturn(mConnectionSvrFocusMgr);
@@ -261,7 +254,6 @@
                 mCallAudioModeStateMachineFactory,
                 mInCallControllerFactory,
                 mRoleManagerAdapter,
-                mIncomingCallFilterFactory,
                 mToastFactory);
 
         when(mPhoneAccountRegistrar.getPhoneAccount(
@@ -1338,6 +1330,8 @@
     @Test
     public void testHandleSilenceVsBackgroundScreeningOrdering() throws Exception {
         Call screenedCall = mock(Call.class);
+        Bundle extra = new Bundle();
+        when(screenedCall.getIntentExtras()).thenReturn(extra);
         String appName = "blah";
         CallFilteringResult result = new CallFilteringResult.Builder()
                 .setShouldAllowCall(true)
@@ -1348,7 +1342,7 @@
                 .setShouldShowNotification(true)
                 .setCallScreeningAppName(appName)
                 .build();
-        mCallsManager.onCallFilteringComplete(screenedCall, result);
+        mCallsManager.onCallFilteringComplete(screenedCall, result, false);
 
         verify(mConnectionSvrFocusMgr).requestFocus(eq(screenedCall),
                 nullable(ConnectionServiceFocusManager.RequestFocusCallback.class));
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 26f24ef..5b4e800 100755
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -342,6 +342,14 @@
                 throws RemoteException { }
 
         @Override
+        public void onUsingAlternativeUi(String activeCallId, boolean usingAlternativeUi,
+                Session.Info info) throws RemoteException { }
+
+        @Override
+        public void onTrackedByNonUiService(String activeCallId, boolean isTracked,
+                Session.Info info) throws RemoteException { }
+
+        @Override
         public void playDtmfTone(String callId, char digit,
                 Session.Info info) throws RemoteException { }
 
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 6a6b9f3..0b926fe 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -876,6 +876,36 @@
         verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS);
     }
 
+    /**
+     * Ensures that the {@link InCallController} will bind to a non-ui service even if no ui service
+     * is bound if the call is self managed.
+     */
+    @MediumTest
+    @Test
+    public void testBindToService_NonUiSelfManaged() throws Exception {
+        setupMocks(false /* isExternalCall */, true);
+        setupMockPackageManager(false /* default */, true/* nonui */, true /* appop_nonui */,
+                true /* system */, false /* external calls */, false /* self mgd in default */,
+                false /* self mgd in car*/, true /* self managed in nonui */);
+
+        // we should bind to only the non ui app.
+        mInCallController.bindToServices(mMockCall);
+
+        // Bind InCallServices
+        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockContext, times(1)).bindServiceAsUser(
+                bindIntentCaptor.capture(),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+                eq(UserHandle.CURRENT));
+
+        // Verify bind
+        assertEquals(1, bindIntentCaptor.getAllValues().size());
+
+        // Should have bound to the third party non ui app.
+        verifyBinding(bindIntentCaptor, 0, NONUI_PKG, NONUI_CLASS);
+    }
 
     @MediumTest
     @Test
@@ -1160,6 +1190,7 @@
                 anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
         when(mMockCall.isExternalCall()).thenReturn(isExternalCall);
         when(mMockCall.isSelfManaged()).thenReturn(isSelfManagedCall);
+        when(mMockCall.visibleToInCallService()).thenReturn(isSelfManagedCall);
     }
 
     private ResolveInfo getDefResolveInfo(final boolean includeExternalCalls,
@@ -1238,7 +1269,7 @@
         }};
     }
 
-    private ResolveInfo getNonUiResolveinfo() {
+    private ResolveInfo getNonUiResolveinfo(boolean supportsSelfManaged) {
         return new ResolveInfo() {{
             serviceInfo = new ServiceInfo();
             serviceInfo.packageName = NONUI_PKG;
@@ -1247,6 +1278,11 @@
             serviceInfo.applicationInfo.uid = NONUI_UID;
             serviceInfo.enabled = true;
             serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+            serviceInfo.metaData = new Bundle();
+            if (supportsSelfManaged) {
+                serviceInfo.metaData.putBoolean(
+                        TelecomManager.METADATA_INCLUDE_SELF_MANAGED_CALLS, true);
+            }
         }};
     }
 
@@ -1282,6 +1318,18 @@
             final boolean useSystemDialer, final boolean includeExternalCalls,
             final boolean includeSelfManagedCallsInDefaultDialer,
             final boolean includeSelfManagedCallsInCarModeDialer) {
+        setupMockPackageManager(useDefaultDialer, useNonUiInCalls/* nonui */,
+                useAppOpNonUiInCalls/* appop_nonui */,
+                useSystemDialer, includeExternalCalls, includeSelfManagedCallsInDefaultDialer,
+                includeSelfManagedCallsInCarModeDialer, false);
+    }
+
+    private void setupMockPackageManager(final boolean useDefaultDialer,
+            final boolean useNonUiInCalls, final boolean useAppOpNonUiInCalls,
+            final boolean useSystemDialer, final boolean includeExternalCalls,
+            final boolean includeSelfManagedCallsInDefaultDialer,
+            final boolean includeSelfManagedCallsInCarModeDialer,
+            final boolean includeSelfManagedCallsInNonUi) {
         doAnswer(new Answer() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
@@ -1319,7 +1367,7 @@
                 } else {
                     // InCallController uses a blank package name when querying for non-ui incalls
                     if (useNonUiInCalls) {
-                        resolveInfo.add(getNonUiResolveinfo());
+                        resolveInfo.add(getNonUiResolveinfo(includeSelfManagedCallsInNonUi));
                     }
                     // InCallController uses a blank package name when querying for App Op non-ui incalls
                     if (useAppOpNonUiInCalls) {
diff --git a/tests/src/com/android/server/telecom/tests/IncomingCallFilterGraphTest.java b/tests/src/com/android/server/telecom/tests/IncomingCallFilterGraphTest.java
index 8c0adfb..9269836 100644
--- a/tests/src/com/android/server/telecom/tests/IncomingCallFilterGraphTest.java
+++ b/tests/src/com/android/server/telecom/tests/IncomingCallFilterGraphTest.java
@@ -112,7 +112,7 @@
     @Test
     public void testEmptyGraph() throws Exception {
         CompletableFuture<CallFilteringResult> testResult = new CompletableFuture<>();
-        CallFilterResultCallback listener = (call, result) -> testResult.complete(result);
+        CallFilterResultCallback listener = (call, result, timeout) -> testResult.complete(result);
 
         IncomingCallFilterGraph graph = new IncomingCallFilterGraph(mCall, listener, mContext,
                 mTimeoutsAdapter, mLock);
@@ -125,7 +125,7 @@
     @Test
     public void testFiltersPerformOrder() throws Exception {
         CompletableFuture<CallFilteringResult> testResult = new CompletableFuture<>();
-        CallFilterResultCallback listener = (call, result) -> testResult.complete(result);
+        CallFilterResultCallback listener = (call, result, timeout) -> testResult.complete(result);
 
         IncomingCallFilterGraph graph = new IncomingCallFilterGraph(mCall, listener, mContext,
                 mTimeoutsAdapter, mLock);
@@ -143,7 +143,7 @@
     @Test
     public void testFiltersPerformInParallel() throws Exception {
         CompletableFuture<CallFilteringResult> testResult = new CompletableFuture<>();
-        CallFilterResultCallback listener = (call, result) -> testResult.complete(result);
+        CallFilterResultCallback listener = (call, result, timeout) -> testResult.complete(result);
 
         IncomingCallFilterGraph graph = new IncomingCallFilterGraph(mCall, listener, mContext,
                 mTimeoutsAdapter, mLock);
@@ -162,7 +162,7 @@
     @Test
     public void testFiltersTimeout() throws Exception {
         CompletableFuture<CallFilteringResult> testResult = new CompletableFuture<>();
-        CallFilterResultCallback listener = (call, result) -> testResult.complete(result);
+        CallFilterResultCallback listener = (call, result, timeout) -> testResult.complete(result);
 
         IncomingCallFilterGraph graph = new IncomingCallFilterGraph(mCall, listener, mContext,
                 mTimeoutsAdapter, mLock);
diff --git a/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java b/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java
deleted file mode 100644
index 8e2d11e..0000000
--- a/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom.tests;
-
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.CallLog.Calls;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.telecom.Call;
-import com.android.server.telecom.Timeouts;
-import com.android.server.telecom.callfiltering.CallFilterResultCallback;
-import com.android.server.telecom.callfiltering.CallFilteringResult;
-import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
-import com.android.server.telecom.TelecomSystem;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(JUnit4.class)
-public class IncomingCallFilterTest extends TelecomTestCase {
-    @Mock private CallFilterResultCallback mResultCallback;
-    @Mock private Call mCall;
-    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {};
-
-    @Mock private IncomingCallFilter.CallFilter mFilter1;
-    @Mock private IncomingCallFilter.CallFilter mFilter2;
-    @Mock private IncomingCallFilter.CallFilter mFilter3;
-    @Mock private IncomingCallFilter.CallFilter mFilter4;
-
-    @Mock private Timeouts.Adapter mTimeoutsAdapter;
-
-    private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
-    private static final long LONG_TIMEOUT = 1000000;
-    private static final long SHORT_TIMEOUT = 100;
-
-    private static final CallFilteringResult PASS_CALL_RESULT =
-            new Builder()
-                    .setShouldAllowCall(true)
-                    .setShouldReject(false)
-                    .setShouldAddToCallLog(true)
-                    .setShouldShowNotification(true)
-                    .build();
-
-    private static final CallFilteringResult ASYNC_BLOCK_CHECK_BLOCK_RESULT =
-            new Builder()
-                    .setShouldAllowCall(false)
-                    .setShouldReject(true)
-                    .setShouldAddToCallLog(true)
-                    .setShouldShowNotification(false)
-                    .setCallBlockReason(Calls.BLOCK_REASON_BLOCKED_NUMBER)
-                    .setCallScreeningAppName(null)
-                    .setCallScreeningComponentName(null)
-                    .build();
-
-    private static final CallFilteringResult DIRECT_TO_VOICEMAIL_CALL_BLOCK_RESULT =
-            new Builder()
-                    .setShouldAllowCall(false)
-                    .setShouldReject(true)
-                    .setShouldAddToCallLog(true)
-                    .setShouldShowNotification(true)
-                    .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
-                    .setCallScreeningAppName(null)
-                    .setCallScreeningComponentName(null)
-                    .build();
-
-    private static final CallFilteringResult CALL_SCREENING_SERVICE_BLOCK_RESULT =
-            new Builder()
-                    .setShouldAllowCall(false)
-                    .setShouldReject(true)
-                    .setShouldAddToCallLog(false)
-                    .setShouldShowNotification(true)
-                    .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
-                    .setCallScreeningAppName("com.android.thirdparty")
-                    .setCallScreeningComponentName(
-                            "com.android.thirdparty/"
-                                    + "com.android.thirdparty.callscreeningserviceimpl")
-                    .build();
-
-    private static final CallFilteringResult DEFAULT_RESULT = PASS_CALL_RESULT;
-    private Handler mHandler = new Handler(Looper.getMainLooper());
-
-    @Override
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
-        when(mCall.getHandle()).thenReturn(TEST_HANDLE);
-        setTimeoutLength(LONG_TIMEOUT);
-    }
-
-    @Override
-    @After
-    public void tearDown() throws Exception {
-        mHandler.removeCallbacksAndMessages(null);
-        waitForHandlerAction(mHandler, 1000);
-        super.tearDown();
-    }
-
-    @SmallTest
-    @Test
-    public void testAsyncBlockCallResultFilter() {
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, ASYNC_BLOCK_CHECK_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq
-                (ASYNC_BLOCK_CHECK_BLOCK_RESULT));
-    }
-
-    @SmallTest
-    @Test
-    public void testDirectToVoiceMailCallResultFilter() {
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, DIRECT_TO_VOICEMAIL_CALL_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq
-                (DIRECT_TO_VOICEMAIL_CALL_BLOCK_RESULT));
-    }
-
-    @SmallTest
-    @Test
-    public void testCallScreeningServiceBlockCallResultFilter() {
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, CALL_SCREENING_SERVICE_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq
-                (CALL_SCREENING_SERVICE_BLOCK_RESULT));
-    }
-
-    @SmallTest
-    @Test
-    public void testPassCallResultFilter() {
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq(PASS_CALL_RESULT));
-    }
-
-    @SmallTest
-    @Test
-    public void testMultipleFiltersForAsyncBlockCheckFilter() {
-        List<IncomingCallFilter.CallFilter> filters =
-                new ArrayList<IncomingCallFilter.CallFilter>() {{
-                    add(mFilter1);
-                    add(mFilter2);
-                    add(mFilter3);
-                    add(mFilter4);
-                }};
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, filters, mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-        verify(mFilter2).startFilterLookup(mCall, testFilter);
-        verify(mFilter3).startFilterLookup(mCall, testFilter);
-        verify(mFilter4).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        testFilter.onCallFilteringComplete(mCall, ASYNC_BLOCK_CHECK_BLOCK_RESULT);
-        testFilter.onCallFilteringComplete(mCall, DIRECT_TO_VOICEMAIL_CALL_BLOCK_RESULT);
-        testFilter.onCallFilteringComplete(mCall, CALL_SCREENING_SERVICE_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq(new Builder()
-                .setShouldAllowCall(false)
-                .setShouldReject(true)
-                .setShouldAddToCallLog(false)
-                .setShouldShowNotification(false)
-                .setCallBlockReason(Calls.BLOCK_REASON_BLOCKED_NUMBER)
-                .setCallScreeningAppName(null)
-                .setCallScreeningComponentName(null)
-                .build()));
-    }
-
-    @SmallTest
-    @Test
-    public void testMultipleFiltersForDirectToVoicemailCallFilter() {
-        List<IncomingCallFilter.CallFilter> filters =
-                new ArrayList<IncomingCallFilter.CallFilter>() {{
-                    add(mFilter1);
-                    add(mFilter2);
-                    add(mFilter3);
-                }};
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, filters, mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-        verify(mFilter2).startFilterLookup(mCall, testFilter);
-        verify(mFilter3).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        testFilter.onCallFilteringComplete(mCall, DIRECT_TO_VOICEMAIL_CALL_BLOCK_RESULT);
-        testFilter.onCallFilteringComplete(mCall, CALL_SCREENING_SERVICE_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq(new Builder()
-                .setShouldAllowCall(false)
-                .setShouldReject(true)
-                .setShouldAddToCallLog(false)
-                .setShouldShowNotification(true)
-                .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
-                .setCallScreeningAppName(null)
-                .setCallScreeningComponentName(null)
-                .build()));
-    }
-
-    @SmallTest
-    @Test
-    public void testMultipleFiltersForCallScreeningServiceFilter() {
-        List<IncomingCallFilter.CallFilter> filters =
-                new ArrayList<IncomingCallFilter.CallFilter>() {{
-                    add(mFilter1);
-                    add(mFilter2);
-                }};
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, filters, mHandler);
-        testFilter.performFiltering();
-        verify(mFilter1).startFilterLookup(mCall, testFilter);
-        verify(mFilter2).startFilterLookup(mCall, testFilter);
-
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        testFilter.onCallFilteringComplete(mCall, CALL_SCREENING_SERVICE_BLOCK_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        verify(mResultCallback).onCallFilteringComplete(eq(mCall), eq(new Builder()
-                .setShouldAllowCall(false)
-                .setShouldReject(true)
-                .setShouldAddToCallLog(false)
-                .setShouldShowNotification(true)
-                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
-                .setCallScreeningAppName("com.android.thirdparty")
-                .setCallScreeningComponentName(
-                        "com.android.thirdparty/com.android.thirdparty.callscreeningserviceimpl")
-                .build()));
-    }
-
-    @SmallTest
-    @Test
-    public void testFilterTimeout() throws Exception {
-        setTimeoutLength(SHORT_TIMEOUT);
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        verify(mResultCallback, timeout((int) SHORT_TIMEOUT * 2)).onCallFilteringComplete(eq(mCall),
-                eq(DEFAULT_RESULT));
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        // verify that we don't report back again with the result
-        verify(mResultCallback, atMost(1)).onCallFilteringComplete(any(Call.class),
-                any(CallFilteringResult.class));
-    }
-
-    @SmallTest
-    @Test
-    public void testFilterTimeoutDoesntTrip() throws Exception {
-        setTimeoutLength(SHORT_TIMEOUT);
-        IncomingCallFilter testFilter = new IncomingCallFilter(mContext, mResultCallback, mCall,
-                mLock, mTimeoutsAdapter, Collections.singletonList(mFilter1), mHandler);
-        testFilter.performFiltering();
-        testFilter.onCallFilteringComplete(mCall, PASS_CALL_RESULT);
-        waitForHandlerAction(testFilter.getHandler(), SHORT_TIMEOUT * 2);
-        Thread.sleep(SHORT_TIMEOUT);
-        verify(mResultCallback, atMost(1)).onCallFilteringComplete(any(Call.class),
-                any(CallFilteringResult.class));
-    }
-
-    @SmallTest
-    @Test
-    public void testToString() {
-        assertEquals("[Allow, logged, notified]", PASS_CALL_RESULT.toString());
-        assertEquals("[Reject, notified, mCallBlockReason = 1, mCallScreeningAppName = com" +
-                ".android.thirdparty, mCallScreeningComponentName = com.android.thirdparty/com" +
-                ".android.thirdparty.callscreeningserviceimpl]",
-            CALL_SCREENING_SERVICE_BLOCK_RESULT.toString());
-        assertEquals("[Reject, logged, mCallBlockReason = 3]",
-            ASYNC_BLOCK_CHECK_BLOCK_RESULT.toString());
-    }
-
-    private void setTimeoutLength(long length) throws Exception {
-        when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
-                .thenReturn(length);
-    }
-}
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
index d2c832a..a8e1c5f 100644
--- a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -20,11 +20,14 @@
 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 android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT;
+import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED;
 
 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.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -44,6 +47,8 @@
 import com.android.server.telecom.CallIntentProcessor;
 import com.android.server.telecom.CallState;
 import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.callfiltering.CallFilteringResult;
 
 import org.junit.After;
 import org.junit.Before;
@@ -58,10 +63,14 @@
     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";
+    private static final String CALL_SCREENING_SERVICE_PACKAGE_NAME = "testapp";
+    private static final String CALL_SCREENING_COMPONENT_NAME = "testapp";
+
     @Mock ContentResolver mContentResolver;
     @Mock IContentProvider mContentProvider;
     @Mock Call mEmergencyCall;
     @Mock Analytics.CallInfo mCallInfo;
+    @Mock Call mIncomingCall;
     private CallsManager mCallsManager;
     private CallIntentProcessor.AdapterImpl mAdapter;
 
@@ -98,7 +107,8 @@
         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));
+        assertEquals(MISSED_REASON_NOT_MISSED,
+                (long) values.getAsLong(CallLog.Calls.MISSED_REASON));
     }
 
     @Test
@@ -116,11 +126,11 @@
         ContentValues values = verifyInsertionWithCapture();
 
         Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
+        assertEquals(AUTO_MISSED_EMERGENCY_CALL,
+                (long) values.getAsLong(CallLog.Calls.MISSED_REASON));
         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
@@ -146,7 +156,7 @@
             assertEquals(AUTO_MISSED_MAXIMUM_DIALING, analyticsMap.get(callId).missedReason);
         }
         assertEquals(AUTO_MISSED_MAXIMUM_DIALING,
-                (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+                (long) values.getAsLong(CallLog.Calls.MISSED_REASON));
     }
 
     @Test
@@ -172,7 +182,49 @@
             assertEquals(AUTO_MISSED_MAXIMUM_RINGING, analyticsMap.get(callId).missedReason);
         }
         assertEquals(AUTO_MISSED_MAXIMUM_RINGING,
-                (int) values.getAsInteger(CallLog.Calls.MISSED_REASON));
+                (long) values.getAsLong(CallLog.Calls.MISSED_REASON));
+    }
+
+    @Test
+    public void testCallFiltersTimeout() throws Exception {
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, true);
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                    new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_CALL_FILTERS_TIMEOUT) > 0);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_CALL_FILTERS_TIMEOUT) > 0);
+    }
+
+    @Test
+    public void testCallScreeningServiceSilence() throws Exception {
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .setShouldSilence(true)
+                .setCallScreeningAppName(CALL_SCREENING_SERVICE_PACKAGE_NAME)
+                .setCallScreeningComponentName(CALL_SCREENING_COMPONENT_NAME)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+        assertTrue(mIncomingCall.isIncoming());
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_CALL_SCREENING_SERVICE_SILENCED) > 0);
+        assertEquals(CALL_SCREENING_COMPONENT_NAME,
+                values.getAsString(CallLog.Calls.CALL_SCREENING_COMPONENT_NAME));
+        assertEquals(CALL_SCREENING_SERVICE_PACKAGE_NAME,
+                values.getAsString(CallLog.Calls.CALL_SCREENING_APP_NAME));
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_CALL_SCREENING_SERVICE_SILENCED) > 0);
     }
 
     private ContentValues verifyInsertionWithCapture() {
@@ -190,4 +242,16 @@
         when(mEmergencyCall.getContext()).thenReturn(mSpyContext);
         when(mEmergencyCall.getHandle()).thenReturn(Uri.parse("tel:" + TEST_NUMBER));
     }
+
+    private void setUpIncomingCall() throws Exception {
+        mIncomingCall = spy(new Call("0", mSpyContext, mCallsManager,
+                (TelecomSystem.SyncRoot) mTelecomSystem.getLock(),
+                null, mCallsManager.getPhoneNumberUtilsAdapter(), null,
+                null, null, mPhoneAccountA0.getAccountHandle(),
+                Call.CALL_DIRECTION_INCOMING, false, false,
+                mClockProxy, null));
+        mIncomingCall.initAnalytics();
+        when(mIncomingCall.getIntentExtras()).thenReturn(new Bundle());
+        when(mIncomingCall.getViaNumber()).thenReturn(TEST_NUMBER);
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index ab7693a..5c1cdc4 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -95,8 +95,6 @@
 import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.WiredHeadsetManager;
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
-import com.android.server.telecom.callfiltering.CallFilterResultCallback;
-import com.android.server.telecom.callfiltering.IncomingCallFilter;
 import com.android.server.telecom.components.UserCallIntentProcessor;
 import com.android.server.telecom.ui.IncomingCallNotifier;
 
@@ -522,16 +520,6 @@
                 },
                 mClockProxy,
                 mRoleManagerAdapter,
-                new IncomingCallFilter.Factory() {
-                    @Override
-                    public IncomingCallFilter create(Context context,
-                            CallFilterResultCallback listener, com.android.server.telecom.Call call,
-                            TelecomSystem.SyncRoot lock, Timeouts.Adapter timeoutsAdapter,
-                            List<IncomingCallFilter.CallFilter> filters) {
-                        return new IncomingCallFilter(context, listener, call, lock,
-                                timeoutsAdapter, filters, mHandlerThread.getThreadHandler());
-                    }
-                },
                 new ContactsAsyncHelper.Factory() {
                     @Override
                     public ContactsAsyncHelper create(