Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0c6caba authored by Jack He's avatar Jack He
Browse files

Bluetooth: Enable in-band ringing in vibration mode (4/4)

* Add RINGER_MODE_CHANGE message in CallAudioModeStateMachine to re-try
  startRinging() in RingingFocus state
* When HFP is connected, CallAudioRouteStateMachine will notify
  CallAudioModeStateMachine about new established SCO connection.
  CallAudioModeStateMachine will try to start playing ringtone at such
  event in case ringtone volume condition changes
* Added and adjusted unit tests in CallAudioRouteStateMachineTest,
  CallAudioModeStateMachineTest and CallAudioRouteTransitionTests

Bug: 72647074
Test: Call phone in vibration mode and hear ringtone on HFP enabled
      headset, verify that ringtone is only played through headset.
      Then disconnect headset and call again to verify that ringtone
      does not play through phone speaker in vibration mode.
      Telecom unit tests: lite_test_telecom

Change-Id: Ie00059213292005c3e3af0c771c148ec0dc22498
(cherry picked from commit fff818b3cd1f8ba91a5037bcb91b5478a5663a25)
parent e574daa1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ public class CallAudioManager extends CallsManagerListenerBase {

        mPlayerFactory.setCallAudioManager(this);
        mCallAudioModeStateMachine.setCallAudioManager(this);
        mCallAudioRouteStateMachine.setCallAudioManager(this);
    }

    @Override
@@ -385,6 +386,11 @@ public class CallAudioManager extends CallsManagerListenerBase {
                CallAudioRouteStateMachine.TOGGLE_MUTE);
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void onRingerModeChange() {
        mCallAudioModeStateMachine.sendMessage(CallAudioModeStateMachine.RINGER_MODE_CHANGE);
    }

    @VisibleForTesting
    public void mute(boolean shouldMute) {
        Log.v(this, "mute, shouldMute: %b", shouldMute);
+17 −5
Original line number Diff line number Diff line
@@ -87,6 +87,8 @@ public class CallAudioModeStateMachine extends StateMachine {

    public static final int FOREGROUND_VOIP_MODE_CHANGE = 4001;

    public static final int RINGER_MODE_CHANGE = 5001;

    public static final int RUN_RUNNABLE = 9001;

    private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
@@ -105,6 +107,7 @@ public class CallAudioModeStateMachine extends StateMachine {
        put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING");
        put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
        put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
        put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE");

        put(RUN_RUNNABLE, "RUN_RUNNABLE");
    }};
@@ -202,18 +205,22 @@ public class CallAudioModeStateMachine extends StateMachine {
    }

    private class RingingFocusState extends BaseState {
        @Override
        public void enter() {
            Log.i(LOG_TAG, "Audio focus entering RINGING state");
        private void tryStartRinging() {
            if (mCallAudioManager.startRinging()) {
                mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
                mAudioManager.setMode(AudioManager.MODE_RINGTONE);
                mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.RINGING_FOCUS);
                mCallAudioManager.setCallAudioRouteFocusState(
                        CallAudioRouteStateMachine.RINGING_FOCUS);
            } else {
                Log.i(LOG_TAG, "Entering RINGING but not acquiring focus -- silent ringtone");
                Log.i(LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
            }
        }

        @Override
        public void enter() {
            Log.i(LOG_TAG, "Audio focus entering RINGING state");
            tryStartRinging();
            mCallAudioManager.stopCallWaiting();
        }

@@ -275,6 +282,11 @@ public class CallAudioModeStateMachine extends StateMachine {
                    transitionTo(args.foregroundCallIsVoip
                            ? mVoipCallFocusState : mSimCallFocusState);
                    return HANDLED;
                case RINGER_MODE_CHANGE: {
                    Log.i(LOG_TAG, "RINGING state, received RINGER_MODE_CHANGE");
                    tryStartRinging();
                    return HANDLED;
                }
                default:
                    // The forced focus switch commands are handled by BaseState.
                    return NOT_HANDLED;
+13 −1
Original line number Diff line number Diff line
@@ -745,6 +745,10 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    mBluetoothRouteManager.getConnectedDevices());
            setSystemAudioState(newState, true);
            updateInternalCallAudioState();
            // Do not send RINGER_MODE_CHANGE if no Bluetooth SCO audio device is available
            if (mBluetoothRouteManager.getBluetoothAudioConnectedDevice() != null) {
                mCallAudioManager.onRingerModeChange();
            }
        }

        @Override
@@ -770,7 +774,9 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    }
                    return HANDLED;
                case BT_AUDIO_CONNECTED:
                    // Nothing to do
                    // Send ringer mode change because we transit to ActiveBluetoothState even
                    // when HFP is connecting
                    mCallAudioManager.onRingerModeChange();
                    return HANDLED;
                case SWITCH_BLUETOOTH:
                case USER_SWITCH_BLUETOOTH:
@@ -1276,6 +1282,8 @@ public class CallAudioRouteStateMachine extends StateMachine {
    private CallAudioState mCurrentCallAudioState;
    private CallAudioState mLastKnownCallAudioState;

    private CallAudioManager mCallAudioManager;

    public CallAudioRouteStateMachine(
            Context context,
            CallsManager callsManager,
@@ -1332,6 +1340,10 @@ public class CallAudioRouteStateMachine extends StateMachine {
        mRouteCodeToQuiescentState.put(ROUTE_WIRED_HEADSET, mQuiescentHeadsetRoute);
    }

    public void setCallAudioManager(CallAudioManager callAudioManager) {
        mCallAudioManager = callAudioManager;
    }

    /**
     * Initializes the state machine with info on initial audio route, supported audio routes,
     * and mute status.
+46 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.test.suitebuilder.annotation.SmallTest;

import com.android.server.telecom.CallAudioManager;
import com.android.server.telecom.CallAudioModeStateMachine;
import com.android.server.telecom.CallAudioRouteStateMachine;

import org.junit.Before;
import org.junit.Test;
@@ -80,6 +81,51 @@ public class CallAudioModeStateMachineTest extends TelecomTestCase {
        verify(mCallAudioManager).stopCallWaiting();
    }

    @SmallTest
    @Test
    public void testRegainFocusWhenHfpIsConnectedSilenced() throws Throwable {
        CallAudioModeStateMachine sm = new CallAudioModeStateMachine(mAudioManager);
        sm.setCallAudioManager(mCallAudioManager);
        sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);

        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
                ));
        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);

        assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());

        verify(mAudioManager, never()).requestAudioFocusForCall(anyInt(), anyInt());
        verify(mAudioManager, never()).setMode(anyInt());

        verify(mCallAudioManager, never()).stopRinging();

        verify(mCallAudioManager).stopCallWaiting();

        when(mCallAudioManager.startRinging()).thenReturn(true);

        sm.sendMessage(CallAudioModeStateMachine.RINGER_MODE_CHANGE);
        waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);

        verify(mCallAudioManager).startRinging();
        verify(mAudioManager).requestAudioFocusForCall(AudioManager.STREAM_RING,
                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
        verify(mAudioManager).setMode(AudioManager.MODE_RINGTONE);
        verify(mCallAudioManager).setCallAudioRouteFocusState(
                CallAudioRouteStateMachine.RINGING_FOCUS);
    }


    private void resetMocks() {
        reset(mCallAudioManager, mAudioManager);
    }
+12 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
    @Mock WiredHeadsetManager mockWiredHeadsetManager;
    @Mock StatusBarNotifier mockStatusBarNotifier;
    @Mock Call fakeCall;
    @Mock CallAudioManager mockCallAudioManager;

    private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
    private static final int TEST_TIMEOUT = 500;
@@ -187,6 +188,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
        stateMachine.setCallAudioManager(mockCallAudioManager);

        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
@@ -229,6 +231,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
        stateMachine.setCallAudioManager(mockCallAudioManager);
        Collection<BluetoothDevice> availableDevices = Collections.singleton(bluetoothDevice1);

        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
@@ -301,6 +304,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
        stateMachine.setCallAudioManager(mockCallAudioManager);

        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
@@ -335,6 +339,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
        stateMachine.setCallAudioManager(mockCallAudioManager);
        setInBandRing(false);
        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(false);
@@ -368,6 +373,12 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                CallAudioRouteStateMachine.ACTIVE_FOCUS);
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        verify(mockBluetoothRouteManager, times(1)).connectBluetoothAudio(null);

        when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice())
                .thenReturn(bluetoothDevice1);
        stateMachine.sendMessage(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        verify(mockCallAudioManager, times(1)).onRingerModeChange();
    }

    @SmallTest
@@ -381,6 +392,7 @@ public class CallAudioRouteStateMachineTest extends TelecomSystemTest {
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
        stateMachine.setCallAudioManager(mockCallAudioManager);
        List<BluetoothDevice> availableDevices =
                Arrays.asList(bluetoothDevice1, bluetoothDevice2, bluetoothDevice3);

Loading