Add wired headset media button behavior for two calls
am: e677f01f4f

Change-Id: I82d33522076d7815c9d6e593e6bac998755ee9bf
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 5a87e5c..899a3eb 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -2110,11 +2110,22 @@
         return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED) != null;
     }
 
-    boolean onMediaButton(int type) {
+    @VisibleForTesting
+    public boolean onMediaButton(int type) {
         if (hasAnyCalls()) {
             Call ringingCall = getFirstCallWithState(CallState.RINGING);
             if (HeadsetMediaButton.SHORT_PRESS == type) {
                 if (ringingCall == null) {
+                    Call activeCall = getFirstCallWithState(CallState.ACTIVE);
+                    Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD);
+                    if (activeCall != null && onHoldCall != null) {
+                        // Two calls, short-press -> switch calls
+                        Log.addEvent(onHoldCall, LogUtils.Events.INFO,
+                                "two calls, media btn short press - switch call.");
+                        unholdCall(onHoldCall);
+                        return true;
+                    }
+
                     Call callToHangup = getFirstCallWithState(CallState.RINGING, CallState.DIALING,
                             CallState.PULLING, CallState.ACTIVE, CallState.ON_HOLD);
                     Log.addEvent(callToHangup, LogUtils.Events.INFO,
@@ -2133,6 +2144,16 @@
                             LogUtils.Events.INFO, "media btn long press - reject");
                     ringingCall.reject(false, null);
                 } else {
+                    Call activeCall = getFirstCallWithState(CallState.ACTIVE);
+                    Call onHoldCall = getFirstCallWithState(CallState.ON_HOLD);
+                    if (activeCall != null && onHoldCall != null) {
+                        // Two calls, long-press -> end current call
+                        Log.addEvent(activeCall, LogUtils.Events.INFO,
+                                "two calls, media btn long press - end current call.");
+                        disconnectCall(activeCall);
+                        return true;
+                    }
+
                     Log.addEvent(getForegroundCall(), LogUtils.Events.INFO,
                             "media btn long press - mute");
                     mCallAudioManager.toggleMute();
diff --git a/src/com/android/server/telecom/HeadsetMediaButton.java b/src/com/android/server/telecom/HeadsetMediaButton.java
index ec77289..ad95c34 100644
--- a/src/com/android/server/telecom/HeadsetMediaButton.java
+++ b/src/com/android/server/telecom/HeadsetMediaButton.java
@@ -26,14 +26,18 @@
 import android.telecom.Log;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Static class to handle listening to the headset media buttons.
  */
 public class HeadsetMediaButton extends CallsManagerListenerBase {
 
     // Types of media button presses
-    static final int SHORT_PRESS = 1;
-    static final int LONG_PRESS = 2;
+    @VisibleForTesting
+    public static final int SHORT_PRESS = 1;
+    @VisibleForTesting
+    public static final int LONG_PRESS = 2;
 
     private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 906b73e..86214e9 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.anyChar;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -719,6 +720,106 @@
         verify(incomingCall).setIsUsingCallFiltering(eq(false));
     }
 
+    @SmallTest
+    @Test
+    public void testAcceptIncomingCallWhenHeadsetMediaButtonShortPress() {
+        // GIVEN an incoming call
+        Call incomingCall = addSpyCall();
+        doReturn(CallState.RINGING).when(incomingCall).getState();
+
+        // WHEN media button short press
+        mCallsManager.onMediaButton(HeadsetMediaButton.SHORT_PRESS);
+
+        // THEN the incoming call is answered
+        verify(incomingCall).answer(VideoProfile.STATE_AUDIO_ONLY);
+    }
+
+    @SmallTest
+    @Test
+    public void testRejectIncomingCallWhenHeadsetMediaButtonLongPress() {
+        // GIVEN an incoming call
+        Call incomingCall = addSpyCall();
+        doReturn(CallState.RINGING).when(incomingCall).getState();
+
+        // WHEN media button long press
+        mCallsManager.onMediaButton(HeadsetMediaButton.LONG_PRESS);
+
+        // THEN the incoming call is rejected
+        verify(incomingCall).reject(false, null);
+    }
+
+    @SmallTest
+    @Test
+    public void testHangupOngoingCallWhenHeadsetMediaButtonShortPress() {
+        // GIVEN an ongoing call
+        Call ongoingCall = addSpyCall();
+        doReturn(CallState.ACTIVE).when(ongoingCall).getState();
+
+        // WHEN media button short press
+        mCallsManager.onMediaButton(HeadsetMediaButton.SHORT_PRESS);
+
+        // THEN the active call is disconnected
+        verify(ongoingCall).disconnect();
+    }
+
+    @SmallTest
+    @Test
+    public void testToggleMuteWhenHeadsetMediaButtonLongPressDuringOngoingCall() {
+        // GIVEN an ongoing call
+        Call ongoingCall = addSpyCall();
+        doReturn(CallState.ACTIVE).when(ongoingCall).getState();
+
+        // WHEN media button long press
+        mCallsManager.onMediaButton(HeadsetMediaButton.LONG_PRESS);
+
+        // THEN the microphone toggle mute
+        verify(mCallAudioRouteStateMachine)
+                .sendMessageWithSessionInfo(CallAudioRouteStateMachine.TOGGLE_MUTE);
+    }
+
+    @SmallTest
+    @Test
+    public void testSwapCallsWhenHeadsetMediaButtonShortPressDuringTwoCalls() {
+        // GIVEN an ongoing call, and this call can be held
+        Call ongoingCall = addSpyCall();
+        doReturn(CallState.ACTIVE).when(ongoingCall).getState();
+        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+        when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
+
+        // and a held call
+        Call heldCall = addSpyCall();
+        doReturn(CallState.ON_HOLD).when(heldCall).getState();
+
+        // WHEN media button short press
+        mCallsManager.onMediaButton(HeadsetMediaButton.SHORT_PRESS);
+
+        // THEN the ongoing call is held, and the focus request for heldCall call is sent
+        verify(ongoingCall).hold(nullable(String.class));
+        verifyFocusRequestAndExecuteCallback(heldCall);
+
+        // and held call is unhold now
+        verify(heldCall).unhold(nullable(String.class));
+    }
+
+    @SmallTest
+    @Test
+    public void testHangupActiveCallWhenHeadsetMediaButtonLongPressDuringTwoCalls() {
+        // GIVEN an  ongoing call
+        Call ongoingCall = addSpyCall();
+        doReturn(CallState.ACTIVE).when(ongoingCall).getState();
+
+        // and a held call
+        Call heldCall = addSpyCall();
+        doReturn(CallState.ON_HOLD).when(heldCall).getState();
+
+        // WHEN media button long press
+        mCallsManager.onMediaButton(HeadsetMediaButton.LONG_PRESS);
+
+        // THEN the ongoing call is disconnected
+        verify(ongoingCall).disconnect();
+    }
+
     private Call addSpyCallWithConnectionService(ConnectionServiceWrapper connSvr) {
         Call call = addSpyCall();
         doReturn(connSvr).when(call).getConnectionService();