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

Commit b8fc769e authored by Joseph Pirozzo's avatar Joseph Pirozzo
Browse files

AVRCP Controller request focus when idle

When no music is playing and an incoming play request comes in from a
paired device, request focus on it's behalf.

Bug: 135112399
Test: atest com.android.bluetooth.avrcpcontroller.AvrcpControllerStateMachineTest
Change-Id: Ia764ea54af95166be6b6c3d9b47f3e3c2d09a0d7
parent c18c577a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -413,7 +413,8 @@ public class A2dpSinkService extends ProfileService {
        if (state == StackEvent.AUDIO_STATE_STARTED) {
            mA2dpSinkStreamHandler.obtainMessage(
                    A2dpSinkStreamHandler.SRC_STR_START).sendToTarget();
        } else if (state == StackEvent.AUDIO_STATE_STOPPED) {
        } else if (state == StackEvent.AUDIO_STATE_STOPPED
                || state == StackEvent.AUDIO_STATE_REMOTE_SUSPEND) {
            mA2dpSinkStreamHandler.obtainMessage(
                    A2dpSinkStreamHandler.SRC_STR_STOP).sendToTarget();
        }
+7 −3
Original line number Diff line number Diff line
@@ -361,11 +361,14 @@ class AvrcpControllerStateMachine extends StateMachine {
                    BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                    if (mAddressedPlayer.getPlaybackState().getState()
                            == PlaybackStateCompat.STATE_PLAYING
                            && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
                            && !shouldRequestFocus()) {
                            && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE) {
                        if (shouldRequestFocus()) {
                            mSessionCallbacks.onPrepare();
                        } else {
                        sendMessage(MSG_AVRCP_PASSTHRU,
                                AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
                        }
                    }
                    return true;

                case MESSAGE_PROCESS_PLAY_POS_CHANGED:
@@ -882,6 +885,7 @@ class AvrcpControllerStateMachine extends StateMachine {

    private boolean shouldRequestFocus() {
        return mService.getResources()
                .getBoolean(R.bool.a2dp_sink_automatically_request_audio_focus);
                .getBoolean(R.bool.a2dp_sink_automatically_request_audio_focus)
                || !mAudioManager.isMusicActive();
    }
}
+54 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.media.AudioManager;
import android.os.Looper;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -34,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;

@@ -66,10 +68,15 @@ public class AvrcpControllerStateMachineTest {
    private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class);
    private byte[] mTestAddress = new byte[]{00, 01, 02, 03, 04, 05};

    @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
    @Rule public final ServiceTestRule mAvrcpServiceRule = new ServiceTestRule();
    @Rule public final ServiceTestRule mA2dpServiceRule = new ServiceTestRule();

    @Mock
    private AdapterService mAdapterService;
    private AdapterService mAvrcpAdapterService;

    @Mock
    private AdapterService mA2dpAdapterService;

    @Mock
    private AudioManager mAudioManager;
    @Mock
@@ -90,8 +97,11 @@ public class AvrcpControllerStateMachineTest {

        // Setup mocks and test assets
        MockitoAnnotations.initMocks(this);
        TestUtils.setAdapterService(mAdapterService);
        TestUtils.startService(mServiceRule, AvrcpControllerService.class);
        TestUtils.setAdapterService(mAvrcpAdapterService);
        TestUtils.startService(mAvrcpServiceRule, AvrcpControllerService.class);
        TestUtils.clearAdapterService(mAvrcpAdapterService);
        TestUtils.setAdapterService(mA2dpAdapterService);
        TestUtils.startService(mA2dpServiceRule, A2dpSinkService.class);
        doReturn(mTargetContext.getResources()).when(mAvrcpControllerService).getResources();
        doReturn(15).when(mAudioManager).getStreamMaxVolume(anyInt());
        doReturn(8).when(mAudioManager).getStreamVolume(anyInt());
@@ -113,7 +123,7 @@ public class AvrcpControllerStateMachineTest {
        if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_avrcp_controller)) {
            return;
        }
        TestUtils.clearAdapterService(mAdapterService);
        TestUtils.clearAdapterService(mA2dpAdapterService);
    }

    /**
@@ -544,6 +554,45 @@ public class AvrcpControllerStateMachineTest {
                .sendRegisterAbsVolRspNative(any(), anyByte(), eq(127), anyInt());
    }

    /**
     * Test playback does not request focus when another app is playing music.
     */
    @Test
    public void testPlaybackWhileMusicPlaying() {
        Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
        doReturn(true).when(mAudioManager).isMusicActive();
        setUpConnectedState(true, true);
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
                PlaybackStateCompat.STATE_PLAYING);
        TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
        verify(mAudioManager, times(1)).isMusicActive();
        verify(mAvrcpControllerService,
                timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).sendPassThroughCommandNative(
                eq(mTestAddress), eq(AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE), eq(KEY_DOWN));
        TestUtils.waitForLooperToFinishScheduledTask(
                A2dpSinkService.getA2dpSinkService().getMainLooper());
        Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
    }

    /**
     * Test playback requests focus while nothing is playing music.
     */
    @Test
    public void testPlaybackWhileIdle() {
        Assert.assertEquals(AudioManager.AUDIOFOCUS_NONE, A2dpSinkService.getFocusState());
        doReturn(false).when(mAudioManager).isMusicActive();
        setUpConnectedState(true, true);
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
                PlaybackStateCompat.STATE_PLAYING);
        TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());
        verify(mAudioManager, times(1)).isMusicActive();
        TestUtils.waitForLooperToFinishScheduledTask(
                A2dpSinkService.getA2dpSinkService().getMainLooper());
        Assert.assertEquals(AudioManager.AUDIOFOCUS_GAIN, A2dpSinkService.getFocusState());
    }

    /**
     * Setup Connected State
     *