Fix audio routing issue and flaky test

There was a potential issue in CallAudioRouteManager where the
transition from a quiescent state to its corresponding active state
would not be communicated to the in-call service. This has been fixed.

This change also changes InCallController to not broadcast current state
to all bound in-call services when a new service is bound.
VideoCallTests was adjusted to take this into account.

Bug: 26827840
Change-Id: Ibda3e2c783b77d82a7337fa39f4675dac22ae071
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 827c814..b47b02e 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -252,15 +252,14 @@
             setBluetoothOn(false);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE,
                     mAvailableRoutes);
-            setSystemAudioState(mCurrentCallAudioState, newState);
+            setSystemAudioState(newState);
             updateInternalCallAudioState();
         }
 
         @Override
         public void updateSystemAudioState() {
-            CallAudioState oldAudioState = mCurrentCallAudioState;
             updateInternalCallAudioState();
-            setSystemAudioState(oldAudioState, mCurrentCallAudioState);
+            setSystemAudioState(mCurrentCallAudioState);
         }
 
         @Override
@@ -412,15 +411,14 @@
             setBluetoothOn(false);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_WIRED_HEADSET,
                     mAvailableRoutes);
-            setSystemAudioState(mCurrentCallAudioState, newState);
+            setSystemAudioState(newState);
             updateInternalCallAudioState();
         }
 
         @Override
         public void updateSystemAudioState() {
-            CallAudioState oldAudioState = mCurrentCallAudioState;
             updateInternalCallAudioState();
-            setSystemAudioState(oldAudioState, mCurrentCallAudioState);
+            setSystemAudioState(mCurrentCallAudioState);
         }
 
         @Override
@@ -576,15 +574,14 @@
             setBluetoothOn(true);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH,
                     mAvailableRoutes);
-            setSystemAudioState(mCurrentCallAudioState, newState);
+            setSystemAudioState(newState);
             updateInternalCallAudioState();
         }
 
         @Override
         public void updateSystemAudioState() {
-            CallAudioState oldAudioState = mCurrentCallAudioState;
             updateInternalCallAudioState();
-            setSystemAudioState(oldAudioState, mCurrentCallAudioState);
+            setSystemAudioState(mCurrentCallAudioState);
         }
 
         @Override
@@ -737,15 +734,14 @@
             setBluetoothOn(false);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_SPEAKER,
                     mAvailableRoutes);
-            setSystemAudioState(mCurrentCallAudioState, newState);
+            setSystemAudioState(newState);
             updateInternalCallAudioState();
         }
 
         @Override
         public void updateSystemAudioState() {
-            CallAudioState oldAudioState = mCurrentCallAudioState;
             updateInternalCallAudioState();
-            setSystemAudioState(oldAudioState, mCurrentCallAudioState);
+            setSystemAudioState(mCurrentCallAudioState);
         }
 
         @Override
@@ -919,6 +915,7 @@
     // CallAudioState is used as an interface to communicate with many other system components.
     // No internal state transitions should depend on this variable.
     private CallAudioState mCurrentCallAudioState;
+    private CallAudioState mLastKnownCallAudioState;
 
     public CallAudioRouteStateMachine(
             Context context,
@@ -975,6 +972,7 @@
 
     public void initialize(CallAudioState initState) {
         mCurrentCallAudioState = initState;
+        mLastKnownCallAudioState = initState;
         mAvailableRoutes = initState.getSupportedRouteMask();
         mIsMuted = initState.isMuted();
         mWasOnSpeaker = initState.getRoute() == ROUTE_SPEAKER;
@@ -1014,7 +1012,7 @@
                 newCallAudioState = new CallAudioState(mIsMuted,
                         mCurrentCallAudioState.getRoute(),
                         mAvailableRoutes);
-                setSystemAudioState(mCurrentCallAudioState, newCallAudioState);
+                setSystemAudioState(newCallAudioState);
                 updateInternalCallAudioState();
                 return;
             case MUTE_OFF:
@@ -1022,7 +1020,7 @@
                 newCallAudioState = new CallAudioState(mIsMuted,
                         mCurrentCallAudioState.getRoute(),
                         mAvailableRoutes);
-                setSystemAudioState(mCurrentCallAudioState, newCallAudioState);
+                setSystemAudioState(newCallAudioState);
                 updateInternalCallAudioState();
                 return;
             case TOGGLE_MUTE:
@@ -1111,16 +1109,16 @@
         mCurrentCallAudioState = new CallAudioState(mIsMuted, currentRoute, mAvailableRoutes);
     }
 
-    private void setSystemAudioState(CallAudioState oldCallAudioState,
-            CallAudioState newCallAudioState) {
-        Log.i(this, "setSystemAudioState: changing from %s to %s", oldCallAudioState,
+    private void setSystemAudioState(CallAudioState newCallAudioState) {
+        Log.i(this, "setSystemAudioState: changing from %s to %s", mLastKnownCallAudioState,
                 newCallAudioState);
         Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
                 CallAudioState.audioRouteToString(newCallAudioState.getRoute()));
 
-        if (!oldCallAudioState.equals(newCallAudioState)) {
-            mCallsManager.onCallAudioStateChanged(oldCallAudioState, newCallAudioState);
+        if (!newCallAudioState.equals(mLastKnownCallAudioState)) {
+            mCallsManager.onCallAudioStateChanged(mLastKnownCallAudioState, newCallAudioState);
             updateAudioForForegroundCall(newCallAudioState);
+            mLastKnownCallAudioState = newCallAudioState;
         }
     }
 
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 26ff625..3c557c8 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -577,10 +577,11 @@
                 } catch (RemoteException ignored) {
                 }
             }
-            onCallAudioStateChanged(
-                    null,
-                    mCallsManager.getAudioState());
-            onCanAddCallChanged(mCallsManager.canAddCall());
+            try {
+                inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
+                inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
+            } catch (RemoteException ignored) {
+            }
         } else {
             unbindFromServices();
         }
diff --git a/tests/src/com/android/server/telecom/tests/VideoCallTests.java b/tests/src/com/android/server/telecom/tests/VideoCallTests.java
index ab29c5b..2a54034 100644
--- a/tests/src/com/android/server/telecom/tests/VideoCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/VideoCallTests.java
@@ -21,6 +21,8 @@
 import android.telecom.CallAudioState;
 import android.telecom.VideoProfile;
 
+import java.util.List;
+
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -42,7 +44,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_BIDIRECTIONAL);
 
-        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 3);
+        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 2);
     }
 
     /**
@@ -57,7 +59,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_RX_ENABLED);
 
-        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 3);
+        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 2);
     }
 
     /**
@@ -70,7 +72,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_BIDIRECTIONAL);
 
-        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 3);
+        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 2);
     }
 
     /**
@@ -84,7 +86,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_TX_ENABLED);
 
-        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 3);
+        verifyAudioRoute(CallAudioState.ROUTE_SPEAKER, 2);
     }
 
     /**
@@ -98,7 +100,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_AUDIO_ONLY);
 
-        verifyAudioRoute(CallAudioState.ROUTE_EARPIECE, 2);
+        verifyAudioRoute(CallAudioState.ROUTE_EARPIECE, 1);
     }
 
     /**
@@ -111,7 +113,7 @@
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
                 VideoProfile.STATE_AUDIO_ONLY);
 
-        verifyAudioRoute(CallAudioState.ROUTE_EARPIECE, 2);
+        verifyAudioRoute(CallAudioState.ROUTE_EARPIECE, 1);
     }
 
     /**
@@ -123,7 +125,7 @@
      * @param audioStateChangeCount The number of audio state changes expected.  This is set based
      *                              on how many times we expect the audio route to change when
      *                              setting up a call.  For an audio-only call, we normally expect
-     *                              2 route changes, and for a video call we expect an extra change.
+     *                              1 route change, and for a video call we expect an extra change.
      */
     private void verifyAudioRoute(int expectedRoute, int audioStateChangeCount) throws Exception {
         // Capture all onCallAudioStateChanged callbacks to InCall.
@@ -132,8 +134,7 @@
         verify(mInCallServiceFixtureX.getTestDouble(),
                 timeout(TEST_TIMEOUT).times(audioStateChangeCount)).
                 onCallAudioStateChanged(callAudioStateArgumentCaptor.capture());
-        assertEquals(expectedRoute,
-                callAudioStateArgumentCaptor.getAllValues().get(audioStateChangeCount - 1)
-                        .getRoute());
+        List<CallAudioState> changes = callAudioStateArgumentCaptor.getAllValues();
+        assertEquals(expectedRoute, changes.get(changes.size() - 1).getRoute());
     }
 }