Merge "Add persistent logging for BT events"
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index bfbd5d23..c01c9aa 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -598,11 +598,19 @@
     }
 
     private void onCallLeavingAudioProcessing() {
-        // TODO: implement
+        if (mAudioProcessingCalls.size() == 0) {
+            mCallAudioModeStateMachine.sendMessageWithArgs(
+                    CallAudioModeStateMachine.NO_MORE_AUDIO_PROCESSING_CALLS,
+                    makeArgsForModeStateMachine());
+        }
     }
 
     private void onCallEnteringAudioProcessing() {
-        // TODO: implement
+        if (mAudioProcessingCalls.size() == 1) {
+            mCallAudioModeStateMachine.sendMessageWithArgs(
+                    CallAudioModeStateMachine.NEW_AUDIO_PROCESSING_CALL,
+                    makeArgsForModeStateMachine());
+        }
     }
 
     private void onCallLeavingActiveDialingOrConnecting() {
@@ -687,6 +695,7 @@
                 .setHasActiveOrDialingCalls(mActiveDialingOrConnectingCalls.size() > 0)
                 .setHasRingingCalls(mRingingCalls.size() > 0)
                 .setHasHoldingCalls(mHoldingCalls.size() > 0)
+                .setHasAudioProcessingCalls(mAudioProcessingCalls.size() > 0)
                 .setIsTonePlaying(mIsTonePlaying)
                 .setForegroundCallIsVoip(
                         mForegroundCall != null && mForegroundCall.getIsVoipAudioMode())
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index 4a7d9fc..06be216 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -28,7 +28,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs.Builder;
 
 public class CallAudioModeStateMachine extends StateMachine {
     public static class Factory {
@@ -42,16 +41,18 @@
         public boolean hasActiveOrDialingCalls;
         public boolean hasRingingCalls;
         public boolean hasHoldingCalls;
+        public boolean hasAudioProcessingCalls;
         public boolean isTonePlaying;
         public boolean foregroundCallIsVoip;
         public Session session;
 
         private MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls,
-                boolean hasHoldingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip,
-                Session session) {
+                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;
@@ -63,6 +64,7 @@
                     "hasActiveCalls=" + hasActiveOrDialingCalls +
                     ", hasRingingCalls=" + hasRingingCalls +
                     ", hasHoldingCalls=" + hasHoldingCalls +
+                    ", hasAudioProcessingCalls=" + hasAudioProcessingCalls +
                     ", isTonePlaying=" + isTonePlaying +
                     ", foregroundCallIsVoip=" + foregroundCallIsVoip +
                     ", session=" + session +
@@ -73,6 +75,7 @@
             private boolean mHasActiveOrDialingCalls;
             private boolean mHasRingingCalls;
             private boolean mHasHoldingCalls;
+            private boolean mHasAudioProcessingCalls;
             private boolean mIsTonePlaying;
             private boolean mForegroundCallIsVoip;
             private Session mSession;
@@ -92,6 +95,11 @@
                 return this;
             }
 
+            public Builder setHasAudioProcessingCalls(boolean hasAudioProcessingCalls) {
+                mHasAudioProcessingCalls = hasAudioProcessingCalls;
+                return this;
+            }
+
             public Builder setIsTonePlaying(boolean isTonePlaying) {
                 mIsTonePlaying = isTonePlaying;
                 return this;
@@ -109,26 +117,32 @@
 
             public MessageArgs build() {
                 return new MessageArgs(mHasActiveOrDialingCalls, mHasRingingCalls, mHasHoldingCalls,
-                        mIsTonePlaying, mForegroundCallIsVoip, mSession);
+                        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;
@@ -143,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");
@@ -161,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();
@@ -181,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;
@@ -202,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);
@@ -226,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);
@@ -234,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"
@@ -291,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.");
@@ -352,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
@@ -365,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:
@@ -389,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);
@@ -421,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
@@ -451,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);
@@ -517,7 +626,7 @@
                     mCallAudioManager.stopCallWaiting();
                     return HANDLED;
                 case TONE_STOPPED_PLAYING:
-                    transitionTo(destinationStateAfterNoMoreActiveCalls(args));
+                    transitionTo(calculateProperStateFromArgs(args));
                 default:
                     return NOT_HANDLED;
             }
@@ -530,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;
@@ -567,13 +677,18 @@
         addState(mRingingFocusState);
         addState(mSimCallFocusState);
         addState(mVoipCallFocusState);
+        addState(mAudioProcessingFocusState);
         addState(mOtherFocusState);
         setInitialState(mUnfocusedState);
         start();
-        sendMessage(INITIALIZE, new Builder().setHasActiveOrDialingCalls(
-                false).setHasRingingCalls(false).setHasHoldingCalls(false).setIsTonePlaying(
-                false).setForegroundCallIsVoip(false).setSession(
-                Log.createSubsession()).build());
+        sendMessage(INITIALIZE, new MessageArgs.Builder()
+                .setHasActiveOrDialingCalls(false)
+                .setHasRingingCalls(false)
+                .setHasHoldingCalls(false)
+                .setIsTonePlaying(false)
+                .setForegroundCallIsVoip(false)
+                .setSession(Log.createSubsession())
+                .build());
     }
 
     public void setCallAudioManager(CallAudioManager callAudioManager) {
@@ -613,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/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/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index d1df29b..3251d7d 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -19,10 +19,12 @@
 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;
@@ -47,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;
@@ -105,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);
@@ -122,6 +126,7 @@
                         .setHasActiveOrDialingCalls(true)
                         .setHasRingingCalls(false)
                         .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
                         .setIsTonePlaying(false)
                         .setForegroundCallIsVoip(false)
                         .setSession(null)
@@ -168,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);
@@ -184,6 +188,7 @@
                         .setHasActiveOrDialingCalls(true)
                         .setHasRingingCalls(false)
                         .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
                         .setIsTonePlaying(false)
                         .setForegroundCallIsVoip(false)
                         .setSession(null)
@@ -204,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(
@@ -221,6 +225,7 @@
                         .setHasActiveOrDialingCalls(true)
                         .setHasRingingCalls(false)
                         .setHasHoldingCalls(false)
+                        .setHasAudioProcessingCalls(false)
                         .setIsTonePlaying(false)
                         .setForegroundCallIsVoip(false)
                         .setSession(null)
@@ -241,12 +246,11 @@
     @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(
@@ -257,6 +261,7 @@
                         .setHasRingingCalls(false)
                         .setHasHoldingCalls(false)
                         .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
                         .setForegroundCallIsVoip(false)
                         .setSession(null)
                         .build();
@@ -286,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);
@@ -363,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/CallAudioModeTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
index a2ddf0f..2047867 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
@@ -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;
     }