Include Bluetooth in baseline route calculations

Include Bluetooth in baseline route calculations to handle the scenario
where a wired headset is connected-and-disconnected while a call is on
bluetooth.

Change-Id: Ia4e4f499f1eef74e9f67c5c06e21e04befa9adfd
Fixes: 62391035
Test: ran unit tests
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 6a91b18..ee5478f 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -406,7 +406,8 @@
                 return;
             case CallAudioState.ROUTE_WIRED_OR_EARPIECE:
                 mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
-                        CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE);
+                        CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE,
+                        CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE);
                 return;
             default:
                 Log.wtf(this, "Invalid route specified: %d", route);
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 8663066..0585377 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -119,6 +119,10 @@
     public static final int ACTIVE_FOCUS = 2;
     public static final int RINGING_FOCUS = 3;
 
+    /** Valid values for the argument for SWITCH_BASELINE_ROUTE */
+    public static final int NO_INCLUDE_BLUETOOTH_IN_BASELINE = 0;
+    public static final int INCLUDE_BLUETOOTH_IN_BASELINE = 1;
+
     private static final SparseArray<String> AUDIO_ROUTE_TO_LOG_EVENT = new SparseArray<String>() {{
         put(CallAudioState.ROUTE_BLUETOOTH, LogUtils.Events.AUDIO_ROUTE_BT);
         put(CallAudioState.ROUTE_EARPIECE, LogUtils.Events.AUDIO_ROUTE_EARPIECE);
@@ -273,10 +277,12 @@
                     removedRoutes |= ROUTE_BLUETOOTH;
                     break;
                 case SWITCH_BASELINE_ROUTE:
-                    sendInternalMessage(calculateBaselineRouteMessage(false));
+                    sendInternalMessage(calculateBaselineRouteMessage(false,
+                            msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
                     return HANDLED;
                 case USER_SWITCH_BASELINE_ROUTE:
-                    sendInternalMessage(calculateBaselineRouteMessage(true));
+                    sendInternalMessage(calculateBaselineRouteMessage(true,
+                            msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
                     return HANDLED;
                 case SWITCH_FOCUS:
                     mAudioFocusType = msg.arg1;
@@ -654,7 +660,7 @@
                     if (mWasOnSpeaker) {
                         sendInternalMessage(SWITCH_SPEAKER);
                     } else {
-                        sendInternalMessage(SWITCH_BASELINE_ROUTE);
+                        sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
                     }
                     return HANDLED;
                 case BT_AUDIO_DISCONNECT:
@@ -744,7 +750,7 @@
                     }
                     return HANDLED;
                 case BT_AUDIO_DISCONNECT:
-                    sendInternalMessage(SWITCH_BASELINE_ROUTE);
+                    sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
                     return HANDLED;
                 default:
                     return NOT_HANDLED;
@@ -825,7 +831,7 @@
                     return HANDLED;
                 case BT_AUDIO_DISCONNECT:
                     // BT SCO might be connected when in-band ringing is enabled
-                    sendInternalMessage(SWITCH_BASELINE_ROUTE);
+                    sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
                     return HANDLED;
                 default:
                     return NOT_HANDLED;
@@ -920,7 +926,7 @@
                     // in the bluetooth route.
                     return HANDLED;
                 case DISCONNECT_BLUETOOTH:
-                    sendInternalMessage(SWITCH_BASELINE_ROUTE);
+                    sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
                     mWasOnSpeaker = false;
                     return HANDLED;
                 case DISCONNECT_WIRED_HEADSET:
@@ -1124,7 +1130,7 @@
                     // Nothing to do here
                     return HANDLED;
                 case DISCONNECT_DOCK:
-                    sendInternalMessage(SWITCH_BASELINE_ROUTE);
+                    sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
                     return HANDLED;
                default:
                     return NOT_HANDLED;
@@ -1486,6 +1492,10 @@
     }
 
     private void sendInternalMessage(int messageCode) {
+        sendInternalMessage(messageCode, 0);
+    }
+
+    private void sendInternalMessage(int messageCode, int arg1) {
         // Internal messages are messages which the state machine sends to itself in the
         // course of processing externally-sourced messages. We want to send these messages at
         // the front of the queue in order to make actions appear atomic to the user and to
@@ -1500,9 +1510,9 @@
         // 7. State machine handler processes SWITCH_HEADSET.
         Session subsession = Log.createSubsession();
         if(subsession != null) {
-            sendMessageAtFrontOfQueue(messageCode, subsession);
+            sendMessageAtFrontOfQueue(messageCode, arg1, 0, subsession);
         } else {
-            sendMessageAtFrontOfQueue(messageCode);
+            sendMessageAtFrontOfQueue(messageCode, arg1);
         }
     }
 
@@ -1555,7 +1565,8 @@
         return true;
     }
 
-    private int calculateBaselineRouteMessage(boolean isExplicitUserRequest) {
+    private int calculateBaselineRouteMessage(boolean isExplicitUserRequest,
+            boolean includeBluetooth) {
         boolean isSkipEarpiece = false;
         if (!isExplicitUserRequest) {
             synchronized (mLock) {
@@ -1564,7 +1575,11 @@
                 isSkipEarpiece = mCallsManager.hasVideoCall();
             }
         }
-        if ((mAvailableRoutes & ROUTE_EARPIECE) != 0 && !isSkipEarpiece) {
+        if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0
+                && !mHasUserExplicitlyLeftBluetooth
+                && includeBluetooth) {
+            return isExplicitUserRequest ? USER_SWITCH_BLUETOOTH : SWITCH_BLUETOOTH;
+        } else if ((mAvailableRoutes & ROUTE_EARPIECE) != 0 && !isSkipEarpiece) {
             return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE;
         } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
             return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET;
@@ -1592,7 +1607,7 @@
 
         // Move to baseline route in the case the current route is no longer available.
         if ((mAvailableRoutes & currentState.getRoute()) == 0) {
-            sendInternalMessage(calculateBaselineRouteMessage(false));
+            sendInternalMessage(calculateBaselineRouteMessage(false, true));
         }
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 95d6d51..8d5184d 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -516,7 +516,7 @@
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
-                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
                 NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
                 true, // isNotificationChangeExpected