Merge "Added support for writing Calls.FEATURES_WIFI and Calls.FEATURES_HD_CALL to the Call Log."
diff --git a/proto/telecom.proto b/proto/telecom.proto
index 2f4fae8..73eba87 100644
--- a/proto/telecom.proto
+++ b/proto/telecom.proto
@@ -16,6 +16,9 @@
 
   // Hardware revision (EVT, DVT, PVT etc.)
   optional string hardware_revision = 3;
+
+  // Carrier ID that the device is associated to
+  optional int32 carrier_id = 4;
 }
 
 message LogSessionTiming {
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 1d3a90e..2997454 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom;
 
+import android.content.Context;
 import android.os.SystemProperties;
 
 import android.telecom.Connection;
@@ -23,6 +24,8 @@
 import android.telecom.Logging.EventManager;
 import android.telecom.ParcelableCallAnalytics;
 import android.telecom.TelecomAnalytics;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.util.Base64;
 import android.telecom.Log;
 
@@ -37,10 +40,12 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.PriorityQueue;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.stream.Collectors;
@@ -628,7 +633,7 @@
         return new TelecomAnalytics(sessionTimings, calls);
     }
 
-    public static void dumpToEncodedProto(PrintWriter pw, String[] args) {
+    public static void dumpToEncodedProto(Context context, PrintWriter pw, String[] args) {
         TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
 
         synchronized (sLock) {
@@ -642,6 +647,7 @@
                             .setTimeMillis(timing.getTime()))
                     .toArray(TelecomLogClass.LogSessionTiming[]::new);
             result.setHardwareRevision(SystemProperties.get("ro.boot.revision", ""));
+            result.setCarrierId(getCarrierId(context));
             if (args.length > 1 && CLEAR_ANALYTICS_ARG.equals(args[1])) {
                 sCallIdToInfo.clear();
                 sSessionTimings.clear();
@@ -652,6 +658,29 @@
         pw.write(encodedProto);
     }
 
+    private static int getCarrierId(Context context) {
+        SubscriptionManager subscriptionManager =
+                context.getSystemService(SubscriptionManager.class);
+        List<SubscriptionInfo> subInfos = subscriptionManager.getActiveSubscriptionInfoList();
+        if (subInfos == null) {
+            return -1;
+        }
+        return subInfos.stream()
+                .max(Comparator.comparing(Analytics::scoreSubscriptionInfo))
+                .map(SubscriptionInfo::getCarrierId).orElse(-1);
+    }
+
+    // Copied over from Telephony's server-side logic for consistency
+    private static int scoreSubscriptionInfo(SubscriptionInfo subInfo) {
+        final int scoreCarrierId = 0b100;
+        final int scoreNotOpportunistic = 0b010;
+        final int scoreSlot0 = 0b001;
+
+        return ((subInfo.getCarrierId() >= 0) ? scoreCarrierId : 0)
+                + (subInfo.isOpportunistic() ? 0 : scoreNotOpportunistic)
+                + ((subInfo.getSimSlotIndex() == 0) ? scoreSlot0 : 0);
+    }
+
     public static void dump(IndentingPrintWriter writer) {
         synchronized (sLock) {
             int prefixLength = CallsManager.TELECOM_CALL_ID_PREFIX.length();
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index e73d623..b507758 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -47,6 +47,8 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
 import android.util.StatsLog;
 import android.os.UserHandle;
@@ -62,11 +64,13 @@
 import java.lang.String;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -336,6 +340,10 @@
 
     private boolean mIsEmergencyCall;
 
+    // The Call is considered an emergency call for testing, but will not actually connect to
+    // emergency services.
+    private boolean mIsTestEmergencyCall;
+
     private boolean mSpeakerphoneOn;
 
     private boolean mIsDisconnectingChildCall = false;
@@ -1073,10 +1081,13 @@
             // call, it will remain so for the rest of it's lifetime.
             if (!mIsEmergencyCall) {
                 mIsEmergencyCall = mHandle != null &&
-                        mPhoneNumberUtilsAdapter.isLocalEmergencyNumber(mContext,
-                                mHandle.getSchemeSpecificPart());
+                        getTelephonyManager().isEmergencyNumber(mHandle.getSchemeSpecificPart());
                 mAnalytics.setCallIsEmergency(mIsEmergencyCall);
             }
+            if (!mIsTestEmergencyCall) {
+                mIsTestEmergencyCall = mHandle != null &&
+                        isTestEmergencyCall(mHandle.getSchemeSpecificPart());
+            }
             startCallerInfoLookup();
             for (Listener l : mListeners) {
                 l.onHandleChanged(this);
@@ -1084,6 +1095,14 @@
         }
     }
 
+    private boolean isTestEmergencyCall(String number) {
+        Map<Integer, List<EmergencyNumber>> eMap = getTelephonyManager().getEmergencyNumberList();
+        return eMap.values().stream().flatMap(Collection::stream)
+                .anyMatch(eNumber ->
+                        eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST) &&
+                                number.equals(eNumber.getNumber()));
+    }
+
     public String getCallerDisplayName() {
         return mCallerDisplayName;
     }
@@ -1144,6 +1163,15 @@
     }
 
     /**
+     * @return {@code true} if this an outgoing call to a test emergency number (and NOT to
+     * emergency services). Used for testing purposes to differentiate between a real and fake
+     * emergency call for safety reasons during testing.
+     */
+    public boolean isTestEmergencyCall() {
+        return mIsTestEmergencyCall;
+    }
+
+    /**
      * @return {@code true} if the network has identified this call as an emergency call.
      */
     public boolean isNetworkIdentifiedEmergencyCall() {
@@ -3163,6 +3191,10 @@
         }
     }
 
+    private TelephonyManager getTelephonyManager() {
+        return mContext.getSystemService(TelephonyManager.class);
+    }
+
     /**
      * Sets whether this {@link Call} is a conference or not.
      * @param isConference
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 7e4c3ba..c01c9aa 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -26,6 +26,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs.Builder;
 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
 
 import java.util.Collection;
@@ -44,6 +45,7 @@
     private final LinkedHashSet<Call> mActiveDialingOrConnectingCalls;
     private final LinkedHashSet<Call> mRingingCalls;
     private final LinkedHashSet<Call> mHoldingCalls;
+    private final LinkedHashSet<Call> mAudioProcessingCalls;
     private final Set<Call> mCalls;
     private final SparseArray<LinkedHashSet<Call>> mCallStateToCalls;
 
@@ -69,9 +71,10 @@
             RingbackPlayer ringbackPlayer,
             BluetoothStateReceiver bluetoothStateReceiver,
             DtmfLocalTonePlayer dtmfLocalTonePlayer) {
-        mActiveDialingOrConnectingCalls = new LinkedHashSet<>();
-        mRingingCalls = new LinkedHashSet<>();
-        mHoldingCalls = new LinkedHashSet<>();
+        mActiveDialingOrConnectingCalls = new LinkedHashSet<>(1);
+        mRingingCalls = new LinkedHashSet<>(1);
+        mHoldingCalls = new LinkedHashSet<>(1);
+        mAudioProcessingCalls = new LinkedHashSet<>(1);
         mCalls = new HashSet<>();
         mCallStateToCalls = new SparseArray<LinkedHashSet<Call>>() {{
             put(CallState.CONNECTING, mActiveDialingOrConnectingCalls);
@@ -80,6 +83,8 @@
             put(CallState.PULLING, mActiveDialingOrConnectingCalls);
             put(CallState.RINGING, mRingingCalls);
             put(CallState.ON_HOLD, mHoldingCalls);
+            put(CallState.SIMULATED_RINGING, mRingingCalls);
+            put(CallState.AUDIO_PROCESSING, mAudioProcessingCalls);
         }};
 
         mCallAudioRouteStateMachine = callAudioRouteStateMachine;
@@ -511,6 +516,13 @@
         pw.increaseIndent();
         mCallAudioRouteStateMachine.dumpPendingMessages(pw);
         pw.decreaseIndent();
+
+        pw.println("BluetoothDeviceManager:");
+        pw.increaseIndent();
+        if (mBluetoothStateReceiver.getBluetoothDeviceManager() != null) {
+            mBluetoothStateReceiver.getBluetoothDeviceManager().dump(pw);
+        }
+        pw.decreaseIndent();
     }
 
     @VisibleForTesting
@@ -534,6 +546,7 @@
                 onCallLeavingActiveDialingOrConnecting();
                 break;
             case CallState.RINGING:
+            case CallState.SIMULATED_RINGING:
             case CallState.ANSWERED:
                 onCallLeavingRinging();
                 break;
@@ -547,6 +560,9 @@
                 stopRingbackForCall(call);
                 onCallLeavingActiveDialingOrConnecting();
                 break;
+            case CallState.AUDIO_PROCESSING:
+                onCallLeavingAudioProcessing();
+                break;
         }
     }
 
@@ -557,6 +573,7 @@
                 onCallEnteringActiveDialingOrConnecting();
                 break;
             case CallState.RINGING:
+            case CallState.SIMULATED_RINGING:
                 onCallEnteringRinging();
                 break;
             case CallState.ON_HOLD:
@@ -574,6 +591,25 @@
                     onCallEnteringActiveDialingOrConnecting();
                 }
                 break;
+            case CallState.AUDIO_PROCESSING:
+                onCallEnteringAudioProcessing();
+                break;
+        }
+    }
+
+    private void onCallLeavingAudioProcessing() {
+        if (mAudioProcessingCalls.size() == 0) {
+            mCallAudioModeStateMachine.sendMessageWithArgs(
+                    CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS,
+                    makeArgsForModeStateMachine());
+        }
+    }
+
+    private void onCallEnteringAudioProcessing() {
+        if (mAudioProcessingCalls.size() == 1) {
+            mCallAudioModeStateMachine.sendMessageWithArgs(
+                    CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL,
+                    makeArgsForModeStateMachine());
         }
     }
 
@@ -655,13 +691,15 @@
 
     @NonNull
     private CallAudioModeStateMachine.MessageArgs makeArgsForModeStateMachine() {
-        return new CallAudioModeStateMachine.MessageArgs(
-                mActiveDialingOrConnectingCalls.size() > 0,
-                mRingingCalls.size() > 0,
-                mHoldingCalls.size() > 0,
-                mIsTonePlaying,
-                mForegroundCall != null && mForegroundCall.getIsVoipAudioMode(),
-                Log.createSubsession());
+        return new Builder()
+                .setHasActiveOrDialingCalls(mActiveDialingOrConnectingCalls.size() > 0)
+                .setHasRingingCalls(mRingingCalls.size() > 0)
+                .setHasHoldingCalls(mHoldingCalls.size() > 0)
+                .setHasAudioProcessingCalls(mAudioProcessingCalls.size() > 0)
+                .setIsTonePlaying(mIsTonePlaying)
+                .setForegroundCallIsVoip(
+                        mForegroundCall != null && mForegroundCall.getIsVoipAudioMode())
+                .setSession(Log.createSubsession()).build();
     }
 
     private HashSet<Call> getBinForCall(Call call) {
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index e5c4617..06be216 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -41,53 +41,108 @@
         public boolean hasActiveOrDialingCalls;
         public boolean hasRingingCalls;
         public boolean hasHoldingCalls;
+        public boolean hasAudioProcessingCalls;
         public boolean isTonePlaying;
         public boolean foregroundCallIsVoip;
         public Session session;
 
-        public MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls,
-                boolean hasHoldingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip,
-                Session session) {
+        private MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls,
+                boolean hasHoldingCalls, boolean hasAudioProcessingCalls, boolean isTonePlaying,
+                boolean foregroundCallIsVoip, Session session) {
             this.hasActiveOrDialingCalls = hasActiveOrDialingCalls;
             this.hasRingingCalls = hasRingingCalls;
             this.hasHoldingCalls = hasHoldingCalls;
+            this.hasAudioProcessingCalls = hasAudioProcessingCalls;
             this.isTonePlaying = isTonePlaying;
             this.foregroundCallIsVoip = foregroundCallIsVoip;
             this.session = session;
         }
 
-        public MessageArgs() {
-            this.session = Log.createSubsession();
-        }
-
         @Override
         public String toString() {
             return "MessageArgs{" +
                     "hasActiveCalls=" + hasActiveOrDialingCalls +
                     ", hasRingingCalls=" + hasRingingCalls +
                     ", hasHoldingCalls=" + hasHoldingCalls +
+                    ", hasAudioProcessingCalls=" + hasAudioProcessingCalls +
                     ", isTonePlaying=" + isTonePlaying +
                     ", foregroundCallIsVoip=" + foregroundCallIsVoip +
                     ", session=" + session +
                     '}';
         }
+
+        public static class Builder {
+            private boolean mHasActiveOrDialingCalls;
+            private boolean mHasRingingCalls;
+            private boolean mHasHoldingCalls;
+            private boolean mHasAudioProcessingCalls;
+            private boolean mIsTonePlaying;
+            private boolean mForegroundCallIsVoip;
+            private Session mSession;
+
+            public Builder setHasActiveOrDialingCalls(boolean hasActiveOrDialingCalls) {
+                mHasActiveOrDialingCalls = hasActiveOrDialingCalls;
+                return this;
+            }
+
+            public Builder setHasRingingCalls(boolean hasRingingCalls) {
+                mHasRingingCalls = hasRingingCalls;
+                return this;
+            }
+
+            public Builder setHasHoldingCalls(boolean hasHoldingCalls) {
+                mHasHoldingCalls = hasHoldingCalls;
+                return this;
+            }
+
+            public Builder setHasAudioProcessingCalls(boolean hasAudioProcessingCalls) {
+                mHasAudioProcessingCalls = hasAudioProcessingCalls;
+                return this;
+            }
+
+            public Builder setIsTonePlaying(boolean isTonePlaying) {
+                mIsTonePlaying = isTonePlaying;
+                return this;
+            }
+
+            public Builder setForegroundCallIsVoip(boolean foregroundCallIsVoip) {
+                mForegroundCallIsVoip = foregroundCallIsVoip;
+                return this;
+            }
+
+            public Builder setSession(Session session) {
+                mSession = session;
+                return this;
+            }
+
+            public MessageArgs build() {
+                return new MessageArgs(mHasActiveOrDialingCalls, mHasRingingCalls, mHasHoldingCalls,
+                        mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, mSession);
+            }
+        }
     }
 
+    // TODO: remove this and replace when the new audio mode gets checked in.
+    public static final int NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING = AudioManager.MODE_NORMAL;
+
     public static final int INITIALIZE = 1;
     // These ENTER_*_FOCUS commands are for testing.
     public static final int ENTER_CALL_FOCUS_FOR_TESTING = 2;
     public static final int ENTER_COMMS_FOCUS_FOR_TESTING = 3;
     public static final int ENTER_RING_FOCUS_FOR_TESTING = 4;
     public static final int ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING = 5;
-    public static final int ABANDON_FOCUS_FOR_TESTING = 6;
+    public static final int ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING = 6;
+    public static final int ABANDON_FOCUS_FOR_TESTING = 7;
 
     public static final int NO_MORE_ACTIVE_OR_DIALING_CALLS = 1001;
     public static final int NO_MORE_RINGING_CALLS = 1002;
     public static final int NO_MORE_HOLDING_CALLS = 1003;
+    public static final int NO_MORE_AUDIO_PROCESSING_CALLS = 1004;
 
     public static final int NEW_ACTIVE_OR_DIALING_CALL = 2001;
     public static final int NEW_RINGING_CALL = 2002;
     public static final int NEW_HOLDING_CALL = 2003;
+    public static final int NEW_AUDIO_PROCESSING_CALL = 2004;
 
     public static final int TONE_STARTED_PLAYING = 3001;
     public static final int TONE_STOPPED_PLAYING = 3002;
@@ -102,14 +157,17 @@
         put(ENTER_CALL_FOCUS_FOR_TESTING, "ENTER_CALL_FOCUS_FOR_TESTING");
         put(ENTER_COMMS_FOCUS_FOR_TESTING, "ENTER_COMMS_FOCUS_FOR_TESTING");
         put(ENTER_RING_FOCUS_FOR_TESTING, "ENTER_RING_FOCUS_FOR_TESTING");
+        put(ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, "ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING");
         put(ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, "ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING");
         put(ABANDON_FOCUS_FOR_TESTING, "ABANDON_FOCUS_FOR_TESTING");
         put(NO_MORE_ACTIVE_OR_DIALING_CALLS, "NO_MORE_ACTIVE_OR_DIALING_CALLS");
         put(NO_MORE_RINGING_CALLS, "NO_MORE_RINGING_CALLS");
         put(NO_MORE_HOLDING_CALLS, "NO_MORE_HOLDING_CALLS");
+        put(NO_MORE_AUDIO_PROCESSING_CALLS, "NO_MORE_AUDIO_PROCESSING_CALLS");
         put(NEW_ACTIVE_OR_DIALING_CALL, "NEW_ACTIVE_OR_DIALING_CALL");
         put(NEW_RINGING_CALL, "NEW_RINGING_CALL");
         put(NEW_HOLDING_CALL, "NEW_HOLDING_CALL");
+        put(NEW_AUDIO_PROCESSING_CALL, "NEW_AUDIO_PROCESSING_CALL");
         put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING");
         put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
         put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
@@ -120,6 +178,8 @@
 
     public static final String TONE_HOLD_STATE_NAME = OtherFocusState.class.getSimpleName();
     public static final String UNFOCUSED_STATE_NAME = UnfocusedState.class.getSimpleName();
+    public static final String AUDIO_PROCESSING_STATE_NAME =
+            AudioProcessingFocusState.class.getSimpleName();
     public static final String CALL_STATE_NAME = SimCallFocusState.class.getSimpleName();
     public static final String RING_STATE_NAME = RingingFocusState.class.getSimpleName();
     public static final String COMMS_STATE_NAME = VoipCallFocusState.class.getSimpleName();
@@ -140,6 +200,9 @@
                 case ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING:
                     transitionTo(mOtherFocusState);
                     return HANDLED;
+                case ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING:
+                    transitionTo(mAudioProcessingFocusState);
+                    return HANDLED;
                 case ABANDON_FOCUS_FOR_TESTING:
                     transitionTo(mUnfocusedState);
                     return HANDLED;
@@ -161,8 +224,8 @@
         public void enter() {
             if (mIsInitialized) {
                 Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED");
-                mAudioManager.abandonAudioFocusForCall();
                 mAudioManager.setMode(AudioManager.MODE_NORMAL);
+                mAudioManager.abandonAudioFocusForCall();
 
                 mMostRecentMode = AudioManager.MODE_NORMAL;
                 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
@@ -185,6 +248,73 @@
                 case NO_MORE_HOLDING_CALLS:
                     // Do nothing.
                     return HANDLED;
+                case NO_MORE_AUDIO_PROCESSING_CALLS:
+                    // Do nothing.
+                    return HANDLED;
+                case NEW_ACTIVE_OR_DIALING_CALL:
+                    transitionTo(args.foregroundCallIsVoip
+                            ? mVoipCallFocusState : mSimCallFocusState);
+                    return HANDLED;
+                case NEW_RINGING_CALL:
+                    transitionTo(mRingingFocusState);
+                    return HANDLED;
+                case NEW_AUDIO_PROCESSING_CALL:
+                    transitionTo(mAudioProcessingFocusState);
+                    return HANDLED;
+                case NEW_HOLDING_CALL:
+                    // This really shouldn't happen, but transition to the focused state anyway.
+                    Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." +
+                            " Args are: \n" + args.toString());
+                    transitionTo(mOtherFocusState);
+                    return HANDLED;
+                case TONE_STARTED_PLAYING:
+                    // This shouldn't happen either, but perform the action anyway.
+                    Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n"
+                            + args.toString());
+                    return HANDLED;
+                default:
+                    // The forced focus switch commands are handled by BaseState.
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    private class AudioProcessingFocusState extends BaseState {
+        @Override
+        public void enter() {
+            if (mIsInitialized) {
+                Log.i(LOG_TAG, "Abandoning audio focus: now audio processing");
+                mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
+                mAudioManager.abandonAudioFocusForCall();
+
+                mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING;
+                mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            if (super.processMessage(msg) == HANDLED) {
+                return HANDLED;
+            }
+            MessageArgs args = (MessageArgs) msg.obj;
+            switch (msg.what) {
+                case NO_MORE_ACTIVE_OR_DIALING_CALLS:
+                    // Do nothing.
+                    return HANDLED;
+                case NO_MORE_RINGING_CALLS:
+                    // Do nothing.
+                    return HANDLED;
+                case NO_MORE_HOLDING_CALLS:
+                    // Do nothing.
+                    return HANDLED;
+                case NO_MORE_AUDIO_PROCESSING_CALLS:
+                    BaseState destState = calculateProperStateFromArgs(args);
+                    if (destState == this) {
+                        Log.w(LOG_TAG, "Got spurious NO_MORE_AUDIO_PROCESSING_CALLS");
+                    }
+                    transitionTo(destState);
+                    return HANDLED;
                 case NEW_ACTIVE_OR_DIALING_CALL:
                     transitionTo(args.foregroundCallIsVoip
                             ? mVoipCallFocusState : mSimCallFocusState);
@@ -193,11 +323,15 @@
                     transitionTo(mRingingFocusState);
                     return HANDLED;
                 case NEW_HOLDING_CALL:
-                    // This really shouldn't happen, but transition to the focused state anyway.
+                    // This really shouldn't happen, but recalculate from args and do the transition
                     Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." +
                             " Args are: \n" + args.toString());
                     transitionTo(mOtherFocusState);
                     return HANDLED;
+                case NEW_AUDIO_PROCESSING_CALL:
+                    Log.w(LOG_TAG, "Unexpected behavior! New audio processing call appeared while"
+                            + " in audio processing state.");
+                    return HANDLED;
                 case TONE_STARTED_PLAYING:
                     // This shouldn't happen either, but perform the action anyway.
                     Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n"
@@ -250,25 +384,25 @@
                     // Do nothing and keep ringing.
                     return HANDLED;
                 case NO_MORE_RINGING_CALLS:
-                    // If there are active or holding calls, switch to the appropriate focus.
-                    // Otherwise abandon focus.
-                    if (args.hasActiveOrDialingCalls) {
-                        if (args.foregroundCallIsVoip) {
-                            transitionTo(mVoipCallFocusState);
-                        } else {
-                            transitionTo(mSimCallFocusState);
-                        }
-                    } else if (args.hasHoldingCalls || args.isTonePlaying) {
-                        transitionTo(mOtherFocusState);
-                    } else {
-                        transitionTo(mUnfocusedState);
+                    BaseState destState = calculateProperStateFromArgs(args);
+                    if (destState == this) {
+                        Log.w(LOG_TAG, "Got spurious NO_MORE_RINGING_CALLS");
                     }
+                    transitionTo(destState);
                     return HANDLED;
                 case NEW_ACTIVE_OR_DIALING_CALL:
                     // If a call becomes active suddenly, give it priority over ringing.
                     transitionTo(args.foregroundCallIsVoip
                             ? mVoipCallFocusState : mSimCallFocusState);
                     return HANDLED;
+                case NEW_AUDIO_PROCESSING_CALL:
+                    // If we don't have any more ringing calls, transition to audio processing.
+                    if (!args.hasRingingCalls) {
+                        transitionTo(mAudioProcessingFocusState);
+                    } else {
+                        Log.w(LOG_TAG, "Got a audio processing call while there's still a call "
+                                + "ringing");
+                    }
                 case NEW_RINGING_CALL:
                     Log.w(LOG_TAG, "Unexpected behavior! New ringing call appeared while in " +
                             "ringing state.");
@@ -311,7 +445,7 @@
             switch (msg.what) {
                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
                     // Switch to either ringing, holding, or inactive
-                    transitionTo(destinationStateAfterNoMoreActiveCalls(args));
+                    transitionTo(calculateProperStateFromArgs(args));
                     return HANDLED;
                 case NO_MORE_RINGING_CALLS:
                     // Don't transition state, but stop any call-waiting tones that may have been
@@ -324,7 +458,7 @@
                     // indicating that a ringing call has disconnected while this state machine
                     // is in the SimCallFocusState.
                     if (!args.hasActiveOrDialingCalls) {
-                        transitionTo(destinationStateAfterNoMoreActiveCalls(args));
+                        transitionTo(calculateProperStateFromArgs(args));
                     }
                     return HANDLED;
                 case NO_MORE_HOLDING_CALLS:
@@ -348,6 +482,14 @@
                         transitionTo(mVoipCallFocusState);
                     }
                     return HANDLED;
+                case NEW_AUDIO_PROCESSING_CALL:
+                    // If we don't have any more active calls, transition to audio processing.
+                    if (!args.hasActiveOrDialingCalls) {
+                        transitionTo(mAudioProcessingFocusState);
+                    } else {
+                        Log.w(LOG_TAG, "Got a audio processing call while there's still a call "
+                                + "active");
+                    }
                 case FOREGROUND_VOIP_MODE_CHANGE:
                     if (args.foregroundCallIsVoip) {
                         transitionTo(mVoipCallFocusState);
@@ -380,7 +522,7 @@
             switch (msg.what) {
                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
                     // Switch to either ringing, holding, or inactive
-                    transitionTo(destinationStateAfterNoMoreActiveCalls(args));
+                    transitionTo(calculateProperStateFromArgs(args));
                     return HANDLED;
                 case NO_MORE_RINGING_CALLS:
                     // Don't transition state, but stop any call-waiting tones that may have been
@@ -410,6 +552,14 @@
                         transitionTo(mSimCallFocusState);
                     }
                     return HANDLED;
+                case NEW_AUDIO_PROCESSING_CALL:
+                    // If we don't have any more active calls, transition to audio processing.
+                    if (!args.hasActiveOrDialingCalls) {
+                        transitionTo(mAudioProcessingFocusState);
+                    } else {
+                        Log.w(LOG_TAG, "Got a audio processing call while there's still a call "
+                                + "active");
+                    }
                 case FOREGROUND_VOIP_MODE_CHANGE:
                     if (!args.foregroundCallIsVoip) {
                         transitionTo(mSimCallFocusState);
@@ -476,7 +626,7 @@
                     mCallAudioManager.stopCallWaiting();
                     return HANDLED;
                 case TONE_STOPPED_PLAYING:
-                    transitionTo(destinationStateAfterNoMoreActiveCalls(args));
+                    transitionTo(calculateProperStateFromArgs(args));
                 default:
                     return NOT_HANDLED;
             }
@@ -489,6 +639,7 @@
     private final BaseState mRingingFocusState = new RingingFocusState();
     private final BaseState mSimCallFocusState = new SimCallFocusState();
     private final BaseState mVoipCallFocusState = new VoipCallFocusState();
+    private final BaseState mAudioProcessingFocusState = new AudioProcessingFocusState();
     private final BaseState mOtherFocusState = new OtherFocusState();
 
     private final AudioManager mAudioManager;
@@ -526,10 +677,18 @@
         addState(mRingingFocusState);
         addState(mSimCallFocusState);
         addState(mVoipCallFocusState);
+        addState(mAudioProcessingFocusState);
         addState(mOtherFocusState);
         setInitialState(mUnfocusedState);
         start();
-        sendMessage(INITIALIZE, new MessageArgs());
+        sendMessage(INITIALIZE, new MessageArgs.Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(Log.createSubsession())
+                .build());
     }
 
     public void setCallAudioManager(CallAudioManager callAudioManager) {
@@ -569,15 +728,32 @@
         Log.endSession();
     }
 
-    private BaseState destinationStateAfterNoMoreActiveCalls(MessageArgs args) {
-        if (args.hasHoldingCalls) {
+    private BaseState calculateProperStateFromArgs(MessageArgs args) {
+        // If there are active, audio-processing, holding, or ringing calls,
+        // switch to the appropriate focus.
+        // Otherwise abandon focus.
+
+        // The order matters here. If there are active calls, holding focus for them takes priority.
+        // After that, we want to prioritize holding calls over ringing calls so that when a
+        // call-waiting call gets answered, there's no transition in and out of the ringing focus
+        // state. After that, we want tones since we actually hold focus during them, then the
+        // audio processing state because that will release focus.
+        if (args.hasActiveOrDialingCalls) {
+            if (args.foregroundCallIsVoip) {
+                return mVoipCallFocusState;
+            } else {
+                return mSimCallFocusState;
+            }
+        } else if (args.hasHoldingCalls) {
             return mOtherFocusState;
         } else if (args.hasRingingCalls) {
             return mRingingFocusState;
         } else if (args.isTonePlaying) {
             return mOtherFocusState;
-        } else {
-            return mUnfocusedState;
+        } else if (args.hasAudioProcessingCalls) {
+            return mAudioProcessingFocusState;
         }
+        return mUnfocusedState;
     }
+
 }
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 4afa645..aea60df 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -38,11 +38,16 @@
     }
 
     public static class AdapterImpl implements Adapter {
+        private final DefaultDialerCache mDefaultDialerCache;
+        public AdapterImpl(DefaultDialerCache cache) {
+            mDefaultDialerCache = cache;
+        }
+
         @Override
         public void processOutgoingCallIntent(Context context, CallsManager callsManager,
                 Intent intent, String callingPackage) {
             CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent,
-                    callingPackage);
+                    callingPackage, mDefaultDialerCache);
         }
 
         @Override
@@ -58,11 +63,6 @@
 
     public static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call";
     public static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
-    /*
-     *  Whether or not the dialer initiating this outgoing call is the default dialer, or system
-     *  dialer and thus allowed to make emergency calls.
-     */
-    public static final String KEY_IS_PRIVILEGED_DIALER = "is_privileged_dialer";
 
     /**
      * The user initiating the outgoing call.
@@ -72,10 +72,13 @@
 
     private final Context mContext;
     private final CallsManager mCallsManager;
+    private final DefaultDialerCache mDefaultDialerCache;
 
-    public CallIntentProcessor(Context context, CallsManager callsManager) {
+    public CallIntentProcessor(Context context, CallsManager callsManager,
+            DefaultDialerCache defaultDialerCache) {
         this.mContext = context;
         this.mCallsManager = callsManager;
+        this.mDefaultDialerCache = defaultDialerCache;
     }
 
     public void processIntent(Intent intent, String callingPackage) {
@@ -86,7 +89,8 @@
         if (isUnknownCall) {
             processUnknownCallIntent(mCallsManager, intent);
         } else {
-            processOutgoingCallIntent(mContext, mCallsManager, intent, callingPackage);
+            processOutgoingCallIntent(mContext, mCallsManager, intent, callingPackage,
+                    mDefaultDialerCache);
         }
         Trace.endSection();
     }
@@ -102,7 +106,8 @@
             Context context,
             CallsManager callsManager,
             Intent intent,
-            String callingPackage) {
+            String callingPackage,
+            DefaultDialerCache defaultDialerCache) {
 
         Uri handle = intent.getData();
         String scheme = handle.getScheme();
@@ -157,6 +162,9 @@
 
         UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
 
+        boolean isPrivilegedDialer = defaultDialerCache.isDefaultOrSystemDialer(callingPackage,
+                initiatingUser.getIdentifier());
+
         // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
         CompletableFuture<Call> callFuture = callsManager
                 .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
@@ -167,7 +175,8 @@
             if (call != null) {
                 Log.continueSession(logSubsession, "CIP.sNOCI");
                 try {
-                    sendNewOutgoingCallIntent(context, call, callsManager, intent);
+                    sendNewOutgoingCallIntent(context, call, callsManager, intent,
+                            isPrivilegedDialer, defaultDialerCache);
                 } finally {
                     Log.endSession();
                 }
@@ -176,17 +185,15 @@
     }
 
     static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
-            Intent intent) {
+            Intent intent, boolean isPrivilegedDialer, DefaultDialerCache defaultDialerCache) {
         // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
         // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
         // killed if memory is scarce. However, this is OK here because the entire Telecom
         // process will be running throughout the duration of the phone call and should never
         // be killed.
-        final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
-
         NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                 context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
-                isPrivilegedDialer);
+                isPrivilegedDialer, defaultDialerCache);
 
         // If the broadcaster comes back with an immediate error, disconnect and show a dialog.
         NewOutgoingCallIntentBroadcaster.CallDisposition disposition = broadcaster.evaluateCall();
diff --git a/src/com/android/server/telecom/CallScreeningServiceHelper.java b/src/com/android/server/telecom/CallScreeningServiceHelper.java
index a9341ab..79d5286 100644
--- a/src/com/android/server/telecom/CallScreeningServiceHelper.java
+++ b/src/com/android/server/telecom/CallScreeningServiceHelper.java
@@ -68,6 +68,11 @@
         }
 
         @Override
+        public void screenCallFurther(String callId) throws RemoteException {
+            // no-op; we don't allow this on outgoing calls.
+        }
+
+        @Override
         public void disallowCall(String s, boolean b, boolean b1, boolean b2,
                 ComponentName componentName) throws RemoteException {
             // no-op; we don't allow this on outgoing calls.
diff --git a/src/com/android/server/telecom/CallState.java b/src/com/android/server/telecom/CallState.java
index 1e31732..0411ecc 100644
--- a/src/com/android/server/telecom/CallState.java
+++ b/src/com/android/server/telecom/CallState.java
@@ -118,7 +118,19 @@
      * Indicates that an incoming call has been answered by the in-call UI, but Telephony hasn't yet
      * set the call to active.
      */
-    public static final int ANSWERED = 11;
+    public static final int ANSWERED = TelecomProtoEnums.ANSWERED; // = 11
+
+    /**
+     * Indicates that the call is undergoing audio processing by a different app in the background.
+     * @see android.telecom.Call#STATE_AUDIO_PROCESSING
+     */
+    public static final int AUDIO_PROCESSING = TelecomProtoEnums.AUDIO_PROCESSING; // = 12
+
+    /**
+     * Indicates that the call is in a fake ringing state.
+     * @see android.telecom.Call#STATE_SIMULATED_RINGING
+     */
+    public static final int SIMULATED_RINGING = TelecomProtoEnums.SIMULATED_RINGING; // = 13
 
     public static String toString(int callState) {
         switch (callState) {
@@ -146,6 +158,10 @@
                 return "PULLING";
             case ANSWERED:
                 return "ANSWERED";
+            case AUDIO_PROCESSING:
+                return "AUDIO_PROCESSING";
+            case SIMULATED_RINGING:
+                return "SIMULATED_RINGING";
             default:
                 return "UNKNOWN";
         }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 36ff803..ca673ad 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -35,6 +35,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -78,6 +79,7 @@
 import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
 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.CallScreeningServiceController;
 import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
 import com.android.server.telecom.callfiltering.IncomingCallFilter;
@@ -608,7 +610,12 @@
                     incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE),
                     incomingCall.isSelfManaged(),
                     extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING));
-            onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));
+            onCallFilteringComplete(incomingCall, new Builder()
+                    .setShouldAllowCall(true)
+                    .setShouldReject(false)
+                    .setShouldAddToCallLog(true)
+                    .setShouldShowNotification(true)
+                    .build());
             incomingCall.setIsUsingCallFiltering(false);
             return;
         }
@@ -1103,9 +1110,11 @@
                 call.setIsVoipAudioMode(true);
             }
         }
-        if (isRttSettingOn() ||
+
+        boolean isRttSettingOn = isRttSettingOn(phoneAccountHandle);
+        if (isRttSettingOn ||
                 extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
-            Log.i(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn());
+            Log.i(this, "Incoming call requesting RTT, rtt setting is %b", isRttSettingOn);
             call.createRttStreams();
             // Even if the phone account doesn't support RTT yet, the connection manager might
             // change that. Set this to check it later.
@@ -1536,11 +1545,12 @@
 
                     boolean isVoicemail = isVoicemail(callToUse.getHandle(), accountToUse);
 
-                    if (!isVoicemail && (isRttSettingOn() || (extras != null
+                    boolean isRttSettingOn = isRttSettingOn(phoneAccountHandle);
+                    if (!isVoicemail && (isRttSettingOn || (extras != null
                             && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT,
                             false)))) {
                         Log.d(this, "Outgoing call requesting RTT, rtt setting is %b",
-                                isRttSettingOn());
+                                isRttSettingOn);
                         if (callToUse.isEmergencyCall() || (accountToUse != null
                                 && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT))) {
                             // If the call requested RTT and it's an emergency call, ignore the
@@ -1623,6 +1633,7 @@
      * @param handle The handle of the outgoing call; used to determine the SIP scheme when matching
      *               phone accounts.
      * @param isVideo {@code true} if the call is a video call, {@code false} otherwise.
+     * @param isEmergency {@code true} if the call is an emergency call.
      * @param initiatingUser The {@link UserHandle} the call is placed on.
      * @return
      */
@@ -1753,7 +1764,7 @@
             Log.w(this, "onCallRedirectionComplete: phoneAccountHandle is null");
             endEarly = true;
             disconnectReason = "Null phoneAccountHandle from Call Redirection Service";
-        } else if (mPhoneNumberUtilsAdapter.isPotentialLocalEmergencyNumber(mContext,
+        } else if (getTelephonyManager().isPotentialEmergencyNumber(
                 handle.getSchemeSpecificPart())) {
             Log.w(this, "onCallRedirectionComplete: emergency number %s is redirected from Call"
                     + " Redirection Service", handle.getSchemeSpecificPart());
@@ -2225,10 +2236,8 @@
                         isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY);
         // First check the Radio SIM Technology
         if(mRadioSimVariants == null) {
-            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
-                    Context.TELEPHONY_SERVICE);
             // Cache Sim Variants
-            mRadioSimVariants = tm.getMultiSimConfiguration();
+            mRadioSimVariants = getTelephonyManager().getMultiSimConfiguration();
         }
         // Only one SIM PhoneAccount can be active at one time for DSDS. Only that SIM PhoneAccount
         // Should be available if a call is already active on the SIM account.
@@ -2252,6 +2261,10 @@
         return allAccounts;
     }
 
+    private TelephonyManager getTelephonyManager() {
+        return mContext.getSystemService(TelephonyManager.class);
+    }
+
     /**
      * Informs listeners (notably {@link CallAudioManager} of a change to the call's external
      * property.
@@ -2320,9 +2333,22 @@
         mProximitySensorManager.turnOff(screenOnImmediately);
     }
 
-    private boolean isRttSettingOn() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
+    private boolean isRttSettingOn(PhoneAccountHandle handle) {
+        boolean isRttModeSettingOn = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+        // If the carrier config says that we should ignore the RTT mode setting from the user,
+        // assume that it's off (i.e. only make an RTT call if it's requested through the extra).
+        boolean shouldIgnoreRttModeSetting = getCarrierConfigForPhoneAccount(handle)
+                .getBoolean(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
+        return isRttModeSettingOn && !shouldIgnoreRttModeSetting;
+    }
+
+    private PersistableBundle getCarrierConfigForPhoneAccount(PhoneAccountHandle handle) {
+        int subscriptionId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle);
+        CarrierConfigManager carrierConfigManager =
+                mContext.getSystemService(CarrierConfigManager.class);
+        PersistableBundle result = carrierConfigManager.getConfigForSubId(subscriptionId);
+        return result == null ? new PersistableBundle() : result;
     }
 
     void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 4621558..911cf0f 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -1743,8 +1743,12 @@
             }
             ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
                     handle.getComponentName(), handle.getUserHandle());
-            if (service != null) {
+            if (service != null && service != this) {
                 simServices.add(service);
+            } else {
+                // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not
+                // also CAPABILITY_CONNECTION_MANAGER
+                Log.w(this, "call provider also detected as SIM call manager: " + service);
             }
         }
 
@@ -1761,11 +1765,6 @@
         Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices);
 
         for (ConnectionServiceWrapper simService : simServices) {
-            if (simService == this) {
-                // Only happens in the unlikely case that a SIM service is also a SIM call manager
-                continue;
-            }
-
             final ConnectionServiceWrapper currentSimService = simService;
 
             currentSimService.mBinder.bind(new BindCallback() {
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index 6c92724..84e97d9 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -383,6 +383,12 @@
                 allAccounts.add(TelephonyUtil.getDefaultEmergencyPhoneAccount());
             }
 
+            // When testing emergency calls, we want the calls to go through to the test connection
+            // service, not the telephony ConnectionService.
+            if (mCall.isTestEmergencyCall()) {
+                allAccounts = mPhoneAccountRegistrar.filterRestrictedPhoneAccounts(allAccounts);
+            }
+
             // Get user preferred PA if it exists.
             PhoneAccount preferredPA = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
                     preferredPAH);
diff --git a/src/com/android/server/telecom/DefaultDialerCache.java b/src/com/android/server/telecom/DefaultDialerCache.java
index b72d860..c2b78ee 100644
--- a/src/com/android/server/telecom/DefaultDialerCache.java
+++ b/src/com/android/server/telecom/DefaultDialerCache.java
@@ -18,9 +18,11 @@
 
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
@@ -134,9 +136,10 @@
     private final Context mContext;
     private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
     private final TelecomSystem.SyncRoot mLock;
-    private final String mSystemDialerName;
+    private final ComponentName mSystemDialerComponentName;
     private final RoleManagerAdapter mRoleManagerAdapter;
     private SparseArray<String> mCurrentDefaultDialerPerUser = new SparseArray<>();
+    private ComponentName mOverrideSystemDialerComponentName;
 
     public DefaultDialerCache(Context context,
             DefaultDialerManagerAdapter defaultDialerManagerAdapter,
@@ -146,7 +149,11 @@
         mDefaultDialerManagerAdapter = defaultDialerManagerAdapter;
         mRoleManagerAdapter = roleManagerAdapter;
         mLock = lock;
-        mSystemDialerName = TelecomServiceImpl.getSystemDialerPackage(mContext);
+        Resources resources = mContext.getResources();
+        mSystemDialerComponentName = new ComponentName(resources.getString(
+                com.android.internal.R.string.config_defaultDialer),
+                resources.getString(R.string.incall_default_class));
+
 
         IntentFilter packageIntentFilter = new IntentFilter();
         packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -194,6 +201,22 @@
         return getDefaultDialerApplication(mContext.getUserId());
     }
 
+    public void setSystemDialerComponentName(ComponentName testComponentName) {
+        mOverrideSystemDialerComponentName = testComponentName;
+    }
+
+    public String getSystemDialerApplication() {
+        if (mOverrideSystemDialerComponentName != null) {
+            return mOverrideSystemDialerComponentName.getPackageName();
+        }
+        return mSystemDialerComponentName.getPackageName();
+    }
+
+    public ComponentName getSystemDialerComponent() {
+        if (mOverrideSystemDialerComponentName != null) return mOverrideSystemDialerComponentName;
+        return mSystemDialerComponentName;
+    }
+
     public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) {
         mRoleManagerAdapter.observeDefaultDialerApp(executor, observer);
     }
@@ -201,7 +224,7 @@
     public boolean isDefaultOrSystemDialer(String packageName, int userId) {
         String defaultDialer = getDefaultDialerApplication(userId);
         return Objects.equals(packageName, defaultDialer)
-                || Objects.equals(packageName, mSystemDialerName);
+                || Objects.equals(packageName, getSystemDialerApplication());
     }
 
     public boolean setDefaultDialer(String packageName, int userId) {
diff --git a/src/com/android/server/telecom/EmergencyCallHelper.java b/src/com/android/server/telecom/EmergencyCallHelper.java
index 7052597..5de4e5a 100644
--- a/src/com/android/server/telecom/EmergencyCallHelper.java
+++ b/src/com/android/server/telecom/EmergencyCallHelper.java
@@ -25,13 +25,13 @@
 
 /**
  * Helps with emergency calls by:
- * 1. granting temporary location permission to the default dialer service during emergency calls
+ * 1. granting temporary location permission to the system dialer service during emergency calls
  * 2. keeping track of the time of the last emergency call
  */
 @VisibleForTesting
 public class EmergencyCallHelper {
     private final Context mContext;
-    private final String mDefaultDialerPackage;
+    private final DefaultDialerCache mDefaultDialerCache;
     private final Timeouts.Adapter mTimeoutsAdapter;
     private UserHandle mLocationPermissionGrantedToUser;
     private boolean mHadFineLocation = false;
@@ -41,10 +41,10 @@
     @VisibleForTesting
     public EmergencyCallHelper(
             Context context,
-            String defaultDialerPackage,
+            DefaultDialerCache defaultDialerCache,
             Timeouts.Adapter timeoutsAdapter) {
         mContext = context;
-        mDefaultDialerPackage = defaultDialerPackage;
+        mDefaultDialerCache = defaultDialerCache;
         mTimeoutsAdapter = timeoutsAdapter;
     }
 
@@ -94,48 +94,50 @@
     }
 
     private void grantLocationPermission(UserHandle userHandle) {
-        Log.i(this, "Granting temporary location permission to " + mDefaultDialerPackage
+        String systemDialerPackage = mDefaultDialerCache.getSystemDialerApplication();
+        Log.i(this, "Granting temporary location permission to " + systemDialerPackage
               + ", user: " + userHandle);
         try {
             boolean hadBackgroundLocation = hasBackgroundLocationPermission();
             boolean hadFineLocation = hasFineLocationPermission();
             if (hadBackgroundLocation && hadFineLocation) {
-                Log.i(this, "Skipping location grant because the default dialer already"
+                Log.i(this, "Skipping location grant because the system dialer already"
                         + " holds sufficient permissions");
                 return;
             }
             if (!hadFineLocation) {
-                mContext.getPackageManager().grantRuntimePermission(mDefaultDialerPackage,
+                mContext.getPackageManager().grantRuntimePermission(systemDialerPackage,
                         Manifest.permission.ACCESS_FINE_LOCATION, userHandle);
             }
             if (!hadBackgroundLocation) {
-                mContext.getPackageManager().grantRuntimePermission(mDefaultDialerPackage,
+                mContext.getPackageManager().grantRuntimePermission(systemDialerPackage,
                         Manifest.permission.ACCESS_BACKGROUND_LOCATION, userHandle);
             }
             mHadFineLocation = hadFineLocation;
             mHadBackgroundLocation = hadBackgroundLocation;
             recordPermissionGrant(userHandle);
         } catch (Exception e) {
-            Log.e(this, e, "Failed to grant location permissions to " + mDefaultDialerPackage
+            Log.e(this, e, "Failed to grant location permissions to " + systemDialerPackage
                   + ", user: " + userHandle);
         }
     }
 
     private void revokeLocationPermission() {
-        Log.i(this, "Revoking temporary location permission from " + mDefaultDialerPackage
+        String systemDialerPackage = mDefaultDialerCache.getSystemDialerApplication();
+        Log.i(this, "Revoking temporary location permission from " + systemDialerPackage
               + ", user: " + mLocationPermissionGrantedToUser);
         UserHandle userHandle = mLocationPermissionGrantedToUser;
         try {
             if (!mHadFineLocation) {
-                mContext.getPackageManager().revokeRuntimePermission(mDefaultDialerPackage,
+                mContext.getPackageManager().revokeRuntimePermission(systemDialerPackage,
                         Manifest.permission.ACCESS_FINE_LOCATION, userHandle);
             }
             if (!mHadBackgroundLocation) {
-                mContext.getPackageManager().revokeRuntimePermission(mDefaultDialerPackage,
+                mContext.getPackageManager().revokeRuntimePermission(systemDialerPackage,
                         Manifest.permission.ACCESS_BACKGROUND_LOCATION, userHandle);
             }
         } catch (Exception e) {
-            Log.e(this, e, "Failed to revoke location permission from " + mDefaultDialerPackage
+            Log.e(this, e, "Failed to revoke location permission from " + systemDialerPackage
                   + ", user: " + userHandle);
         }
         clearPermissionGrant();
@@ -143,13 +145,15 @@
 
     private boolean hasBackgroundLocationPermission() {
         return mContext.getPackageManager().checkPermission(
-                Manifest.permission.ACCESS_BACKGROUND_LOCATION, mDefaultDialerPackage)
+                Manifest.permission.ACCESS_BACKGROUND_LOCATION,
+                mDefaultDialerCache.getSystemDialerApplication())
                 == PackageManager.PERMISSION_GRANTED;
     }
 
     private boolean hasFineLocationPermission() {
         return mContext.getPackageManager().checkPermission(
-                Manifest.permission.ACCESS_FINE_LOCATION, mDefaultDialerPackage)
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                mDefaultDialerCache.getSystemDialerApplication())
                 == PackageManager.PERMISSION_GRANTED;
     }
 
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 8de27be..888010d 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -19,6 +19,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.telecom.Log;
 import android.telecom.PhoneAccountHandle;
 
@@ -319,6 +320,16 @@
     }
 
     @Override
+    public void enterBackgroundAudioProcessing(String callId) {
+        // TODO: implement this
+    }
+
+    @Override
+    public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
+        // TODO: implement this
+    }
+
+    @Override
     public void conference(String callId, String otherCallId) {
         try {
             Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerComponentName);
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index d562c7e..c4df1d3 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -721,9 +721,6 @@
 
     private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getId);
 
-    /** The {@link ComponentName} of the default InCall UI. */
-    private final ComponentName mSystemInCallComponentName;
-
     private final Context mContext;
     private final TelecomSystem.SyncRoot mLock;
     private final CallsManager mCallsManager;
@@ -751,11 +748,6 @@
         mDefaultDialerCache = defaultDialerCache;
         mEmergencyCallHelper = emergencyCallHelper;
 
-        Resources resources = mContext.getResources();
-        mSystemInCallComponentName = new ComponentName(
-                TelecomServiceImpl.getSystemDialerPackage(mContext),
-                resources.getString(R.string.incall_default_class));
-
         mSystemStateHelper.addListener(mSystemStateListener);
     }
 
@@ -1106,13 +1098,13 @@
             Log.i(this, "defaultDialer: " + defaultDialerComponentInfo);
             if (defaultDialerComponentInfo != null &&
                     !defaultDialerComponentInfo.getComponentName().equals(
-                            mSystemInCallComponentName)) {
+                            mDefaultDialerCache.getSystemDialerComponent())) {
                 dialerInCall = new InCallServiceBindingConnection(defaultDialerComponentInfo);
             }
             Log.i(this, "defaultDialer: " + dialerInCall);
 
             InCallServiceInfo systemInCallInfo = getInCallServiceComponent(
-                    mSystemInCallComponentName, IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                    mDefaultDialerCache.getSystemDialerComponent(), IN_CALL_SERVICE_TYPE_SYSTEM_UI);
             EmergencyInCallServiceConnection systemInCall =
                     new EmergencyInCallServiceConnection(systemInCallInfo, dialerInCall);
             systemInCall.setHasEmergency(mCallsManager.hasEmergencyCall());
@@ -1120,7 +1112,8 @@
             InCallServiceConnection carModeInCall = null;
             InCallServiceInfo carModeComponentInfo = getCarModeComponent();
             if (carModeComponentInfo != null &&
-                    !carModeComponentInfo.getComponentName().equals(mSystemInCallComponentName)) {
+                    !carModeComponentInfo.getComponentName().equals(
+                            mDefaultDialerCache.getSystemDialerComponent())) {
                 carModeInCall = new InCallServiceBindingConnection(carModeComponentInfo);
             }
 
@@ -1280,8 +1273,9 @@
             return IN_CALL_SERVICE_TYPE_INVALID;
         }
 
-        if (mSystemInCallComponentName.getPackageName().equals(serviceInfo.packageName) &&
-                mSystemInCallComponentName.getClassName().equals(serviceInfo.name)) {
+        if (mDefaultDialerCache.getSystemDialerApplication().equals(serviceInfo.packageName) &&
+                mDefaultDialerCache.getSystemDialerComponent().getClassName()
+                        .equals(serviceInfo.name)) {
             return IN_CALL_SERVICE_TYPE_SYSTEM_UI;
         }
 
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index 1e82fc0..f55fa2c 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -137,6 +137,7 @@
         public static final String BIND_SCREENING = "BIND_SCREENING";
         public static final String SCREENING_BOUND = "SCREENING_BOUND";
         public static final String SCREENING_SENT = "SCREENING_SENT";
+        public static final String SCREENING_SKIPPED = "SCREENING_SKIPPED";
         public static final String CONTROLLER_SCREENING_COMPLETED =
                 "CONTROLLER_SCREENING_COMPLETED";
         public static final String SCREENING_COMPLETED = "SCREENING_COMPLETED";
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index 7a641af..1abd6fb 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -35,6 +35,7 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.DisconnectCause;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -76,6 +77,7 @@
     private final Context mContext;
     private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
     private final TelecomSystem.SyncRoot mLock;
+    private final DefaultDialerCache mDefaultDialerCache;
 
     /*
      * Whether or not the outgoing call intent originated from the default phone application. If
@@ -99,7 +101,7 @@
     @VisibleForTesting
     public NewOutgoingCallIntentBroadcaster(Context context, CallsManager callsManager, Call call,
             Intent intent, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
-            boolean isDefaultPhoneApp) {
+            boolean isDefaultPhoneApp, DefaultDialerCache defaultDialerCache) {
         mContext = context;
         mCallsManager = callsManager;
         mCall = call;
@@ -107,6 +109,7 @@
         mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
         mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
         mLock = mCallsManager.getLock();
+        mDefaultDialerCache = defaultDialerCache;
     }
 
     /**
@@ -137,8 +140,7 @@
                         disconnectTimeout = getDisconnectTimeoutFromApp(
                                 getResultExtras(false), disconnectTimeout);
                         endEarly = true;
-                    } else if (mPhoneNumberUtilsAdapter.isPotentialLocalEmergencyNumber(
-                            mContext, resultNumber)) {
+                    } else if (isPotentialEmergencyNumber(resultNumber)) {
                         Log.w(this, "Cannot modify outgoing call to emergency number %s.",
                                 resultNumber);
                         disconnectTimeout = 0;
@@ -492,10 +494,7 @@
 
     private void launchSystemDialer(Uri handle) {
         Intent systemDialerIntent = new Intent();
-        final Resources resources = mContext.getResources();
-        systemDialerIntent.setClassName(
-                TelecomServiceImpl.getSystemDialerPackage(mContext),
-                resources.getString(R.string.dialer_default_class));
+        systemDialerIntent.setComponent(mDefaultDialerCache.getSystemDialerComponent());
         systemDialerIntent.setAction(Intent.ACTION_DIAL);
         systemDialerIntent.setData(handle);
         systemDialerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -519,8 +518,8 @@
      */
     private boolean isPotentialEmergencyNumber(String number) {
         Log.v(this, "Checking restrictions for number : %s", Log.pii(number));
-        return (number != null)
-                && mPhoneNumberUtilsAdapter.isPotentialLocalEmergencyNumber(mContext, number);
+        if (number == null) return false;
+        return mContext.getSystemService(TelephonyManager.class).isPotentialEmergencyNumber(number);
     }
 
     /**
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 8746de1..8776ffd 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -154,6 +154,7 @@
     private final AppLabelProxy mAppLabelProxy;
     private State mState;
     private UserHandle mCurrentUserHandle;
+    private String mTestPhoneAccountPackageNameFilter;
     private interface PhoneAccountRegistrarWriteLock {}
     private final PhoneAccountRegistrarWriteLock mWriteLock =
             new PhoneAccountRegistrarWriteLock() {};
@@ -458,6 +459,34 @@
     }
 
     /**
+     * Sets a filter for which {@link PhoneAccount}s will be returned from
+     * {@link #filterRestrictedPhoneAccounts(List)}. If non-null, only {@link PhoneAccount}s
+     * with the package name packageNameFilter will be returned. If null, no filter is set.
+     * @param packageNameFilter The package name that will be used to filter only
+     * {@link PhoneAccount}s with the same package name.
+     */
+    public void setTestPhoneAccountPackageNameFilter(String packageNameFilter) {
+        mTestPhoneAccountPackageNameFilter = packageNameFilter;
+        Log.i(this, "filter set for PhoneAccounts, packageName=" + packageNameFilter);
+    }
+
+    /**
+     * Filter the given {@link List<PhoneAccount>} and keep only {@link PhoneAccount}s that have the
+     * #mTestPhoneAccountPackageNameFilter.
+     * @param accounts List of {@link PhoneAccount}s to filter.
+     * @return new list of filtered {@link PhoneAccount}s.
+     */
+    public List<PhoneAccount> filterRestrictedPhoneAccounts(List<PhoneAccount> accounts) {
+        if (TextUtils.isEmpty(mTestPhoneAccountPackageNameFilter)) {
+            return new ArrayList<>(accounts);
+        }
+        // Remove all PhoneAccounts that do not have the same package name as the filter.
+        return accounts.stream().filter(account -> mTestPhoneAccountPackageNameFilter.equals(
+                account.getAccountHandle().getComponentName().getPackageName()))
+                .collect(Collectors.toList());
+    }
+
+    /**
      * If it is a outgoing call, sim call manager associated with the target phone account of the
      * call is returned (if one exists).
      * Otherwise, we return the sim call manager of the user associated with the
@@ -1202,6 +1231,9 @@
                 pw.println(phoneAccount);
             }
             pw.decreaseIndent();
+            pw.increaseIndent();
+            pw.println("test emergency PhoneAccount filter: " + mTestPhoneAccountPackageNameFilter);
+            pw.decreaseIndent();
         }
     }
 
diff --git a/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java b/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
index aa568a9..28d832d 100644
--- a/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
+++ b/src/com/android/server/telecom/PhoneNumberUtilsAdapter.java
@@ -24,8 +24,6 @@
  * refactoring.
  */
 public interface PhoneNumberUtilsAdapter {
-    boolean isLocalEmergencyNumber(Context context, String number);
-    boolean isPotentialLocalEmergencyNumber(Context context, String number);
     boolean isUriNumber(String number);
     boolean isSamePhoneNumber(String number1, String number2);
     String getNumberFromIntent(Intent intent, Context context);
diff --git a/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java b/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
index 8b3c856..517857b 100644
--- a/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
+++ b/src/com/android/server/telecom/PhoneNumberUtilsAdapterImpl.java
@@ -23,20 +23,6 @@
 
 public class PhoneNumberUtilsAdapterImpl implements PhoneNumberUtilsAdapter {
     @Override
-    public boolean isLocalEmergencyNumber(Context context, String number) {
-        TelephonyManager tm = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return tm.isEmergencyNumber(number);
-    }
-
-    @Override
-    public boolean isPotentialLocalEmergencyNumber(Context context, String number) {
-        TelephonyManager tm = (TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return tm.isPotentialEmergencyNumber(number);
-    }
-
-    @Override
     public boolean isUriNumber(String number) {
         return PhoneNumberUtils.isUriNumber(number);
     }
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 93f6908..2469c1e 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -374,12 +374,12 @@
                     && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()
                     && isRingerAudible) {
                 Log.i(this, "start vibration for ramping ringer.");
-                mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
                 mIsVibrating = true;
+                mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
             } else {
                 Log.i(this, "start normal vibration.");
-                mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
                 mIsVibrating = true;
+                mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
             }
         } else if (mIsVibrating) {
             Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, "already vibrating");
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index ca44cd4..8d2a2c5 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -18,12 +18,17 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
 import android.telecom.Log;
+import android.widget.Toast;
 
 import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity;
 import com.android.server.telecom.ui.ConfirmCallDialogActivity;
 
+import java.util.List;
+
 public final class TelecomBroadcastIntentProcessor {
     /** The action used to send SMS response for the missed call notification. */
     public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
@@ -119,7 +124,15 @@
 
                 Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
                 callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                mContext.startActivityAsUser(callIntent, userHandle);
+                PackageManager packageManager = mContext.getPackageManager();
+                List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
+                        callIntent, PackageManager.MATCH_DEFAULT_ONLY, userHandle.getIdentifier());
+                if (activities.size() > 0) {
+                    mContext.startActivityAsUser(callIntent, userHandle);
+                } else {
+                    Toast.makeText(mContext, com.android.internal.R.string.noApplications,
+                            Toast.LENGTH_SHORT).show();
+                }
 
                 // Call back recent caller from the missed call notification.
             } else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 61aecfe..f82215f 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -34,7 +34,6 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -679,11 +678,7 @@
         public ComponentName getDefaultPhoneApp() {
             try {
                 Log.startSession("TSI.gDPA");
-                // No need to synchronize
-                Resources resources = mContext.getResources();
-                return new ComponentName(
-                        TelecomServiceImpl.getSystemDialerPackage(mContext),
-                        resources.getString(R.string.dialer_default_class));
+                return mDefaultDialerCache.getSystemDialerComponent();
             } finally {
                 Log.endSession();
             }
@@ -718,7 +713,25 @@
         public String getSystemDialerPackage() {
             try {
                 Log.startSession("TSI.gSDP");
-                return TelecomServiceImpl.getSystemDialerPackage(mContext);
+                return mDefaultDialerCache.getSystemDialerApplication();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        public void setSystemDialer(ComponentName testComponentName) {
+            try {
+                Log.startSession("TSI.sSD");
+                enforceModifyPermission();
+                enforceShellOnly(Binder.getCallingUid(), "setSystemDialer");
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mDefaultDialerCache.setSystemDialerComponentName(testComponentName);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
             } finally {
                 Log.endSession();
             }
@@ -1379,10 +1392,13 @@
                 return;
             }
 
+
             if (args.length > 0 && Analytics.ANALYTICS_DUMPSYS_ARG.equals(args[0])) {
-                Analytics.dumpToEncodedProto(writer, args);
+                Binder.withCleanCallingIdentity(() ->
+                        Analytics.dumpToEncodedProto(mContext, writer, args));
                 return;
             }
+
             boolean isTimeLineView = (args.length > 0 && TIME_LINE_ARG.equalsIgnoreCase(args[0]));
 
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1483,6 +1499,26 @@
             }
         }
 
+        @Override
+        public void setTestEmergencyPhoneAccountPackageNameFilter(String packageName) {
+            try {
+                Log.startSession("TSI.sTPAPNF");
+                enforceModifyPermission();
+                enforceShellOnly(Binder.getCallingUid(),
+                        "setTestEmergencyPhoneAccountPackageNameFilter");
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mPhoneAccountRegistrar.setTestPhoneAccountPackageNameFilter(packageName);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+
         /**
          * See {@link TelecomManager#isInEmergencyCall()}
          */
@@ -1507,10 +1543,10 @@
         }
 
         /**
-         * See {@link TelecomManager#handleCallIntent(Intent)} ()}
+         * See {@link TelecomManager#handleCallIntent(Intent, String)}
          */
         @Override
-        public void handleCallIntent(Intent intent) {
+        public void handleCallIntent(Intent intent, String callingPackage) {
             try {
                 Log.startSession("TSI.hCI");
                 synchronized (mLock) {
@@ -1521,7 +1557,7 @@
                     try {
                         Log.i(this, "handleCallIntent: handling call intent");
                         mCallIntentProcessorAdapter.processOutgoingCallIntent(mContext,
-                                mCallsManager, intent, null /* callingPackage */);
+                                mCallsManager, intent, callingPackage);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
@@ -1746,10 +1782,6 @@
         });
     }
 
-    public static String getSystemDialerPackage(Context context) {
-        return context.getResources().getString(com.android.internal.R.string.config_defaultDialer);
-    }
-
     public ITelecomService.Stub getBinder() {
         return mBinderImpl;
     }
@@ -1938,6 +1970,15 @@
         }
     }
 
+    // to be used for TestApi methods that can only be called with SHELL UID.
+    private void enforceShellOnly(int callingUid, String message) {
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+            return; // okay
+        }
+
+        throw new SecurityException(message + ": Only shell user can call it");
+    }
+
     private boolean canReadPhoneState(String callingPackage, String message) {
         // The system/default dialer can always read phone state - so that emergency calls will
         // still work.
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 5ffca0d..f354b94 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -254,7 +254,7 @@
                         mContactsAsyncHelper, mLock);
 
         EmergencyCallHelper emergencyCallHelper = new EmergencyCallHelper(mContext,
-                TelecomServiceImpl.getSystemDialerPackage(mContext), timeoutsAdapter);
+                defaultDialerCache, timeoutsAdapter);
 
         InCallControllerFactory inCallControllerFactory = new InCallControllerFactory() {
             @Override
@@ -327,7 +327,7 @@
 
         mBluetoothPhoneServiceImpl = bluetoothPhoneServiceImplFactory.makeBluetoothPhoneServiceImpl(
                 mContext, mLock, mCallsManager, mPhoneAccountRegistrar);
-        mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager);
+        mCallIntentProcessor = new CallIntentProcessor(mContext, mCallsManager, defaultDialerCache);
         mTelecomBroadcastIntentProcessor = new TelecomBroadcastIntentProcessor(
                 mContext, mCallsManager);
 
@@ -340,7 +340,7 @@
         final UserManager userManager = UserManager.get(mContext);
         mTelecomServiceImpl = new TelecomServiceImpl(
                 mContext, mCallsManager, mPhoneAccountRegistrar,
-                new CallIntentProcessor.AdapterImpl(),
+                new CallIntentProcessor.AdapterImpl(defaultDialerCache),
                 new UserCallIntentProcessorFactory() {
                     @Override
                     public UserCallIntentProcessor create(Context context, UserHandle userHandle) {
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 23a086b..92de536 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -22,7 +22,9 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.telecom.Log;
+import android.util.LocalLog;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothHeadsetProxy;
 
@@ -43,18 +45,21 @@
                     Log.startSession("BMSL.oSC");
                     try {
                         synchronized (mLock) {
+                            String logString;
                             if (profile == BluetoothProfile.HEADSET) {
                                 mBluetoothHeadsetService =
                                         new BluetoothHeadsetProxy((BluetoothHeadset) proxy);
-                                Log.i(this, "- Got BluetoothHeadset: " + mBluetoothHeadsetService);
+                                logString = "Got BluetoothHeadset: " + mBluetoothHeadsetService;
                             } else if (profile == BluetoothProfile.HEARING_AID) {
                                 mBluetoothHearingAidService = (BluetoothHearingAid) proxy;
-                                Log.i(this, "- Got BluetoothHearingAid: "
-                                        + mBluetoothHearingAidService);
+                                logString = "Got BluetoothHearingAid: "
+                                        + mBluetoothHearingAidService;
                             } else {
-                                Log.w(this, "Connected to non-requested bluetooth service." +
-                                        " Not changing bluetooth headset.");
+                                logString = "Connected to non-requested bluetooth service." +
+                                        " Not changing bluetooth headset.";
                             }
+                            Log.i(BluetoothDeviceManager.this, logString);
+                            mLocalLog.log(logString);
                         }
                     } finally {
                         Log.endSession();
@@ -67,23 +72,25 @@
                     try {
                         synchronized (mLock) {
                             LinkedHashMap<String, BluetoothDevice> lostServiceDevices;
+                            String logString;
                             if (profile == BluetoothProfile.HEADSET) {
                                 mBluetoothHeadsetService = null;
-                                Log.i(BluetoothDeviceManager.this,
-                                        "Lost BluetoothHeadset service. " +
-                                                "Removing all tracked devices.");
                                 lostServiceDevices = mHfpDevicesByAddress;
                                 mBluetoothRouteManager.onActiveDeviceChanged(null, false);
+                                logString = "Lost BluetoothHeadset service. " +
+                                        "Removing all tracked devices";
                             } else if (profile == BluetoothProfile.HEARING_AID) {
                                 mBluetoothHearingAidService = null;
-                                Log.i(BluetoothDeviceManager.this,
-                                        "Lost BluetoothHearingAid service. " +
-                                                "Removing all tracked devices.");
+                                logString = "Lost BluetoothHearingAid service. " +
+                                        "Removing all tracked devices.";
                                 lostServiceDevices = mHearingAidDevicesByAddress;
                                 mBluetoothRouteManager.onActiveDeviceChanged(null, true);
                             } else {
                                 return;
                             }
+                            Log.i(BluetoothDeviceManager.this, logString);
+                            mLocalLog.log(logString);
+
                             List<BluetoothDevice> devicesToRemove = new LinkedList<>(
                                     lostServiceDevices.values());
                             lostServiceDevices.clear();
@@ -103,6 +110,7 @@
             new LinkedHashMap<>();
     private final LinkedHashMap<BluetoothDevice, Long> mHearingAidDeviceSyncIds =
             new LinkedHashMap<>();
+    private final LocalLog mLocalLog = new LocalLog(20);
 
     // This lock only protects internal state -- it doesn't lock on anything going into Telecom.
     private final Object mLock = new Object();
@@ -188,6 +196,8 @@
     }
 
     void onDeviceConnected(BluetoothDevice device, boolean isHearingAid) {
+        mLocalLog.log("Device connected -- address: " + device.getAddress() + " isHeadingAid: "
+                + isHearingAid);
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
             if (isHearingAid) {
@@ -213,6 +223,8 @@
     }
 
     void onDeviceDisconnected(BluetoothDevice device, boolean isHearingAid) {
+        mLocalLog.log("Device disconnected -- address: " + device.getAddress() + " isHeadingAid: "
+                + isHearingAid);
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
             if (isHearingAid) {
@@ -297,4 +309,7 @@
         }
     }
 
+    public void dump(IndentingPrintWriter pw) {
+        mLocalLog.dump(pw);
+    }
 }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index 9e64b56..7671abd 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -152,6 +152,10 @@
         }
     }
 
+    public BluetoothDeviceManager getBluetoothDeviceManager() {
+        return mBluetoothDeviceManager;
+    }
+
     public BluetoothStateReceiver(BluetoothDeviceManager deviceManager,
             BluetoothRouteManager routeManager) {
         mBluetoothDeviceManager = deviceManager;
diff --git a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java b/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
index 0abd15d..edc68dd 100644
--- a/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
+++ b/src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.java
@@ -30,6 +30,7 @@
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallerInfoLookupHelper;
 import com.android.server.telecom.LogUtils;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 import com.android.server.telecom.settings.BlockedNumbersUtil;
 
 /**
@@ -121,15 +122,15 @@
         try {
             CallFilteringResult result;
             if (isBlocked) {
-                result = new CallFilteringResult(
-                        false, // shouldAllowCall
-                        true, //shouldReject
-                        true, //shouldAddToCallLog
-                        false, // shouldShowNotification
-                        convertBlockStatusToReason(), //callBlockReason
-                        null, //callScreeningAppName
-                        null //callScreeningComponentName
-                );
+                result = new Builder()
+                        .setShouldAllowCall(false)
+                        .setShouldReject(true)
+                        .setShouldAddToCallLog(true)
+                        .setShouldShowNotification(false)
+                        .setCallBlockReason(convertBlockStatusToReason())
+                        .setCallScreeningAppName(null)
+                        .setCallScreeningComponentName(null)
+                        .build();
                 if (mCallBlockListener != null) {
                     String number = mIncomingCall.getHandle() == null ? null
                             : mIncomingCall.getHandle().getSchemeSpecificPart();
@@ -137,12 +138,12 @@
                             mIncomingCall.getInitiatingUser());
                 }
             } else {
-                result = new CallFilteringResult(
-                        true, // shouldAllowCall
-                        false, // shouldReject
-                        true, // shouldAddToCallLog
-                        true // shouldShowNotification
-                );
+                result = new Builder()
+                        .setShouldAllowCall(true)
+                        .setShouldReject(false)
+                        .setShouldAddToCallLog(true)
+                        .setShouldShowNotification(true)
+                        .build();
             }
             Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_FINISHED,
                     BlockedNumberContract.SystemContract.blockStatusToString(mBlockStatus) + " "
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index af3ee1e..028fbf5 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -21,47 +21,73 @@
 import android.text.TextUtils;
 
 public class CallFilteringResult {
+    public static class Builder {
+        private boolean mShouldAllowCall;
+        private boolean mShouldReject;
+        private boolean mShouldAddToCallLog;
+        private boolean mShouldShowNotification;
+        private boolean mShouldSilence = false;
+        private int mCallBlockReason = Calls.BLOCK_REASON_NOT_BLOCKED;
+        private CharSequence mCallScreeningAppName = null;
+        private String mCallScreeningComponentName = null;
+
+        public Builder setShouldAllowCall(boolean shouldAllowCall) {
+            mShouldAllowCall = shouldAllowCall;
+            return this;
+        }
+
+        public Builder setShouldReject(boolean shouldReject) {
+            mShouldReject = shouldReject;
+            return this;
+        }
+
+        public Builder setShouldAddToCallLog(boolean shouldAddToCallLog) {
+            mShouldAddToCallLog = shouldAddToCallLog;
+            return this;
+        }
+
+        public Builder setShouldShowNotification(boolean shouldShowNotification) {
+            mShouldShowNotification = shouldShowNotification;
+            return this;
+        }
+
+        public Builder setShouldSilence(boolean shouldSilence) {
+            mShouldSilence = shouldSilence;
+            return this;
+        }
+
+        public Builder setCallBlockReason(int callBlockReason) {
+            mCallBlockReason = callBlockReason;
+            return this;
+        }
+
+        public Builder setCallScreeningAppName(CharSequence callScreeningAppName) {
+            mCallScreeningAppName = callScreeningAppName;
+            return this;
+        }
+
+        public Builder setCallScreeningComponentName(String callScreeningComponentName) {
+            mCallScreeningComponentName = callScreeningComponentName;
+            return this;
+        }
+
+        public CallFilteringResult build() {
+            return new CallFilteringResult(mShouldAllowCall, mShouldReject, mShouldSilence,
+                    mShouldAddToCallLog, mShouldShowNotification, mCallBlockReason,
+                    mCallScreeningAppName, mCallScreeningComponentName);
+        }
+    }
+
     public boolean shouldAllowCall;
     public boolean shouldReject;
     public boolean shouldSilence;
     public boolean shouldAddToCallLog;
     public boolean shouldShowNotification;
-    public int mCallBlockReason = CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
-    public CharSequence mCallScreeningAppName = null;
-    public String mCallScreeningComponentName = null;
+    public int mCallBlockReason;
+    public CharSequence mCallScreeningAppName;
+    public String mCallScreeningComponentName;
 
-    public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
-            shouldAddToCallLog, boolean shouldShowNotification) {
-        this.shouldAllowCall = shouldAllowCall;
-        this.shouldReject = shouldReject;
-        this.shouldSilence = false;
-        this.shouldAddToCallLog = shouldAddToCallLog;
-        this.shouldShowNotification = shouldShowNotification;
-    }
-
-    public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
-            shouldAddToCallLog, boolean shouldShowNotification, int callBlockReason,
-            CharSequence callScreeningAppName, String callScreeningComponentName) {
-        this.shouldAllowCall = shouldAllowCall;
-        this.shouldReject = shouldReject;
-        this.shouldSilence = false;
-        this.shouldAddToCallLog = shouldAddToCallLog;
-        this.shouldShowNotification = shouldShowNotification;
-        this.mCallBlockReason = callBlockReason;
-        this.mCallScreeningAppName = callScreeningAppName;
-        this.mCallScreeningComponentName = callScreeningComponentName;
-    }
-
-    public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
-            shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification) {
-        this.shouldAllowCall = shouldAllowCall;
-        this.shouldReject = shouldReject;
-        this.shouldSilence = shouldSilence;
-        this.shouldAddToCallLog = shouldAddToCallLog;
-        this.shouldShowNotification = shouldShowNotification;
-    }
-
-    public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
+    private CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
             shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int
             callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName) {
         this.shouldAllowCall = shouldAllowCall;
@@ -109,12 +135,13 @@
                 other.mCallScreeningAppName, other.mCallScreeningComponentName);
         }
 
-        return new CallFilteringResult(
-            shouldAllowCall && other.shouldAllowCall,
-            shouldReject || other.shouldReject,
-            shouldSilence || other.shouldSilence,
-            shouldAddToCallLog && other.shouldAddToCallLog,
-            shouldShowNotification && other.shouldShowNotification);
+        return new Builder()
+                .setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
+                .setShouldReject(shouldReject || other.shouldReject)
+                .setShouldSilence(shouldSilence || other.shouldSilence)
+                .setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
+                .setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
+                .build();
     }
 
     private boolean isBlockedByProvider(int blockReason) {
@@ -131,15 +158,16 @@
 
     private CallFilteringResult getCombinedCallFilteringResult(CallFilteringResult other,
         int callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName) {
-        return new CallFilteringResult(
-            shouldAllowCall && other.shouldAllowCall,
-            shouldReject || other.shouldReject,
-            shouldSilence|| other.shouldSilence,
-            shouldAddToCallLog && other.shouldAddToCallLog,
-            shouldShowNotification && other.shouldShowNotification,
-            callBlockReason,
-            callScreeningAppName,
-            callScreeningComponentName);
+        return new Builder()
+                .setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
+                .setShouldReject(shouldReject || other.shouldReject)
+                .setShouldSilence(shouldSilence || other.shouldSilence)
+                .setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
+                .setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
+                .setCallBlockReason(callBlockReason)
+                .setCallScreeningAppName(callScreeningAppName)
+                .setCallScreeningComponentName(callScreeningComponentName)
+                .build();
     }
 
 
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java
index 5b1971e..42d9a59 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceController.java
@@ -39,6 +39,7 @@
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.TelecomServiceImpl;
 import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 
 /**
  * This class supports binding to the various {@link android.telecom.CallScreeningService}:
@@ -66,12 +67,12 @@
     private Call mCall;
     private CallFilterResultCallback mCallback;
 
-    private CallFilteringResult mResult = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private CallFilteringResult mResult = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
     private boolean mIsFinished;
     private boolean mIsCarrierFinished;
@@ -195,10 +196,18 @@
             if (TextUtils.isEmpty(userChosenPackageName)) {
                 mIsUserChosenFinished = true;
             } else {
-                createCallScreeningServiceFilter().startCallScreeningFilter(mCall,
-                        CallScreeningServiceController.this, userChosenPackageName,
-                        mAppLabelProxy.getAppLabel(userChosenPackageName),
-                        CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
+                // If the user chosen call screening service is the same as the default dialer, then
+                // we have already bound to it above and don't need to do so again here.
+                if (userChosenPackageName.equals(dialerPackageName)) {
+                    Log.addEvent(mCall, LogUtils.Events.SCREENING_SKIPPED,
+                            "user pkg same as dialer: " + userChosenPackageName);
+                    mIsUserChosenFinished = true;
+                } else {
+                    createCallScreeningServiceFilter().startCallScreeningFilter(mCall,
+                            CallScreeningServiceController.this, userChosenPackageName,
+                            mAppLabelProxy.getAppLabel(userChosenPackageName),
+                            CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED);
+                }
             }
 
             if (mIsDefaultDialerFinished && mIsUserChosenFinished) {
@@ -253,7 +262,7 @@
         PersistableBundle configBundle = configManager.getConfig();
         if (configBundle != null) {
             componentName = ComponentName.unflattenFromString(configBundle.getString
-                    (CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING));
+                    (CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, ""));
         }
 
         return componentName != null ? componentName.getPackageName() : null;
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index c8ec18a..9ea8d70 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -24,7 +24,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.provider.Settings;
 import android.telecom.Log;
 import android.telecom.TelecomManager;
@@ -41,6 +41,7 @@
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.TelecomServiceImpl.SettingsSecureAdapter;
 import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 
 /**
  * Binds to {@link ICallScreeningService} to allow call blocking. A single instance of this class
@@ -96,13 +97,13 @@
                 synchronized (mTelecomLock) {
                     Log.d(this, "allowCall(%s)", callId);
                     if (mCall != null && mCall.getId().equals(callId)) {
-                        mResult = new CallFilteringResult(
-                                true, // shouldAllowCall
-                                false, //shouldReject
-                                false, //shouldSilence
-                                true, //shouldAddToCallLog
-                                true // shouldShowNotification
-                        );
+                        mResult = new Builder()
+                                .setShouldAllowCall(true)
+                                .setShouldReject(false)
+                                .setShouldSilence(false)
+                                .setShouldAddToCallLog(true)
+                                .setShouldShowNotification(true)
+                                .build();
                     } else {
                         Log.w(this, "allowCall, unknown call id: %s", callId);
                     }
@@ -131,16 +132,16 @@
                                     + "shouldShowNotification: %b", callId, shouldReject,
                             isServiceRequestingLogging, shouldShowNotification);
                     if (mCall != null && mCall.getId().equals(callId)) {
-                        mResult = new CallFilteringResult(
-                                false, // shouldAllowCall
-                                shouldReject, //shouldReject
-                                false, // shouldSilenceCall
-                                isServiceRequestingLogging, //shouldAddToCallLog
-                                shouldShowNotification, // shouldShowNotification
-                                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                                mAppName, //callScreeningAppName
-                                componentName.flattenToString() //callScreeningComponentName
-                        );
+                        mResult = new Builder()
+                                .setShouldAllowCall(false)
+                                .setShouldReject(shouldReject)
+                                .setShouldSilence(false)
+                                .setShouldAddToCallLog(isServiceRequestingLogging)
+                                .setShouldShowNotification(shouldShowNotification)
+                                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                                .setCallScreeningAppName(mAppName)
+                                .setCallScreeningComponentName(componentName.flattenToString())
+                                .build();
                     } else {
                         Log.w(this, "disallowCall, unknown call id: %s", callId);
                     }
@@ -160,13 +161,13 @@
                 synchronized (mTelecomLock) {
                     Log.d(this, "silenceCall(%s)", callId);
                     if (mCall != null && mCall.getId().equals(callId)) {
-                        mResult = new CallFilteringResult(
-                                true, // shouldAllowCall
-                                false, //shouldReject
-                                true, //shouldSilence
-                                true, //shouldAddToCallLog
-                                true // shouldShowNotification
-                        );
+                        mResult = new Builder()
+                                .setShouldAllowCall(true)
+                                .setShouldReject(false)
+                                .setShouldSilence(true)
+                                .setShouldAddToCallLog(true)
+                                .setShouldShowNotification(true)
+                                .build();
                     } else {
                         Log.w(this, "silenceCall, unknown call id: %s", callId);
                     }
@@ -177,6 +178,11 @@
                 Log.endSession();
             }
         }
+
+        @Override
+        public void screenCallFurther(String callId) {
+            // TODO: implement this
+        }
     }
 
     private final Context mContext;
@@ -194,12 +200,12 @@
     private boolean mHasFinished = false;
     private int mCallScreeningServiceType;
 
-    private CallFilteringResult mResult = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, //shouldReject
-            true, //shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private CallFilteringResult mResult = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
     public CallScreeningServiceFilter(
             Context context,
diff --git a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java b/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
index 3a8ff7d..16d731b 100644
--- a/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
+++ b/src/com/android/server/telecom/callfiltering/DirectToVoicemailCallFilter.java
@@ -17,13 +17,14 @@
 package com.android.server.telecom.callfiltering;
 
 import android.net.Uri;
-import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.telecom.Log;
 
 import com.android.internal.telephony.CallerInfo;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallerInfoLookupHelper;
 import com.android.server.telecom.LogUtils;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 
 import java.util.Objects;
 
@@ -46,33 +47,32 @@
                         CallFilteringResult result;
                         if ((handle != null) && Objects.equals(callHandle, handle)) {
                             if (info != null && info.shouldSendToVoicemail) {
-                                result = new CallFilteringResult(
-                                        false, // shouldAllowCall
-                                        true, // shouldReject
-                                        true, // shouldAddToCallLog
-                                        true, // shouldShowNotification
-                                        CallLog.Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL,
-                                        //callBlockReason
-                                        null, //callScreeningAppName
-                                        null // callScreeningComponentName
-                                );
+                                result = new Builder()
+                                        .setShouldAllowCall(false)
+                                        .setShouldReject(true)
+                                        .setShouldAddToCallLog(true)
+                                        .setShouldShowNotification(true)
+                                        .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
+                                        .setCallScreeningAppName(null)
+                                        .setCallScreeningComponentName(null)
+                                        .build();
                             } else {
-                                result = new CallFilteringResult(
-                                        true, // shouldAllowCall
-                                        false, // shouldReject
-                                        true, // shouldAddToCallLog
-                                        true // shouldShowNotification
-                                );
+                                result = new Builder()
+                                        .setShouldAllowCall(true)
+                                        .setShouldReject(false)
+                                        .setShouldAddToCallLog(true)
+                                        .setShouldShowNotification(true)
+                                        .build();
                             }
                             Log.addEvent(call, LogUtils.Events.DIRECT_TO_VM_FINISHED, result);
                             callback.onCallFilteringComplete(call, result);
                         } else {
-                            result = new CallFilteringResult(
-                                true, // shouldAllowCall
-                                false, // shouldReject
-                                true, // shouldAddToCallLog
-                                true // shouldShowNotification
-                            );
+                            result = new Builder()
+                                    .setShouldAllowCall(true)
+                                    .setShouldReject(false)
+                                    .setShouldAddToCallLog(true)
+                                    .setShouldShowNotification(true)
+                                    .build();
                             Log.addEvent(call, LogUtils.Events.DIRECT_TO_VM_FINISHED, result);
                             Log.w(this, "CallerInfo lookup returned with a different handle than " +
                                     "what was passed in. Was %s, should be %s", handle, callHandle);
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
index cc686ab..860de1f 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilter.java
@@ -27,6 +27,7 @@
 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;
 
@@ -53,12 +54,12 @@
     private final CallFilterResultCallback mListener;
     private final Timeouts.Adapter mTimeoutsAdapter;
 
-    private CallFilteringResult mResult = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private CallFilteringResult mResult = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
     private boolean mIsPending = true;
     private int mNumPendingFilters;
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index ae4a7d8..134db80 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -22,13 +22,11 @@
 import android.net.Uri;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.telecom.DefaultDialerManager;
 import android.telecom.Log;
 import android.telecom.PhoneAccount;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
 
 import com.android.server.telecom.CallIntentProcessor;
 import com.android.server.telecom.R;
@@ -153,31 +151,12 @@
                 VideoProfile.STATE_AUDIO_ONLY);
         Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
 
-        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
-                isDefaultOrSystemDialer(callingPackageName));
-
         // Save the user handle of current user before forwarding the intent to primary user.
         intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
 
         sendIntentToDestination(intent, isLocalInvocation, callingPackageName);
     }
 
-    private boolean isDefaultOrSystemDialer(String callingPackageName) {
-        if (TextUtils.isEmpty(callingPackageName)) {
-            return false;
-        }
-
-        final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext,
-                mUserHandle.getIdentifier());
-        if (TextUtils.equals(defaultDialer, callingPackageName)) {
-            return true;
-        }
-
-        final TelecomManager telecomManager =
-                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-        return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName);
-    }
-
     /**
      * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
      *
@@ -211,7 +190,7 @@
             // process; we need to trampoline to TelecomSystem in the system server process.
             Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
             TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-            tm.handleCallIntent(intent);
+            tm.handleCallIntent(intent, callingPackage);
         }
         return true;
     }
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index 1fad3f7..ec5f7ba 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -25,6 +25,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.os.Build;
@@ -39,6 +40,8 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoCallImpl;
 import android.telecom.VideoProfile;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
@@ -60,6 +63,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -70,10 +74,16 @@
 
 @RunWith(JUnit4.class)
 public class AnalyticsTests extends TelecomSystemTest {
+    private SubscriptionManager mSubscriptionManager;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        // this is a mock
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Collections.emptyList());
     }
 
     @Override
@@ -253,7 +263,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -300,6 +310,7 @@
     @Test
     public void testAnalyticsDumpToProto() throws Exception {
         Analytics.reset();
+        setupCarrierIds();
         IdPair testCall = startAndMakeActiveIncomingCall(
                 "650-555-1212",
                 mPhoneAccountA0.getAccountHandle(),
@@ -311,10 +322,11 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
+        assertEquals(1, analyticsProto.getCarrierId());
         assertEquals(1, analyticsProto.callLogs.length);
         TelecomLogClass.CallLog callLog = analyticsProto.callLogs[0];
 
@@ -413,7 +425,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -432,7 +444,7 @@
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
-        Analytics.dumpToEncodedProto(pw, new String[]{});
+        Analytics.dumpToEncodedProto(mContext, pw, new String[]{});
         TelecomLogClass.TelecomLog analyticsProto =
                 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT));
 
@@ -445,4 +457,17 @@
     private void assertIsRoundedToOneSigFig(long x) {
         assertEquals(x, Analytics.roundToOneSigFig(x));
     }
+
+    private void setupCarrierIds() {
+        SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class);
+        SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class);
+        when(subInfo1.getCarrierId()).thenReturn(1);
+        when(subInfo2.getCarrierId()).thenReturn(2);
+        when(subInfo1.isOpportunistic()).thenReturn(false);
+        when(subInfo2.isOpportunistic()).thenReturn(true);
+        when(subInfo1.getSimSlotIndex()).thenReturn(0);
+        when(subInfo2.getSimSlotIndex()).thenReturn(1);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList())
+                .thenReturn(Arrays.asList(subInfo2, subInfo1));
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java b/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java
index ebc2826..ee34b0c 100644
--- a/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/AsyncBlockCheckFilterTest.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -34,6 +34,7 @@
 import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
 import com.android.server.telecom.callfiltering.CallFilterResultCallback;
 import com.android.server.telecom.callfiltering.CallFilteringResult;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 
 import org.junit.After;
 import org.junit.Before;
@@ -61,23 +62,22 @@
     @Mock private CarrierConfigManager mCarrierConfigManager;
 
     private AsyncBlockCheckFilter mFilter;
-    private static final CallFilteringResult BLOCK_RESULT = new CallFilteringResult(
-            false, // shouldAllowCall
-            true, //shouldReject
-            true, //shouldAddToCallLog
-            false, // shouldShowNotification
-            CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER, //blockReason
-            null, // callScreeningAppName
-            null //callScreeningComponentName
+    private static final CallFilteringResult 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 PASS_RESULT = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private static final CallFilteringResult PASS_RESULT = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
     private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
     private static final int TEST_TIMEOUT = 1000;
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index 6c5ee8b..3251d7d 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -19,16 +19,19 @@
 import android.media.ToneGenerator;
 import android.telecom.DisconnectCause;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.SparseArray;
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallAudioModeStateMachine;
+import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs;
 import com.android.server.telecom.CallAudioRouteStateMachine;
 import com.android.server.telecom.CallState;
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.DtmfLocalTonePlayer;
 import com.android.server.telecom.InCallTonePlayer;
+import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs.Builder;
 import com.android.server.telecom.RingbackPlayer;
 import com.android.server.telecom.Ringer;
 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
@@ -46,13 +49,16 @@
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -104,12 +110,11 @@
     public void testUnmuteOfSecondIncomingCall() {
         // Start with a single incoming call.
         Call call = createIncomingCall();
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
         when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO))
                 .thenReturn(false);
         when(call.getId()).thenReturn("1");
 
-        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
-                ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
         // Answer the incoming call
         mCallAudioManager.onIncomingCallAnswered(call);
         when(call.getState()).thenReturn(CallState.ACTIVE);
@@ -117,14 +122,15 @@
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
         CallAudioModeStateMachine.MessageArgs correctArgs =
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                );
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
         assertMessageArgEquality(correctArgs, captor.getValue());
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
@@ -167,11 +173,10 @@
     @Test
     public void testSingleIncomingCallFlowWithoutMTSpeedUp() {
         Call call = createIncomingCall();
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
         when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO))
                 .thenReturn(false);
 
-        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
-                ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
         // Answer the incoming call
         mCallAudioManager.onIncomingCallAnswered(call);
         when(call.getState()).thenReturn(CallState.ACTIVE);
@@ -179,14 +184,15 @@
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
         CallAudioModeStateMachine.MessageArgs correctArgs =
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                );
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
         assertMessageArgEquality(correctArgs, captor.getValue());
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
@@ -203,12 +209,11 @@
     @Test
     public void testSingleIncomingCallFlowWithMTSpeedUp() {
         Call call = createIncomingCall();
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
         when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO))
                 .thenReturn(true);
         when(call.getState()).thenReturn(CallState.ANSWERED);
 
-        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
-                ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
         // Answer the incoming call
         mCallAudioManager.onCallStateChanged(call, CallState.RINGING, CallState.ANSWERED);
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
@@ -216,14 +221,15 @@
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
         CallAudioModeStateMachine.MessageArgs correctArgs =
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                );
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
         assertMessageArgEquality(correctArgs, captor.getValue());
         assertMessageArgEquality(correctArgs, captor.getValue());
         when(call.getState()).thenReturn(CallState.ACTIVE);
@@ -240,25 +246,25 @@
     @Test
     public void testSingleOutgoingCall() {
         Call call = mock(Call.class);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
         when(call.getState()).thenReturn(CallState.CONNECTING);
 
         mCallAudioManager.onCallAdded(call);
         assertEquals(call, mCallAudioManager.getForegroundCall());
-        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
-                ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
         verify(mCallAudioRouteStateMachine).sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
         CallAudioModeStateMachine.MessageArgs expectedArgs =
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                );
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
         assertMessageArgEquality(expectedArgs, captor.getValue());
 
         when(call.getState()).thenReturn(CallState.DIALING);
@@ -285,6 +291,347 @@
         verifyProperCleanup();
     }
 
+    @SmallTest
+    @Test
+    public void testNewCallGoesToAudioProcessing() {
+        Call call = mock(Call.class);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+        when(call.getState()).thenReturn(CallState.NEW);
+
+        // Make sure nothing happens when we add the NEW call
+        mCallAudioManager.onCallAdded(call);
+
+        verify(mCallAudioRouteStateMachine, never()).sendMessageWithSessionInfo(anyInt());
+        verify(mCallAudioModeStateMachine, never()).sendMessageWithArgs(
+                anyInt(), nullable(MessageArgs.class));
+
+        // Transition the call to AUDIO_PROCESSING and see what happens
+        when(call.getState()).thenReturn(CallState.AUDIO_PROCESSING);
+        mCallAudioManager.onCallStateChanged(call, CallState.NEW, CallState.AUDIO_PROCESSING);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL), captor.capture());
+
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+    }
+
+    @SmallTest
+    @Test
+    public void testRingingCallGoesToAudioProcessing() {
+        Call call = mock(Call.class);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+        when(call.getState()).thenReturn(CallState.RINGING);
+
+        // Make sure appropriate messages are sent when we add a RINGING call
+        mCallAudioManager.onCallAdded(call);
+
+        assertEquals(call, mCallAudioManager.getForegroundCall());
+        verify(mCallAudioRouteStateMachine).sendMessageWithSessionInfo(
+                CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_RINGING_CALL), captor.capture());
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+
+        // Transition the call to AUDIO_PROCESSING and see what happens
+        when(call.getState()).thenReturn(CallState.AUDIO_PROCESSING);
+        mCallAudioManager.onCallStateChanged(call, CallState.RINGING, CallState.AUDIO_PROCESSING);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL), captor.capture());
+
+        CallAudioModeStateMachine.MessageArgs expectedArgs2 =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+    }
+
+    @SmallTest
+    @Test
+    public void testActiveCallGoesToAudioProcessing() {
+        Call call = mock(Call.class);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+        when(call.getState()).thenReturn(CallState.ACTIVE);
+
+        // Make sure appropriate messages are sent when we add an active call
+        mCallAudioManager.onCallAdded(call);
+
+        assertEquals(call, mCallAudioManager.getForegroundCall());
+        verify(mCallAudioRouteStateMachine).sendMessageWithSessionInfo(
+                CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+
+        // Transition the call to AUDIO_PROCESSING and see what happens
+        when(call.getState()).thenReturn(CallState.AUDIO_PROCESSING);
+        mCallAudioManager.onCallStateChanged(call, CallState.ACTIVE, CallState.AUDIO_PROCESSING);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL), captor.capture());
+
+        CallAudioModeStateMachine.MessageArgs expectedArgs2 =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+    }
+
+    @SmallTest
+    @Test
+    public void testAudioProcessingCallDisconnects() {
+        Call call = createAudioProcessingCall();
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        when(call.getState()).thenReturn(CallState.DISCONNECTED);
+        when(call.getDisconnectCause()).thenReturn(new DisconnectCause(DisconnectCause.LOCAL,
+                "", "", "", ToneGenerator.TONE_UNKNOWN));
+
+        mCallAudioManager.onCallStateChanged(call, CallState.AUDIO_PROCESSING,
+                CallState.DISCONNECTED);
+        verify(mPlayerFactory, never()).createPlayer(anyInt());
+        CallAudioModeStateMachine.MessageArgs expectedArgs2 = new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setHasAudioProcessingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+        verify(mCallAudioModeStateMachine, never()).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.TONE_STARTED_PLAYING), nullable(MessageArgs.class));
+
+        mCallAudioManager.onCallRemoved(call);
+        verifyProperCleanup();
+    }
+
+    @SmallTest
+    @Test
+    public void testAudioProcessingCallDoesSimulatedRing() {
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        Call call = createAudioProcessingCall();
+
+        when(call.getState()).thenReturn(CallState.SIMULATED_RINGING);
+
+        mCallAudioManager.onCallStateChanged(call, CallState.AUDIO_PROCESSING,
+                CallState.SIMULATED_RINGING);
+        verify(mPlayerFactory, never()).createPlayer(anyInt());
+        CallAudioModeStateMachine.MessageArgs expectedArgs = new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(true)
+                .setHasHoldingCalls(false)
+                .setHasAudioProcessingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_RINGING_CALL), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+    }
+
+    @SmallTest
+    @Test
+    public void testAudioProcessingCallGoesActive() {
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        Call call = createAudioProcessingCall();
+
+        when(call.getState()).thenReturn(CallState.ACTIVE);
+
+        mCallAudioManager.onCallStateChanged(call, CallState.AUDIO_PROCESSING,
+                CallState.ACTIVE);
+        verify(mPlayerFactory, never()).createPlayer(anyInt());
+        CallAudioModeStateMachine.MessageArgs expectedArgs = new Builder()
+                .setHasActiveOrDialingCalls(true)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setHasAudioProcessingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+    }
+
+    @SmallTest
+    @Test
+    public void testSimulatedRingingCallGoesActive() {
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        Call call = createSimulatedRingingCall();
+
+        when(call.getState()).thenReturn(CallState.ACTIVE);
+
+        mCallAudioManager.onCallStateChanged(call, CallState.SIMULATED_RINGING,
+                CallState.ACTIVE);
+        verify(mPlayerFactory, never()).createPlayer(anyInt());
+        CallAudioModeStateMachine.MessageArgs expectedArgs = new Builder()
+                .setHasActiveOrDialingCalls(true)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setHasAudioProcessingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+    }
+
+    private Call createAudioProcessingCall() {
+        Call call = mock(Call.class);
+        when(call.getState()).thenReturn(CallState.AUDIO_PROCESSING);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        // Set up an AUDIO_PROCESSING call
+        mCallAudioManager.onCallAdded(call);
+
+        assertNull(mCallAudioManager.getForegroundCall());
+
+        verify(mCallAudioRouteStateMachine, never()).sendMessageWithSessionInfo(
+                CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL), captor.capture());
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+
+        return call;
+    }
+
+    @SmallTest
+    @Test
+    public void testSimulatedRingingCallDisconnects() {
+        Call call = createSimulatedRingingCall();
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        when(call.getState()).thenReturn(CallState.DISCONNECTED);
+        when(call.getDisconnectCause()).thenReturn(new DisconnectCause(DisconnectCause.LOCAL,
+                "", "", "", ToneGenerator.TONE_UNKNOWN));
+
+        mCallAudioManager.onCallStateChanged(call, CallState.SIMULATED_RINGING,
+                CallState.DISCONNECTED);
+        verify(mPlayerFactory, never()).createPlayer(anyInt());
+        CallAudioModeStateMachine.MessageArgs expectedArgs2 = new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setHasAudioProcessingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
+        assertMessageArgEquality(expectedArgs2, captor.getValue());
+        verify(mCallAudioModeStateMachine, never()).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.TONE_STARTED_PLAYING), nullable(MessageArgs.class));
+
+        mCallAudioManager.onCallRemoved(call);
+        verifyProperCleanup();
+    }
+
+    private Call createSimulatedRingingCall() {
+        Call call = mock(Call.class);
+        when(call.getState()).thenReturn(CallState.SIMULATED_RINGING);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+
+        mCallAudioManager.onCallAdded(call);
+
+        assertEquals(call, mCallAudioManager.getForegroundCall());
+
+        verify(mCallAudioRouteStateMachine).sendMessageWithSessionInfo(
+                CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_RINGING_CALL), captor.capture());
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+
+        return call;
+    }
+
     private Call createIncomingCall() {
         Call call = mock(Call.class);
         when(call.getState()).thenReturn(CallState.RINGING);
@@ -297,14 +644,15 @@
                 CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NEW_RINGING_CALL), captor.capture());
-        assertMessageArgEquality(new CallAudioModeStateMachine.MessageArgs(
-                false, // hasActiveOrDialingCalls
-                true, // hasRingingCalls
-                false, // hasHoldingCalls
-                false, // isTonePlaying
-                false, // foregroundCallIsVoip
-                null // session
-        ), captor.getValue());
+        assertMessageArgEquality(new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                captor.getValue());
 
         return call;
     }
@@ -320,14 +668,14 @@
 
         mCallAudioManager.onCallStateChanged(call, CallState.ACTIVE, CallState.DISCONNECTED);
         verify(mPlayerFactory).createPlayer(InCallTonePlayer.TONE_CALL_ENDED);
-        correctArgs = new CallAudioModeStateMachine.MessageArgs(
-                false, // hasActiveOrDialingCalls
-                false, // hasRingingCalls
-                false, // hasHoldingCalls
-                true, // isTonePlaying
-                false, // foregroundCallIsVoip
-                null // session
-        );
+        correctArgs = new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setIsTonePlaying(true)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build();
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS), captor.capture());
         assertMessageArgEquality(correctArgs, captor.getValue());
@@ -340,15 +688,14 @@
         ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
                 ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
         mCallAudioManager.setIsTonePlaying(false);
-        CallAudioModeStateMachine.MessageArgs correctArgs =
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                );
+        CallAudioModeStateMachine.MessageArgs correctArgs = new Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
         verify(mCallAudioModeStateMachine).sendMessageWithArgs(
                 eq(CallAudioModeStateMachine.TONE_STOPPED_PLAYING), captor.capture());
         assertMessageArgEquality(correctArgs, captor.getValue());
@@ -362,6 +709,10 @@
         }
     }
 
+    private ArgumentCaptor<MessageArgs> makeNewCaptor() {
+        return ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
+    }
+
     private void assertMessageArgEquality(CallAudioModeStateMachine.MessageArgs expected,
             CallAudioModeStateMachine.MessageArgs actual) {
         assertEquals(expected.hasActiveOrDialingCalls, actual.hasActiveOrDialingCalls);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
index 0e33721..ca84c4c 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
@@ -23,6 +23,7 @@
 import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.CallAudioModeStateMachine;
 import com.android.server.telecom.CallAudioRouteStateMachine;
+import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs.Builder;
 import com.android.server.telecom.SystemStateHelper;
 
 import org.junit.After;
@@ -79,15 +80,14 @@
         resetMocks();
         when(mCallAudioManager.startRinging()).thenReturn(false);
 
-        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL,
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ));
+        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL, new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(true)
+                .setHasHoldingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build());
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
 
         assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
@@ -107,29 +107,27 @@
                 mAudioManager, mTestThread.getLooper());
         sm.setCallAudioManager(mCallAudioManager);
         sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
-        sm.sendMessage(CallAudioModeStateMachine.NEW_HOLDING_CALL,
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ));
+        sm.sendMessage(CallAudioModeStateMachine.NEW_HOLDING_CALL, new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(true)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build());
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
         assertEquals(CallAudioModeStateMachine.TONE_HOLD_STATE_NAME, sm.getCurrentStateName());
         when(mSystemStateHelper.isDeviceAtEar()).thenReturn(true);
 
         resetMocks();
-        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL,
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ));
+        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL, new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(true)
+                .setHasHoldingCalls(true)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build());
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
 
         verify(mAudioManager, never()).requestAudioFocusForCall(anyInt(), anyInt());
@@ -150,15 +148,14 @@
         resetMocks();
         when(mCallAudioManager.startRinging()).thenReturn(false);
 
-        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL,
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ));
+        sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL, new Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(true)
+                .setHasHoldingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(null)
+                .build());
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
 
         assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
index c90557d..2047867 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
@@ -16,13 +16,13 @@
 
 package com.android.server.telecom.tests;
 
-import android.content.Context;
 import android.media.AudioManager;
 import android.os.HandlerThread;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.CallAudioModeStateMachine;
+import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs;
 import com.android.server.telecom.SystemStateHelper;
 
 import org.junit.After;
@@ -200,14 +200,14 @@
                 "New active/dialing call with no other calls when unfocused",
                 CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -219,14 +219,14 @@
                 "New active/dialing voip call with no other calls when unfocused",
                 CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        true, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(true)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.COMMS_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_COMMUNICATION, // expectedMode
@@ -238,14 +238,14 @@
                 "New ringing call with no other calls when unfocused",
                 CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_RINGING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
                 FOCUS_RING, // expectedFocus
                 AudioManager.MODE_RINGTONE, // expectedMode
@@ -257,14 +257,14 @@
                 "New ringing call coming in on top of active/dialing call",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_RINGING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -276,14 +276,14 @@
                 "Ringing call becomes active, part 1",
                 CallAudioModeStateMachine.ENTER_RING_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -295,14 +295,14 @@
                 "Ringing call becomes active, part 2",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -314,14 +314,14 @@
                 "Active call disconnects, but tone is playing",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        true, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.TONE_HOLD_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -333,14 +333,14 @@
                 "Tone stops playing, with no active calls",
                 CallAudioModeStateMachine.ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.TONE_STOPPED_PLAYING, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.UNFOCUSED_STATE_NAME, // expectedFinalStateName
                 FOCUS_OFF, // expectedFocus
                 AudioManager.MODE_NORMAL, // expectedMode
@@ -352,14 +352,14 @@
                 "Ringing call disconnects",
                 CallAudioModeStateMachine.ENTER_RING_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.UNFOCUSED_STATE_NAME, // expectedFinalStateName
                 FOCUS_OFF, // expectedFocus
                 AudioManager.MODE_NORMAL, // expectedMode
@@ -371,14 +371,14 @@
                 "Call-waiting call disconnects",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        true, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -390,14 +390,14 @@
                 "Call is placed on hold - 1",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.TONE_HOLD_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -409,14 +409,14 @@
                 "Call is placed on hold - 2",
                 CallAudioModeStateMachine.ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_HOLDING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.TONE_HOLD_STATE_NAME, // expectedFinalStateName
                 FOCUS_NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -428,14 +428,14 @@
                 "Swap between voip and sim calls - 1",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_HOLDING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        true, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(true)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.COMMS_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_COMMUNICATION, // expectedMode
@@ -447,14 +447,14 @@
                 "Swap between voip and sim calls - 2",
                 CallAudioModeStateMachine.ENTER_COMMS_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_HOLDING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -466,14 +466,14 @@
                 "Swap between voip and sim calls - 3",
                 CallAudioModeStateMachine.ENTER_COMMS_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -485,14 +485,14 @@
                 "Swap between voip and sim calls - 4",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_HOLDING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        true, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(true)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.COMMS_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_COMMUNICATION, // expectedMode
@@ -504,14 +504,14 @@
                 "Call is taken off hold - 1",
                 CallAudioModeStateMachine.ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_HOLDING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -523,14 +523,14 @@
                 "Call is taken off hold - 2",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -542,14 +542,14 @@
                 "Active call disconnects while there's a call-waiting call",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        true, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        true, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
                 FOCUS_RING, // expectedFocus
                 AudioManager.MODE_RINGTONE, // expectedMode
@@ -561,14 +561,14 @@
                 "New dialing call when there's a call on hold",
                 CallAudioModeStateMachine.ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -580,14 +580,14 @@
                 "Ringing call disconnects with a holding call in the background",
                 CallAudioModeStateMachine.ENTER_RING_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        false, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        true, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.TONE_HOLD_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_NORMAL, // expectedMode -- we're expecting this because
@@ -600,14 +600,14 @@
                 "Foreground call transitions from sim to voip",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.FOREGROUND_VOIP_MODE_CHANGE, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        true, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(true)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.COMMS_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_COMMUNICATION, // expectedMode
@@ -619,14 +619,14 @@
                 "Foreground call transitions from voip to sim",
                 CallAudioModeStateMachine.ENTER_COMMS_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.FOREGROUND_VOIP_MODE_CHANGE, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        false, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_VOICE, // expectedFocus
                 AudioManager.MODE_IN_CALL, // expectedMode
@@ -639,14 +639,14 @@
                         "foreground",
                 CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        true, // isTonePlaying
-                        false, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(true)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
                 FOCUS_NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -659,14 +659,14 @@
                         "foreground",
                 CallAudioModeStateMachine.ENTER_COMMS_FOCUS_FOR_TESTING, // initialAudioState
                 CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
-                new CallAudioModeStateMachine.MessageArgs(
-                        true, // hasActiveOrDialingCalls
-                        false, // hasRingingCalls
-                        false, // hasHoldingCalls
-                        true, // isTonePlaying
-                        true, // foregroundCallIsVoip
-                        null // session
-                ),
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(true)
+                        .setForegroundCallIsVoip(true)
+                        .setSession(null)
+                        .build(),
                 CallAudioModeStateMachine.COMMS_STATE_NAME, // expectedFinalStateName
                 FOCUS_NO_CHANGE, // expectedFocus
                 NO_CHANGE, // expectedMode
@@ -674,6 +674,188 @@
                 OFF // expectedCallWaitingInteraction
         ));
 
+        result.add(new ModeTestParameters(
+                "Call enters audio processing state from call screening service",
+                CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING, // initialAudioState
+                CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.AUDIO_PROCESSING_STATE_NAME, // expectedFinalStateName
+                FOCUS_NO_CHANGE, // expectedFocus
+                CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING, // expectedMode
+                NO_CHANGE, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Call enters audio processing state by manual intervention from ringing state, 1",
+                CallAudioModeStateMachine.ENTER_RING_FOCUS_FOR_TESTING, // initialAudioState
+                CallAudioModeStateMachine.NO_MORE_RINGING_CALLS, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.AUDIO_PROCESSING_STATE_NAME, // expectedFinalStateName
+                FOCUS_OFF, // expectedFocus
+                CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING, // expectedMode
+                OFF, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Call enters audio processing state by manual intervention from ringing state, 2",
+                CallAudioModeStateMachine.ENTER_RING_FOCUS_FOR_TESTING, // initialAudioState
+                CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.AUDIO_PROCESSING_STATE_NAME, // expectedFinalStateName
+                FOCUS_OFF, // expectedFocus
+                CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING, // expectedMode
+                OFF, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Call enters audio processing state from active call, 1",
+                CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
+                CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.AUDIO_PROCESSING_STATE_NAME, // expectedFinalStateName
+                FOCUS_OFF, // expectedFocus
+                CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING, // expectedMode
+                NO_CHANGE, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Call enters audio processing state from active call, 2",
+                CallAudioModeStateMachine.ENTER_CALL_FOCUS_FOR_TESTING, // initialAudioState
+                CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(true)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.AUDIO_PROCESSING_STATE_NAME, // expectedFinalStateName
+                FOCUS_OFF, // expectedFocus
+                CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING, // expectedMode
+                NO_CHANGE, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Call in audio processing gets hanged up",
+                CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, // initialAudioS
+                CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.UNFOCUSED_STATE_NAME, // expectedFinalStateName
+                NO_CHANGE, // expectedFocus
+                AudioManager.MODE_NORMAL, // expectedMode
+                NO_CHANGE, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Notify user of a call in audio processing by simulating ringing, 1",
+                CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, // initialAudioS
+                CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
+                FOCUS_RING, // expectedFocus
+                AudioManager.MODE_RINGTONE, // expectedMode
+                ON, // expectedRingingInteraction
+                // We expect a call to stopCallWaiting because it happens whenever the ringer starts
+                OFF // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Notify user of a call in audio processing by simulating ringing, 2",
+                CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, // initialAudioS
+                CallAudioModeStateMachine.NEW_RINGING_CALL, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(false)
+                        .setHasRingingCalls(true)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
+                FOCUS_RING, // expectedFocus
+                AudioManager.MODE_RINGTONE, // expectedMode
+                ON, // expectedRingingInteraction
+                // We expect a call to stopCallWaiting because it happens whenever the ringer starts
+                OFF // expectedCallWaitingInteraction
+        ));
+
+        result.add(new ModeTestParameters(
+                "Audio processing call gets set to active manually",
+                CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, // initialAudioS
+                CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS, // messageType
+                new MessageArgs.Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build(),
+                CallAudioModeStateMachine.CALL_STATE_NAME, // expectedFinalStateName
+                FOCUS_VOICE, // expectedFocus
+                AudioManager.MODE_IN_CALL, // expectedMode
+                NO_CHANGE, // expectedRingingInteraction
+                NO_CHANGE // expectedCallWaitingInteraction
+        ));
+
         return result;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
index c4acfe0..24cc8d2 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
@@ -29,6 +29,7 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -45,6 +46,7 @@
 import com.android.server.telecom.TelecomSystem;
 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.CallScreeningServiceController;
 
 import org.junit.After;
@@ -70,31 +72,6 @@
 @RunWith(JUnit4.class)
 public class CallScreeningServiceControllerTest extends TelecomTestCase {
 
-    @Mock Context mContext;
-    @Mock Call mCall;
-    @Mock private CallFilterResultCallback mCallback;
-    @Mock CallsManager mCallsManager;
-    @Mock RoleManagerAdapter mRoleManagerAdapter;
-    @Mock CarrierConfigManager mCarrierConfigManager;
-    @Mock private TelecomManager mTelecomManager;
-    @Mock PackageManager mPackageManager;
-    @Mock ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
-    @Mock PhoneAccountRegistrar mPhoneAccountRegistrar;
-    @Mock private CallerInfoLookupHelper mCallerInfoLookupHelper;
-
-    CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy =
-            new CallScreeningServiceHelper.AppLabelProxy() {
-        @Override
-        public CharSequence getAppLabel(String packageName) {
-            return APP_NAME;
-        }
-    };
-
-    private ResolveInfo mResolveInfo;
-    private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
-            spy(new CallScreeningServiceFilterTest.SettingsSecureAdapterFake());
-    private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
-
     private static final String CALL_ID = "u89prgt9ps78y5";
     private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");
     private static final String DEFAULT_DIALER_PACKAGE = "com.android.dialer";
@@ -107,27 +84,46 @@
             "com.android.dialer", "com.android.dialer.callscreeningserviceimpl");
     private static final ComponentName USER_CHOSEN_CALL_SCREENING = new ComponentName(
             "com.android.userchosen", "com.android.userchosen.callscreeningserviceimpl");
-
-    private static final CallFilteringResult PASS_RESULT = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
-
-    public static class SettingsSecureAdapterFake implements
-            TelecomServiceImpl.SettingsSecureAdapter {
-        @Override
-        public void putStringForUser(ContentResolver resolver, String name, String value,
-                                     int userHandle) {
-
-        }
-
-        @Override
-        public String getStringForUser(ContentResolver resolver, String name, int userHandle) {
-            return USER_CHOSEN_CALL_SCREENING.flattenToString();
-        }
-    }
+    private static final CallFilteringResult PASS_RESULT = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
+    @Mock
+    Context mContext;
+    @Mock
+    Call mCall;
+    @Mock
+    CallsManager mCallsManager;
+    @Mock
+    RoleManagerAdapter mRoleManagerAdapter;
+    @Mock
+    CarrierConfigManager mCarrierConfigManager;
+    @Mock
+    PackageManager mPackageManager;
+    @Mock
+    ParcelableCallUtils.Converter mParcelableCallUtilsConverter;
+    @Mock
+    PhoneAccountRegistrar mPhoneAccountRegistrar;
+    CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy =
+            new CallScreeningServiceHelper.AppLabelProxy() {
+                @Override
+                public CharSequence getAppLabel(String packageName) {
+                    return APP_NAME;
+                }
+            };
+    @Mock
+    private CallFilterResultCallback mCallback;
+    @Mock
+    private TelecomManager mTelecomManager;
+    @Mock
+    private CallerInfoLookupHelper mCallerInfoLookupHelper;
+    private ResolveInfo mResolveInfo;
+    private TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter =
+            spy(new CallScreeningServiceFilterTest.SettingsSecureAdapterFake());
+    private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {
+    };
 
     @Override
     @Before
@@ -145,7 +141,7 @@
         when(TelecomManager.from(mContext)).thenReturn(mTelecomManager);
         when(mTelecomManager.getDefaultDialerPackage()).thenReturn(DEFAULT_DIALER_PACKAGE);
 
-        mResolveInfo =  new ResolveInfo() {{
+        mResolveInfo = new ResolveInfo() {{
             serviceInfo = new ServiceInfo();
             serviceInfo.packageName = PKG_NAME;
             serviceInfo.name = CLS_NAME;
@@ -236,30 +232,27 @@
 
         controller.startFilterLookup(mCall, mCallback);
 
-        controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                false, // shouldAddToCallLog
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
-                APP_NAME,
-                CARRIER_DEFINED_CALL_SCREENING.flattenToString()
-        ), CARRIER_DEFINED_CALL_SCREENING.getPackageName());
+        CallFilteringResult expectedResult = new Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldAddToCallLog(false)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                .setCallScreeningAppName(APP_NAME)
+                .setCallScreeningComponentName(
+                        CARRIER_DEFINED_CALL_SCREENING.flattenToString())
+                .build();
+
+        controller.onCallScreeningFilterComplete(mCall, expectedResult,
+                CARRIER_DEFINED_CALL_SCREENING.getPackageName());
 
         verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
                 any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.CURRENT));
 
-        verify(mCallback).onCallFilteringComplete(eq(mCall), eq(new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                false, // shouldAddToCallLog
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                APP_NAME, //callScreeningAppName
-                CARRIER_DEFINED_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )));
+        verify(mCallback)
+                .onCallFilteringComplete(eq(mCall), eq(expectedResult));
     }
 
     @SmallTest
@@ -282,30 +275,31 @@
         callerInfo.contactExists = false;
         queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
 
-        controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                false, // shouldAddToCallLog
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
-                APP_NAME,
-                DEFAULT_DIALER_CALL_SCREENING.flattenToString()
-        ), DEFAULT_DIALER_CALL_SCREENING.getPackageName());
+        CallFilteringResult.Builder resultBuilder = new Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                .setCallScreeningAppName(APP_NAME)
+                .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString());
+
+        CallFilteringResult providedResult = resultBuilder
+                .setShouldAddToCallLog(false)
+                .build();
+
+        controller.onCallScreeningFilterComplete(mCall, providedResult,
+                DEFAULT_DIALER_CALL_SCREENING.getPackageName());
 
         verify(mContext, times(3)).bindServiceAsUser(any(Intent.class),
                 any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.CURRENT));
 
-        verify(mCallback).onCallFilteringComplete(eq(mCall), eq(new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                true, // shouldAddToCallLog (we don't allow services to skip call log)
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                APP_NAME, //callScreeningAppName
-                DEFAULT_DIALER_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )));
+        CallFilteringResult expectedResult = resultBuilder
+                .setShouldAddToCallLog(true)
+                .build();
+
+        verify(mCallback).onCallFilteringComplete(eq(mCall), eq(expectedResult));
     }
 
     @SmallTest
@@ -330,30 +324,99 @@
 
         controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
                 DEFAULT_DIALER_CALL_SCREENING.getPackageName());
-        controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                false, // shouldAddToCallLog
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
-                APP_NAME,
-                USER_CHOSEN_CALL_SCREENING.flattenToString()
-        ), USER_CHOSEN_CALL_SCREENING.getPackageName());
+
+        CallFilteringResult.Builder resultBuilder = new Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                .setCallScreeningAppName(APP_NAME)
+                .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString());
+        CallFilteringResult providedResult = resultBuilder
+                .setShouldAddToCallLog(false)
+                .build();
+
+        controller.onCallScreeningFilterComplete(mCall, providedResult,
+                USER_CHOSEN_CALL_SCREENING.getPackageName());
 
         verify(mContext, times(3)).bindServiceAsUser(any(Intent.class),
                 any(ServiceConnection.class),
                 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
                 eq(UserHandle.CURRENT));
 
-        verify(mCallback).onCallFilteringComplete(eq(mCall), eq(new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                true, // shouldAddToCallLog (we don't allow services to skip call log)
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                APP_NAME, //callScreeningAppName
-                USER_CHOSEN_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )));
+        CallFilteringResult expectedResult = resultBuilder
+                .setShouldAddToCallLog(true)
+                .build();
+
+        verify(mCallback).onCallFilteringComplete(eq(mCall), eq(expectedResult));
+    }
+
+    /**
+     * This test verifies that where the default dialer role is filled by the same app as the caller
+     * id and spam role, we will only bind to that call screening service once.
+     */
+    @SmallTest
+    @Test
+    public void testOnlyBindOnce() {
+        // Assume the user chose the default dialer to also fill the caller id and spam role.
+        when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(
+                DEFAULT_DIALER_CALL_SCREENING.getPackageName());
+        CallScreeningServiceController controller = new CallScreeningServiceController(mContext,
+                mCallsManager,
+                mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mLock,
+                mSettingsSecureAdapter, mCallerInfoLookupHelper, mAppLabelProxy);
+
+        controller.startFilterLookup(mCall, mCallback);
+
+        controller.onCallScreeningFilterComplete(mCall, PASS_RESULT,
+                CARRIER_DEFINED_CALL_SCREENING.getPackageName());
+
+        CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();
+        CallerInfo callerInfo = new CallerInfo();
+        callerInfo.contactExists = false;
+        queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
+
+        controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult.Builder()
+                        .setShouldAllowCall(false)
+                        .setShouldReject(true)
+                        .setShouldAddToCallLog(false)
+                        .setShouldShowNotification(true)
+                        .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                        .setCallScreeningAppName(APP_NAME)
+                        .setCallScreeningComponentName(
+                                DEFAULT_DIALER_CALL_SCREENING.flattenToString())
+                        .build(),
+                DEFAULT_DIALER_CALL_SCREENING.getPackageName());
+
+        controller.onCallScreeningFilterComplete(mCall, new CallFilteringResult.Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldAddToCallLog(false)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                .setCallScreeningAppName(APP_NAME)
+                .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString())
+                .build(), USER_CHOSEN_CALL_SCREENING.getPackageName());
+
+        // Expect to bind twice; once to the carrier defined service, and then again to the default
+        // dialer.
+        verify(mContext, times(2)).bindServiceAsUser(any(Intent.class),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.CURRENT));
+
+        // Expect filtering to complete only a single time from the default dialer service.
+        verify(mCallback, times(1)).onCallFilteringComplete(eq(mCall),
+                eq(new CallFilteringResult.Builder()
+                        .setShouldAllowCall(false)
+                        .setShouldReject(true)
+                        .setShouldAddToCallLog(true)
+                        .setShouldShowNotification(true)
+                        .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                        .setCallScreeningAppName(APP_NAME)
+                        .setCallScreeningComponentName(
+                                DEFAULT_DIALER_CALL_SCREENING.flattenToString())
+                        .build()));
     }
 
     private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
@@ -377,4 +440,18 @@
                 .thenReturn(mCarrierConfigManager);
         when(mCarrierConfigManager.getConfig()).thenReturn(bundle);
     }
+
+    public static class SettingsSecureAdapterFake implements
+            TelecomServiceImpl.SettingsSecureAdapter {
+        @Override
+        public void putStringForUser(ContentResolver resolver, String name, String value,
+                int userHandle) {
+
+        }
+
+        @Override
+        public String getStringForUser(ContentResolver resolver, String name, int userHandle) {
+            return USER_CHOSEN_CALL_SCREENING.flattenToString();
+        }
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index b11b397..7b3a499 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -29,7 +29,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.telecom.CallScreeningService;
 import android.telecom.ParcelableCall;
 import android.telecom.TelecomManager;
@@ -44,6 +44,7 @@
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.TelecomServiceImpl;
 import com.android.server.telecom.callfiltering.CallFilteringResult;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
 import com.android.server.telecom.TelecomSystem;
 
@@ -105,20 +106,20 @@
     private static final String USER_CHOSEN_CALL_SCREENING_APP_NAME = "UserChosen";
     private ResolveInfo mResolveInfo;
 
-    private static final CallFilteringResult PASS_RESULT = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private static final CallFilteringResult PASS_RESULT = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
-    private static final CallFilteringResult PASS_RESULT_WITH_SILENCE = new CallFilteringResult(
-            true, // shouldAllowCall
-            false, // shouldReject
-            true, // shouldSilence
-            true, // shouldAddToCallLog
-            true // shouldShowNotification
-    );
+    private static final CallFilteringResult PASS_RESULT_WITH_SILENCE = new Builder()
+            .setShouldAllowCall(true)
+            .setShouldReject(false)
+            .setShouldSilence(true)
+            .setShouldAddToCallLog(true)
+            .setShouldShowNotification(true)
+            .build();
 
     private CallScreeningServiceFilter mFilter;
 
@@ -274,15 +275,17 @@
                 true, // shouldShowNotification
                 CARRIER_DEFINED_CALL_SCREENING
         );
-        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new CallFilteringResult(
-                false, // shouldAllowCall
-                true, // shouldReject
-                false, // shouldAddToCallLog
-                true, // shouldShowNotification
-                CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                CARRIER_DEFINED_CALL_SCREENING_APP_NAME, //callScreeningAppName
-                CARRIER_DEFINED_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )), eq(CARRIER_DEFINED_CALL_SCREENING.getPackageName()));
+        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
+                        .setShouldAllowCall(false)
+                        .setShouldReject(true)
+                        .setShouldAddToCallLog(false)
+                        .setShouldShowNotification(true)
+                        .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                        .setCallScreeningAppName(CARRIER_DEFINED_CALL_SCREENING_APP_NAME)
+                        .setCallScreeningComponentName(
+                                CARRIER_DEFINED_CALL_SCREENING.flattenToString())
+                        .build()),
+                eq(CARRIER_DEFINED_CALL_SCREENING.getPackageName()));
     }
 
     @SmallTest
@@ -307,15 +310,16 @@
             true, // shouldShowNotification
             DEFAULT_DIALER_CALL_SCREENING
         );
-        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new CallFilteringResult(
-            false, // shouldAllowCall
-            true, // shouldReject
-            true, // shouldAddToCallLog
-            true, // shouldShowNotification
-            CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-            DEFAULT_DIALER_APP_NAME, //callScreeningAppName
-            DEFAULT_DIALER_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )), eq(DEFAULT_DIALER_CALL_SCREENING.getPackageName()));
+        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldAddToCallLog(true)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                .setCallScreeningAppName(DEFAULT_DIALER_APP_NAME)
+                .setCallScreeningComponentName(DEFAULT_DIALER_CALL_SCREENING.flattenToString())
+                .build()),
+                eq(DEFAULT_DIALER_CALL_SCREENING.getPackageName()));
     }
 
     @SmallTest
@@ -340,15 +344,16 @@
             true, // shouldShowNotification
             USER_CHOSEN_CALL_SCREENING
         );
-        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new CallFilteringResult(
-            false, // shouldAllowCall
-            true, // shouldReject
-            true, // shouldAddToCallLog
-            true, // shouldShowNotification
-            CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-            USER_CHOSEN_CALL_SCREENING_APP_NAME, //callScreeningAppName
-            USER_CHOSEN_CALL_SCREENING.flattenToString() //callScreeningComponentName
-        )), eq(USER_CHOSEN_CALL_SCREENING.getPackageName()));
+        verify(mCallback).onCallScreeningFilterComplete(eq(mCall), eq(new Builder()
+                        .setShouldAllowCall(false)
+                        .setShouldReject(true)
+                        .setShouldAddToCallLog(true)
+                        .setShouldShowNotification(true)
+                        .setCallBlockReason(Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
+                        .setCallScreeningAppName(USER_CHOSEN_CALL_SCREENING_APP_NAME)
+                        .setCallScreeningComponentName(USER_CHOSEN_CALL_SCREENING.flattenToString())
+                        .build()),
+                eq(USER_CHOSEN_CALL_SCREENING.getPackageName()));
     }
 
     private ServiceConnection verifyBindingIntent() {
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 165d80e..fdd1d89 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -263,7 +263,7 @@
 
         Call ongoingCall = new Call(
                 "1", /* callId */
-                mComponentContextFixture.getTestDouble(),
+                mContext,
                 mCallsManager,
                 mLock,
                 null /* ConnectionServiceRepository */,
@@ -1026,7 +1026,8 @@
     public void testIsInEmergencyCallLocal() {
         // Setup a call which is considered emergency based on its phone number.
         Call ongoingCall = addSpyCall();
-        when(mPhoneNumberUtilsAdapter.isLocalEmergencyNumber(any(), any())).thenReturn(true);
+        when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
+                .thenReturn(true);
         ongoingCall.setHandle(Uri.fromParts("tel", "5551212", null),
                 TelecomManager.PRESENTATION_ALLOWED);
 
@@ -1102,7 +1103,7 @@
 
     private Call addSpyCall(PhoneAccountHandle targetPhoneAccount) {
         Call ongoingCall = new Call(String.format("TC@%d", sCallId++), /* callId */
-                mComponentContextFixture.getTestDouble(),
+                mContext,
                 mCallsManager,
                 mLock, /* ConnectionServiceRepository */
                 null,
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 86bbadb..e6e8ba1 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -51,6 +51,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IInterface;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.CallAudioState;
@@ -209,6 +210,10 @@
                 return Context.AUDIO_SERVICE;
             } else if (svcClass == TelephonyManager.class) {
                 return Context.TELEPHONY_SERVICE;
+            } else if (svcClass == CarrierConfigManager.class) {
+                return Context.CARRIER_CONFIG_SERVICE;
+            } else if (svcClass == SubscriptionManager.class) {
+                return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
             }
             throw new UnsupportedOperationException();
         }
@@ -513,6 +518,9 @@
 
         when(mNotificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
 
+        when(mCarrierConfigManager.getConfig()).thenReturn(new PersistableBundle());
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(new PersistableBundle());
+
         when(mUserManager.getSerialNumberForUser(any(UserHandle.class))).thenReturn(-1L);
 
         doReturn(null).when(mApplicationContextSpy).registerReceiver(any(BroadcastReceiver.class),
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index c2db626..845a838 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -48,7 +48,9 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
@@ -286,6 +288,45 @@
     }
 
     /**
+     * Ensure that when a test emergency number is being dialed and we restrict the usable
+     * PhoneAccounts using {@link PhoneAccountRegistrar#filterRestrictedPhoneAccounts(List)}, the
+     * test emergency call is sent on the filtered PhoneAccount.
+     */
+    @SmallTest
+    @Test
+    public void testFakeEmergencyNumber() throws Exception {
+        when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(true);
+        // Put in a regular phone account as the target and make sure it calls that.
+        PhoneAccount regularAccount = makeEmergencyTestPhoneAccount("tel_acct1", 0);
+        PhoneAccountHandle regularAccountHandle = regularAccount.getAccountHandle();
+        List<PhoneAccount> filteredList = new ArrayList<>();
+        filteredList.add(regularAccount);
+        when(mMockAccountRegistrar.filterRestrictedPhoneAccounts(anyList()))
+                .thenReturn(filteredList);
+        mapToSubSlot(regularAccount, 1 /*subId*/, 0 /*slotId*/);
+        setTargetPhoneAccount(mMockCall, regularAccount.getAccountHandle());
+        phoneAccounts.add(regularAccount);
+        // Do not use this account, even though it is a SIM subscription and can place emergency
+        // calls
+        ConnectionServiceWrapper service = makeConnectionServiceWrapper();
+        PhoneAccount emergencyPhoneAccount = makeEmergencyPhoneAccount("tel_emer", 0);
+        mapToSubSlot(emergencyPhoneAccount, 2 /*subId*/, 1 /*slotId*/);
+        phoneAccounts.add(emergencyPhoneAccount);
+
+        mTestCreateConnectionProcessor.process();
+
+        verify(mMockCall).setConnectionManagerPhoneAccount(eq(regularAccountHandle));
+        verify(mMockCall).setTargetPhoneAccount(eq(regularAccountHandle));
+        verify(mMockCall).setConnectionService(eq(service));
+        verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class));
+        // Notify successful connection to call
+        CallIdMapper mockCallIdMapper = mock(CallIdMapper.class);
+        mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null);
+        verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
+    }
+
+    /**
      * Ensure that the non-emergency capable PhoneAccount and the SIM manager is not chosen to place
      * the emergency call if there is an emergency capable PhoneAccount available as well.
      */
@@ -293,6 +334,7 @@
     @Test
     public void testEmergencyCall() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         // Put in a regular phone account as the target to be sure it doesn't call that
         PhoneAccount regularAccount = makePhoneAccount("tel_acct1",
                 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
@@ -331,6 +373,7 @@
     @Test
     public void testEmergencyCallMultiSimNoPreferred() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         // Put in a non-SIM phone account as the target to be sure it doesn't call that.
         PhoneAccount regularAccount = makePhoneAccount("tel_acct1", 0);
         setTargetPhoneAccount(mMockCall, regularAccount.getAccountHandle());
@@ -368,6 +411,7 @@
     @Test
     public void testEmergencyCallMultiSimTelephonyPreferred() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         ConnectionServiceWrapper service = makeConnectionServiceWrapper();
         PhoneAccount emergencyPhoneAccount1 = makeEmergencyPhoneAccount("tel_emer1", 0);
         mapToSubSlot(emergencyPhoneAccount1, 1 /*subId*/, 0 /*slotId*/);
@@ -400,6 +444,7 @@
     @Test
     public void testEmergencyCallMultiSimUserPreferred() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         // Include a Connection Manager to be sure it doesn't call that
         PhoneAccount callManagerPA = createNewConnectionManagerPhoneAccountForCall(mMockCall,
                 "cm_acct", 0);
@@ -436,6 +481,7 @@
     @Test
     public void testEmergencyCallMultiSimUserPreferredInvalidSlot() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         // Include a Connection Manager to be sure it doesn't call that
         PhoneAccount callManagerPA = createNewConnectionManagerPhoneAccountForCall(mMockCall,
                 "cm_acct", 0);
@@ -472,6 +518,7 @@
     @Test
     public void testEmergencyCallMultiSimNoPreferenceInvalidSlot() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         // Include a Connection Manager to be sure it doesn't call that
         PhoneAccount callManagerPA = createNewConnectionManagerPhoneAccountForCall(mMockCall,
                 "cm_acct", 0);
@@ -503,6 +550,7 @@
     @Test
     public void testEmergencyCallSimFailToConnectionManager() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
         when(mMockCall.getHandle()).thenReturn(Uri.parse(""));
         // Put in a regular phone account to be sure it doesn't call that
         PhoneAccount regularAccount = makePhoneAccount("tel_acct1",
@@ -542,6 +590,16 @@
         verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class));
     }
 
+    private PhoneAccount makeEmergencyTestPhoneAccount(String id, int capabilities) {
+        final PhoneAccount emergencyPhoneAccount = makeQuickAccount(id, capabilities |
+                PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS);
+        PhoneAccountHandle emergencyPhoneAccountHandle = emergencyPhoneAccount.getAccountHandle();
+        givePhoneAccountBindPermission(emergencyPhoneAccountHandle);
+        when(mMockAccountRegistrar.getPhoneAccountUnchecked(emergencyPhoneAccountHandle))
+                .thenReturn(emergencyPhoneAccount);
+        return emergencyPhoneAccount;
+    }
+
     private PhoneAccount makeEmergencyPhoneAccount(String id, int capabilities) {
         final PhoneAccount emergencyPhoneAccount = makeQuickAccount(id, capabilities |
                 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
diff --git a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java b/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
index 551165d..e62a9fc 100644
--- a/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/DirectToVoicemailCallFilterTest.java
@@ -17,14 +17,14 @@
 package com.android.server.telecom.tests;
 
 import android.net.Uri;
-import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.CallerInfo;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.callfiltering.CallFilterResultCallback;
 import com.android.server.telecom.CallerInfoLookupHelper;
-import com.android.server.telecom.callfiltering.CallFilteringResult;
+import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
 import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
 
 import org.junit.After;
@@ -68,16 +68,15 @@
         callerInfo.shouldSendToVoicemail = true;
 
         queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-        verify(mCallback).onCallFilteringComplete(mCall,
-                new CallFilteringResult(
-                        false, // shouldAllowCall
-                        true, // shouldReject
-                        true, // shouldAddToCallLog
-                        true, // shouldShowNotification
-                        CallLog.Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL, //callBlockReason
-                        null, //callScreeningAppName
-                        null // callScreeningComponentName
-                ));
+        verify(mCallback).onCallFilteringComplete(mCall, new Builder()
+                .setShouldAllowCall(false)
+                .setShouldReject(true)
+                .setShouldAddToCallLog(true)
+                .setShouldShowNotification(true)
+                .setCallBlockReason(Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL)
+                .setCallScreeningAppName(null)
+                .setCallScreeningComponentName(null)
+                .build());
     }
 
     @SmallTest
@@ -89,13 +88,12 @@
         callerInfo.shouldSendToVoicemail = false;
 
         queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
-        verify(mCallback).onCallFilteringComplete(mCall,
-                new CallFilteringResult(
-                        true, // shouldAllowCall
-                        false, // shouldReject
-                        true, // shouldAddToCallLog
-                        true // shouldShowNotification
-                ));
+        verify(mCallback).onCallFilteringComplete(mCall, new Builder()
+                .setShouldAllowCall(true)
+                .setShouldReject(false)
+                .setShouldAddToCallLog(true)
+                .setShouldShowNotification(true)
+                .build());
     }
 
     @SmallTest
@@ -104,13 +102,12 @@
         CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart(null);
 
         queryListener.onCallerInfoQueryComplete(null, null);
-        verify(mCallback).onCallFilteringComplete(mCall,
-                new CallFilteringResult(
-                        true, // shouldAllowCall
-                        false, // shouldReject
-                        true, // shouldAddToCallLog
-                        true // shouldShowNotification
-                ));
+        verify(mCallback).onCallFilteringComplete(mCall, new Builder()
+                .setShouldAllowCall(true)
+                .setShouldReject(false)
+                .setShouldAddToCallLog(true)
+                .setShouldShowNotification(true)
+                .build());
     }
 
     private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index ce874f4..2577631 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -148,7 +148,10 @@
                 com.android.internal.R.string.config_defaultDialer);
         doReturn(SYS_CLASS).when(mMockResources).getString(R.string.incall_default_class);
         doReturn(true).when(mMockResources).getBoolean(R.bool.grant_location_permission_enabled);
-        mEmergencyCallHelper = new EmergencyCallHelper(mMockContext, SYS_PKG,
+        when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(SYS_PKG);
+        when(mDefaultDialerCache.getSystemDialerComponent()).thenReturn(
+                new ComponentName(SYS_PKG, SYS_CLASS));
+        mEmergencyCallHelper = new EmergencyCallHelper(mMockContext, mDefaultDialerCache,
                 mTimeoutsAdapter);
         when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
         mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
diff --git a/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java b/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java
index 76341b2..8e2d11e 100644
--- a/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/IncomingCallFilterTest.java
@@ -17,17 +17,17 @@
 package com.android.server.telecom.tests;
 
 import android.content.ContentResolver;
-import android.content.IContentProvider;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
-import android.provider.CallLog;
+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;
 
@@ -68,46 +68,47 @@
     private static final long SHORT_TIMEOUT = 100;
 
     private static final CallFilteringResult PASS_CALL_RESULT =
-            new CallFilteringResult(
-                    true, // shouldAllowCall
-                    false, // shouldReject
-                    true, // shouldAddToCallLog
-                    true // shouldShowNotification
-            );
+            new Builder()
+                    .setShouldAllowCall(true)
+                    .setShouldReject(false)
+                    .setShouldAddToCallLog(true)
+                    .setShouldShowNotification(true)
+                    .build();
 
     private static final CallFilteringResult ASYNC_BLOCK_CHECK_BLOCK_RESULT =
-            new CallFilteringResult(
-                    false, // shouldAllowCall
-                    true, // shouldReject
-                    true, // shouldAddToCallLog
-                    false, // shouldShowNotification
-                    CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER, //callBlockReason
-                    null, //callScreeningAppName
-                    null //callScreeningComponentName
-            );
+            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 CallFilteringResult(
-                    false, // shouldAllowCall
-                    true, // shouldReject
-                    true, // shouldAddToCallLog
-                    true, // shouldShowNotification
-                    CallLog.Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL, //callBlockReason
-                    null, //callScreeningAppName
-                    null //callScreeningComponentName
-            );
+            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 CallFilteringResult(
-                    false, // shouldAllowCall
-                    true, // shouldReject
-                    false, // shouldAddToCallLog
-                    true, // shouldShowNotification
-                    CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                    "com.android.thirdparty", //callScreeningAppName
-                    "com.android.thirdparty/com.android.thirdparty.callscreeningserviceimpl"
-                    //callScreeningComponentName
-            );
+            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());
@@ -207,16 +208,15 @@
         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 CallFilteringResult(
-                        false, // shouldAllowCall
-                        true, // shouldReject
-                        false, // shouldAddToCallLog
-                        false, // shouldShowNotification
-                        CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER, //callBlockReason
-                        null, //callScreeningAppName
-                        null //callScreeningComponentName
-                )));
+        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
@@ -239,16 +239,15 @@
         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 CallFilteringResult(
-                        false, // shouldAllowCall
-                        true, // shouldReject
-                        false, // shouldAddToCallLog
-                        true, // shouldShowNotification
-                        CallLog.Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL, //callBlockReason
-                        null, ////callScreeningAppName
-                        null ////callScreeningComponentName
-                )));
+        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
@@ -268,17 +267,16 @@
         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 CallFilteringResult(
-                        false, // shouldAllowCall
-                        true, // shouldReject
-                        false, // shouldAddToCallLog
-                        true, // shouldShowNotification
-                        CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, //callBlockReason
-                        "com.android.thirdparty", //callScreeningAppName
-                        "com.android.thirdparty/com.android.thirdparty.callscreeningserviceimpl"
-                        //callScreeningComponentName
-                )));
+        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
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index 54fc89c..3438802 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -38,7 +38,6 @@
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -54,6 +53,7 @@
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.DefaultDialerCache;
 import com.android.server.telecom.NewOutgoingCallIntentBroadcaster;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneNumberUtilsAdapter;
@@ -89,15 +89,14 @@
     @Mock private PhoneAccount mPhoneAccount;
     @Mock private PhoneAccountRegistrar mPhoneAccountRegistrar;
     @Mock private RoleManagerAdapter mRoleManagerAdapter;
+    @Mock private DefaultDialerCache mDefaultDialerCache;
 
-    private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapterSpy;
+    private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter = new PhoneNumberUtilsAdapterImpl();
 
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
-        mPhoneNumberUtilsAdapterSpy = spy(new PhoneNumberUtilsAdapterImpl());
         when(mCall.getInitiatingUser()).thenReturn(UserHandle.CURRENT);
         when(mCallsManager.getLock()).thenReturn(new TelecomSystem.SyncRoot() { });
         when(mCallsManager.getSystemStateHelper()).thenReturn(mSystemStateHelper);
@@ -217,8 +216,8 @@
     @Test
     public void testEmergencyCallWithNonDefaultDialer() {
         Uri handle = Uri.parse("tel:6505551911");
-        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
-                any(Context.class), eq(handle.getSchemeSpecificPart()));
+        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(eq(handle.getSchemeSpecificPart()));
         Intent intent = new Intent(Intent.ACTION_CALL, handle);
 
         String ui_package_string = "sample_string_1";
@@ -227,6 +226,9 @@
                 ui_package_string);
         mComponentContextFixture.putResource(R.string.dialer_default_class,
                 dialer_default_class_string);
+        when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(ui_package_string);
+        when(mDefaultDialerCache.getSystemDialerComponent()).thenReturn(
+                new ComponentName(ui_package_string, dialer_default_class_string));
 
         int result = processIntent(intent, false).disconnectCause;
 
@@ -285,8 +287,8 @@
     @Test
     public void testActionEmergencyWithNonEmergencyNumber() {
         Uri handle = Uri.parse("tel:6505551911");
-        doReturn(false).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
-                any(Context.class), eq(handle.getSchemeSpecificPart()));
+        doReturn(false).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(eq(handle.getSchemeSpecificPart()));
         Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY, handle);
         int result = processIntent(intent, true).disconnectCause;
 
@@ -299,8 +301,8 @@
         Uri handle = intent.getData();
         int videoState = VideoProfile.STATE_BIDIRECTIONAL;
         boolean isSpeakerphoneOn = true;
-        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
-                any(Context.class), eq(handle.getSchemeSpecificPart()));
+        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(eq(handle.getSchemeSpecificPart()));
         intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, isSpeakerphoneOn);
         intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
 
@@ -421,8 +423,8 @@
         String newEmergencyNumber = "1234567890";
         result.receiver.setResultData(newEmergencyNumber);
 
-        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
-                any(Context.class), eq(newEmergencyNumber));
+        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(eq(newEmergencyNumber));
         result.receiver.onReceive(mContext, result.intent);
         verify(mCall).disconnect(eq(0L));
     }
@@ -458,8 +460,8 @@
     private NewOutgoingCallIntentBroadcaster.CallDisposition processIntent(Intent intent,
             boolean isDefaultPhoneApp) {
         NewOutgoingCallIntentBroadcaster b = new NewOutgoingCallIntentBroadcaster(
-                mContext, mCallsManager, mCall, intent, mPhoneNumberUtilsAdapterSpy,
-                isDefaultPhoneApp);
+                mContext, mCallsManager, mCall, intent, mPhoneNumberUtilsAdapter,
+                isDefaultPhoneApp, mDefaultDialerCache);
         NewOutgoingCallIntentBroadcaster.CallDisposition cd = b.evaluateCall();
         if (cd.disconnectCause == DisconnectCause.NOT_DISCONNECTED) {
             b.processCall(cd);
diff --git a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
index 3f0216f..7104e3a 100644
--- a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
+++ b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
@@ -61,9 +61,10 @@
         when(mCallsManager.getCallerInfoLookupHelper()).thenReturn(mCallerInfoLookupHelper);
         when(mCallsManager.getPhoneAccountRegistrar()).thenReturn(mPhoneAccountRegistrar);
         when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any())).thenReturn(null);
-        when(mPhoneNumberUtilsAdapter.isLocalEmergencyNumber(any(), any())).thenReturn(false);
+        when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
+                .thenReturn(false);
         mCall = new Call("1",
-                null /* context */,
+                mContext /* context */,
                 mCallsManager,
                 mLock,
                 null /* ConnectionServiceRepository */,
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index a978cfd..e9efacd 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -69,6 +69,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -153,6 +154,68 @@
         assertPhoneAccountEquals(input, result);
     }
 
+    @SmallTest
+    @Test
+    public void testFilterPhoneAccountForTest() throws Exception {
+        ComponentName componentA = new ComponentName("a", "a");
+        ComponentName componentB1 = new ComponentName("b", "b1");
+        ComponentName componentB2 = new ComponentName("b", "b2");
+        ComponentName componentC = new ComponentName("c", "c");
+
+        PhoneAccount simAccountA = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentA, "1"), "1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setIsEnabled(true)
+                .build();
+
+        List<PhoneAccount> accountAList = new ArrayList<>();
+        accountAList.add(simAccountA);
+
+        PhoneAccount simAccountB1 = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentB1, "2"), "2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setIsEnabled(true)
+                .build();
+
+        PhoneAccount simAccountB2 = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentB2, "3"), "3")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setIsEnabled(true)
+                .build();
+
+        List<PhoneAccount> accountBList = new ArrayList<>();
+        accountBList.add(simAccountB1);
+        accountBList.add(simAccountB2);
+
+        PhoneAccount simAccountC = new PhoneAccount.Builder(
+                makeQuickAccountHandle(componentC, "4"), "4")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setIsEnabled(true)
+                .build();
+
+        List<PhoneAccount> accountCList = new ArrayList<>();
+        accountCList.add(simAccountC);
+
+        List<PhoneAccount> allAccounts = new ArrayList<>();
+        allAccounts.addAll(accountAList);
+        allAccounts.addAll(accountBList);
+        allAccounts.addAll(accountCList);
+
+        assertEquals(allAccounts, mRegistrar.filterRestrictedPhoneAccounts(allAccounts));
+
+        mRegistrar.setTestPhoneAccountPackageNameFilter(componentA.getPackageName());
+        assertEquals(accountAList, mRegistrar.filterRestrictedPhoneAccounts(allAccounts));
+
+        mRegistrar.setTestPhoneAccountPackageNameFilter(componentB1.getPackageName());
+        assertEquals(accountBList, mRegistrar.filterRestrictedPhoneAccounts(allAccounts));
+
+        mRegistrar.setTestPhoneAccountPackageNameFilter(componentC.getPackageName());
+        assertEquals(accountCList, mRegistrar.filterRestrictedPhoneAccounts(allAccounts));
+
+        mRegistrar.setTestPhoneAccountPackageNameFilter(null);
+        assertEquals(allAccounts, mRegistrar.filterRestrictedPhoneAccounts(allAccounts));
+    }
+
     @MediumTest
     @Test
     public void testDefaultPhoneAccountHandleEmptyGroup() throws Exception {
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 9b89a03..4fc9ed6 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -78,6 +78,7 @@
 import com.android.server.telecom.ClockProxy;
 import com.android.server.telecom.ConnectionServiceFocusManager;
 import com.android.server.telecom.ContactsAsyncHelper;
+import com.android.server.telecom.DefaultDialerCache;
 import com.android.server.telecom.HeadsetMediaButton;
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockController;
@@ -183,18 +184,6 @@
     }
 
     MissedCallNotifierFakeImpl mMissedCallNotifier = new MissedCallNotifierFakeImpl();
-    private class EmergencyNumberUtilsAdapter extends PhoneNumberUtilsAdapterImpl {
-
-        @Override
-        public boolean isLocalEmergencyNumber(Context context, String number) {
-            return mIsEmergencyCall;
-        }
-
-        @Override
-        public boolean isPotentialLocalEmergencyNumber(Context context, String number) {
-            return mIsEmergencyCall;
-        }
-    }
 
     private class IncomingCallAddedListener extends CallsManagerListenerBase {
 
@@ -210,8 +199,6 @@
         }
     }
 
-    PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter = new EmergencyNumberUtilsAdapter();
-
     @Mock HeadsetMediaButton mHeadsetMediaButton;
     @Mock ProximitySensorManager mProximitySensorManager;
     @Mock InCallWakeLockController mInCallWakeLockController;
@@ -344,8 +331,6 @@
 
     private int mNumOutgoingCallsMade;
 
-    private boolean mIsEmergencyCall;
-
     class IdPair {
         final String mConnectionId;
         final String mCallId;
@@ -368,7 +353,10 @@
 
         mNumOutgoingCallsMade = 0;
 
-        mIsEmergencyCall = false;
+        doReturn(false).when(mComponentContextFixture.getTelephonyManager())
+                .isEmergencyNumber(any());
+        doReturn(false).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(any());
 
         // First set up information about the In-Call services in the mock Context, since
         // Telecom will search for these as soon as it is instantiated
@@ -492,7 +480,7 @@
                 mConnServFMFactory,
                 mTimeoutsAdapter,
                 mAsyncRingtonePlayer,
-                mPhoneNumberUtilsAdapter,
+                new PhoneNumberUtilsAdapterImpl(),
                 mIncomingCallNotifier,
                 (streamType, volume) -> mToneGenerator,
                 new CallAudioRouteStateMachine.Factory() {
@@ -712,7 +700,11 @@
         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
 
-        mIsEmergencyCall = true;
+        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+                .isEmergencyNumber(any());
+        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+                .isPotentialEmergencyNumber(any());
+
         // Call will not use the ordered broadcaster, since it is an Emergency Call
         startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle,
                 connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/);