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

Commit f3ac5e2b authored by Sandeep Samdaria's avatar Sandeep Samdaria Committed by Gerrit Code Review
Browse files

Merge "Media session should start on audio focus"

parents d9d4b628 42d5b74e
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ public class A2dpSinkStreamHandler extends Handler {
    public void handleMessage(Message message) {
        if (DBG) {
            Log.d(TAG, " process message: " + message.what);
            Log.d(TAG, " audioFocus =  " + mAudioFocus);
            Log.d(TAG, " current audioFocus state =  " + mAudioFocus);
        }
        switch (message.what) {
            case SRC_STR_START:
@@ -183,7 +183,12 @@ public class A2dpSinkStreamHandler extends Handler {
                break;

            case AUDIO_FOCUS_CHANGE:
                mAudioFocus = (int) message.obj;
                final int focusChangeCode = (int) message.obj;
                if (DBG) {
                    Log.d(TAG, "New audioFocus =  " + focusChangeCode
                            + " Previous audio focus = " + mAudioFocus);
                }
                mAudioFocus = focusChangeCode;
                // message.obj is the newly granted audio focus.
                switch (mAudioFocus) {
                    case AudioManager.AUDIOFOCUS_GAIN:
@@ -221,7 +226,7 @@ public class A2dpSinkStreamHandler extends Handler {
                AvrcpControllerService avrcpControllerService =
                        AvrcpControllerService.getAvrcpControllerService();
                if (avrcpControllerService != null) {
                    avrcpControllerService.onAudioFocusStateChanged(mAudioFocus);
                    avrcpControllerService.onAudioFocusStateChanged(focusChangeCode);
                } else {
                    Log.w(TAG, "AVRCP Controller Service not available to send focus events to.");
                }
@@ -259,8 +264,12 @@ public class A2dpSinkStreamHandler extends Handler {
        int focusRequestStatus = mAudioManager.requestAudioFocus(focusRequest);
        // If the request is granted begin streaming immediately and schedule an upgrade.
        if (focusRequestStatus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            startFluorideStreaming();
            mAudioFocus = AudioManager.AUDIOFOCUS_GAIN;
            final Message a2dpSinkStreamHandlerMessage = A2dpSinkStreamHandler.this
                    .obtainMessage(AUDIO_FOCUS_CHANGE, mAudioFocus);
            A2dpSinkStreamHandler.this.sendMessageAtFrontOfQueue(a2dpSinkStreamHandlerMessage);
        } else {
            Log.e(TAG, "Audio focus was not granted:" + focusRequestStatus);
        }
        return focusRequestStatus;
    }
+9 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetoothAvrcpController;
import android.content.AttributionSource;
import android.content.Intent;
import android.media.AudioManager;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.session.PlaybackStateCompat;
import android.sysprop.BluetoothProperties;
@@ -510,13 +511,11 @@ public class AvrcpControllerService extends ProfileService {
            // The first device to connect gets to be the active device
            if (getActiveDevice() == null) {
                setActiveDevice(device);
                BluetoothMediaBrowserService.setActive(true);
            }
        } else {
            stateMachine.disconnect();
            if (device.equals(getActiveDevice())) {
                setActiveDevice(null);
                BluetoothMediaBrowserService.setActive(false);
            }
        }
    }
@@ -585,6 +584,14 @@ public class AvrcpControllerService extends ProfileService {
        // Make sure the active device isn't changed while we're processing the event so play/pause
        // commands get routed to the correct device
        synchronized (mActiveDeviceLock) {
            switch (state) {
                case AudioManager.AUDIOFOCUS_GAIN:
                    BluetoothMediaBrowserService.setActive(true);
                    break;
                case AudioManager.AUDIOFOCUS_LOSS:
                    BluetoothMediaBrowserService.setActive(false);
                    break;
            }
            BluetoothDevice device = getActiveDevice();
            if (device == null) {
                Log.w(TAG, "No active device set, ignore focus change");
+14 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import androidx.media.MediaBrowserServiceCompat;

import com.android.bluetooth.BluetoothPrefs;
import com.android.bluetooth.R;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;
@@ -304,12 +305,24 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
     */
    public static synchronized void setActive(boolean active) {
        if (sBluetoothMediaBrowserService != null) {
            if (DBG) Log.d(TAG, "Setting the session active state to:" + active);
            sBluetoothMediaBrowserService.mSession.setActive(active);
        } else {
            Log.w(TAG, "setActive Unavailable");
        }
    }

    /**
     * Checks if the media session is active or not.
     * @return true if media session is active, false otherwise.
     */
    @VisibleForTesting
    public static synchronized boolean isActive() {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession.isActive();
        }
        return false;
    }
    /**
     * Get Media session for updating state
     */
@@ -371,6 +384,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
            sb.append("\n    playbackState=" + playbackState);
            sb.append("\n    queue=" + queue);
            sb.append("\n    internal_queue=" + sBluetoothMediaBrowserService.mMediaQueue);
            sb.append("\n    session active state=").append(isActive());
        } else {
            Log.w(TAG, "dump Unavailable");
            sb.append(" null");
+3 −3
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ public class TestUtils {
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Assert.assertNull("AdapterService.getAdapterService() must be null before setting another"
                + " AdapterService", AdapterService.getAdapterService());
        Assert.assertNotNull(adapterService);
        Assert.assertNotNull("Adapter service should not be null", adapterService);
        // We cannot mock AdapterService.getAdapterService() with Mockito.
        // Hence we need to use reflection to call a private method to
        // initialize properly the AdapterService.sAdapterService field.
@@ -119,7 +119,7 @@ public class TestUtils {
        Assert.assertSame("AdapterService.getAdapterService() must return the same object as the"
                        + " supplied adapterService in this method", adapterService,
                AdapterService.getAdapterService());
        Assert.assertNotNull(adapterService);
        Assert.assertNotNull("Adapter service should not be null", adapterService);
        Method method =
                AdapterService.class.getDeclaredMethod("clearAdapterService", AdapterService.class);
        method.setAccessible(true);
@@ -142,7 +142,7 @@ public class TestUtils {
    public static <T extends ProfileService> void startService(ServiceTestRule serviceTestRule,
            Class<T> profileServiceClass) throws TimeoutException {
        AdapterService adapterService = AdapterService.getAdapterService();
        Assert.assertNotNull(adapterService);
        Assert.assertNotNull("Adapter service should not be null", adapterService);
        Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object"
                + " before calling this method", MockUtil.isMock(adapterService));
        Intent startIntent =
+40 −8
Original line number Diff line number Diff line
@@ -29,13 +29,19 @@ import android.os.Looper;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ServiceTestRule;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
import com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService;
import com.android.bluetooth.btservice.AdapterService;

import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -59,14 +65,23 @@ public class A2dpSinkStreamHandlerTest {

    @Mock private PackageManager mMockPackageManager;

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

    @Mock
    private AdapterService mAdapterService;

    @Before
    public void setUp() {
    public void setUp() throws Exception{
        mTargetContext = InstrumentationRegistry.getTargetContext();
        MockitoAnnotations.initMocks(this);
        // Mock the looper
        if (Looper.myLooper() == null) {
            Looper.prepare();
        }
        TestUtils.setAdapterService(mAdapterService);
        doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
        TestUtils.startService(mServiceRule, AvrcpControllerService.class);

        mHandlerThread = new HandlerThread("A2dpSinkStreamHandlerTest");
        mHandlerThread.start();
@@ -86,6 +101,13 @@ public class A2dpSinkStreamHandlerTest {
        when(mMockPackageManager.hasSystemFeature(any())).thenReturn(false);

        mStreamHandler = spy(new A2dpSinkStreamHandler(mMockA2dpSink, mMockNativeInterface));
        BluetoothMediaBrowserService.setActive(false);
    }

    @After
    public void tearDown() throws Exception {
        TestUtils.stopService(mServiceRule, AvrcpControllerService.class);
        TestUtils.clearAdapterService(mAdapterService);
    }

    @Test
@@ -97,6 +119,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockNativeInterface, times(0)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(0)).informAudioTrackGain(1.0f);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -108,6 +131,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockNativeInterface, times(0)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(0)).informAudioTrackGain(1.0f);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -115,9 +139,8 @@ public class A2dpSinkStreamHandlerTest {
        // Play was pressed locally, expect streaming to start soon.
        mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SNK_PLAY));
        verify(mMockAudioManager, times(1)).requestAudioFocus(any());
        verify(mMockNativeInterface, times(1)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(1)).informAudioTrackGain(1.0f);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -128,6 +151,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockNativeInterface, times(0)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(0)).informAudioTrackGain(1.0f);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -139,6 +163,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockAudioManager, times(0)).abandonAudioFocus(any());
        verify(mMockNativeInterface, times(0)).informAudioFocusState(0);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -149,6 +174,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockNativeInterface, times(0)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(0)).informAudioTrackGain(1.0f);
        assertThat(mStreamHandler.isPlaying()).isFalse();
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -157,8 +183,7 @@ public class A2dpSinkStreamHandlerTest {
        when(mMockPackageManager.hasSystemFeature(any())).thenReturn(true);
        mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
        verify(mMockAudioManager, times(1)).requestAudioFocus(any());
        verify(mMockNativeInterface, times(1)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(1)).informAudioTrackGain(1.0f);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mStreamHandler.isPlaying()).isTrue();
    }

@@ -180,11 +205,12 @@ public class A2dpSinkStreamHandlerTest {
                mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
                        AudioManager.AUDIOFOCUS_GAIN));
        verify(mMockAudioManager, times(1)).requestAudioFocus(any());
        verify(mMockNativeInterface, times(2)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(2)).informAudioTrackGain(1.0f);
        verify(mMockNativeInterface, times(1)).informAudioFocusState(1);
        verify(mMockNativeInterface, times(1)).informAudioTrackGain(1.0f);

        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mStreamHandler.getFocusState()).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
        assertThat(BluetoothMediaBrowserService.isActive()).isTrue();
    }

    @Test
@@ -199,6 +225,7 @@ public class A2dpSinkStreamHandlerTest {
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mStreamHandler.getFocusState()).isEqualTo(
                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -215,6 +242,7 @@ public class A2dpSinkStreamHandlerTest {
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mStreamHandler.getFocusState()).isEqualTo(
                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
    }

    @Test
@@ -230,6 +258,8 @@ public class A2dpSinkStreamHandlerTest {
        mStreamHandler.handleMessage(
                mStreamHandler.obtainMessage(A2dpSinkStreamHandler.REQUEST_FOCUS, true));
        verify(mMockAudioManager, times(2)).requestAudioFocus(any());
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
    }

    @Test
@@ -241,9 +271,10 @@ public class A2dpSinkStreamHandlerTest {
                mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
                        AudioManager.AUDIOFOCUS_GAIN));
        verify(mMockAudioManager, times(0)).abandonAudioFocus(any());
        verify(mMockNativeInterface, times(2)).informAudioTrackGain(1.0f);
        verify(mMockNativeInterface, times(1)).informAudioTrackGain(1.0f);

        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(BluetoothMediaBrowserService.isActive()).isTrue();
        assertThat(mStreamHandler.getFocusState()).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
    }

@@ -258,6 +289,7 @@ public class A2dpSinkStreamHandlerTest {
        verify(mMockNativeInterface, times(1)).informAudioFocusState(0);

        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(BluetoothMediaBrowserService.isActive()).isFalse();
        assertThat(mStreamHandler.getFocusState()).isEqualTo(AudioManager.AUDIOFOCUS_NONE);
        assertThat(mStreamHandler.isPlaying()).isFalse();
    }
Loading