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
(cherry picked from commit e6ff50d6328dca536acd131d91c109072febd70f)
Merged-In: Ia764ea54af95166be6b6c3d9b47f3e3c2d09a0d7
Change-Id: I16d132e6fc90c1bb0f21d05de3ddf877ff5ea5b4
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
index e41def0..5271cc7 100644
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
@@ -413,7 +413,8 @@
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();
}
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 83ba850..23f1ce7 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -361,10 +361,13 @@
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;
@@ -882,6 +885,7 @@
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();
}
}
diff --git a/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java b/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
index 4c77e0a..c766c7c 100644
--- a/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java
@@ -26,6 +26,7 @@
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 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 @@
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 @@
// 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 @@
if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_avrcp_controller)) {
return;
}
- TestUtils.clearAdapterService(mAdapterService);
+ TestUtils.clearAdapterService(mA2dpAdapterService);
}
/**
@@ -545,6 +555,45 @@
}
/**
+ * 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
*
* @return number of times mAvrcpControllerService.sendBroadcastAsUser() has been invoked