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

Commit 2dedcbe3 authored by Ted Wang's avatar Ted Wang Committed by Myles Watson
Browse files

Store volume when the active device is set to null

Store volume device when setting active device to null and move AVRCP
volume memory code into removeActiveDevice.
Add method in ServiceFactory to get AvrcpTargetSercie for unit test to
mock AvrcpTargetService.

Bug: 128471448
Bug: 124818780
Test: runtest bluetooth
Change-Id: Icf5d5f00c04436038cf0790a0f7bfd81cb62a451
parent 0c67c076
Loading
Loading
Loading
Loading
+25 −23
Original line number Diff line number Diff line
@@ -34,10 +34,10 @@ import android.util.StatsLog;

import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.Utils;
import com.android.bluetooth.avrcp.AvrcpTargetService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

@@ -62,6 +62,8 @@ public class A2dpService extends ProfileService {

    @VisibleForTesting
    A2dpNativeInterface mA2dpNativeInterface;
    @VisibleForTesting
    ServiceFactory mFactory = new ServiceFactory();
    private AudioManager mAudioManager;
    private A2dpCodecConfig mA2dpCodecConfig;

@@ -156,11 +158,6 @@ public class A2dpService extends ProfileService {
            return true;
        }

        // Step 10: Store volume if there is an active device
        if (mActiveDevice != null && AvrcpTargetService.get() != null) {
            AvrcpTargetService.get().storeVolumeForDevice(mActiveDevice);
        }

        // Step 9: Clear active device and stop playing audio
        removeActiveDevice(true);

@@ -436,9 +433,19 @@ public class A2dpService extends ProfileService {
        }
    }

    private void storeActiveDeviceVolume() {
        // Make sure volume has been stored before been removed from active.
        if (mFactory.getAvrcpTargetService() != null && mActiveDevice != null) {
            mFactory.getAvrcpTargetService().storeVolumeForDevice(mActiveDevice);
        }
    }

    private void removeActiveDevice(boolean forceStopPlayingAudio) {
        BluetoothDevice previousActiveDevice = mActiveDevice;
        synchronized (mStateMachines) {
            // Make sure volume has been store before device been remove from active.
            storeActiveDeviceVolume();

            // This needs to happen before we inform the audio manager that the device
            // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why.
            updateAndBroadcastActiveDevice(null);
@@ -480,9 +487,6 @@ public class A2dpService extends ProfileService {
            Log.d(TAG, "setSilenceMode(" + device + "): " + silence);
        }
        if (silence && Objects.equals(mActiveDevice, device)) {
            if (mActiveDevice != null && AvrcpTargetService.get() != null) {
                AvrcpTargetService.get().storeVolumeForDevice(mActiveDevice);
            }
            removeActiveDevice(true);
        } else if (!silence && mActiveDevice == null) {
            // Set the device as the active device if currently no active device.
@@ -503,13 +507,11 @@ public class A2dpService extends ProfileService {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");

        synchronized (mStateMachines) {
            if ((mActiveDevice != null) && (AvrcpTargetService.get() != null)) {
            // Switch active device from A2DP to Hearing Aids.
            if (DBG) {
                Log.d(TAG, "earlyNotifyHearingAidActive: Save volume for " + mActiveDevice);
            }
                AvrcpTargetService.get().storeVolumeForDevice(mActiveDevice);
            }
            storeActiveDeviceVolume();
        }
    }

@@ -552,12 +554,12 @@ public class A2dpService extends ProfileService {
            codecStatus = sm.getCodecStatus();

            boolean deviceChanged = !Objects.equals(device, mActiveDevice);
            if ((AvrcpTargetService.get() != null) && (mActiveDevice != null) && deviceChanged) {
            if (deviceChanged) {
                // Switch from one A2DP to another A2DP device
                if (DBG) {
                    Log.d(TAG, "Switch A2DP devices to " + device + " from " + mActiveDevice);
                }
                AvrcpTargetService.get().storeVolumeForDevice(mActiveDevice);
                storeActiveDeviceVolume();
            }

            // This needs to happen before we inform the audio manager that the device
@@ -584,8 +586,8 @@ public class A2dpService extends ProfileService {
                }

                int rememberedVolume = -1;
                if (AvrcpTargetService.get() != null) {
                    rememberedVolume = AvrcpTargetService.get()
                if (mFactory.getAvrcpTargetService() != null) {
                    rememberedVolume = mFactory.getAvrcpTargetService()
                            .getRememberedVolumeForDevice(mActiveDevice);
                }

@@ -649,8 +651,8 @@ public class A2dpService extends ProfileService {
    public void setAvrcpAbsoluteVolume(int volume) {
        // TODO (apanicke): Instead of using A2DP as a middleman for volume changes, add a binder
        // service to the new AVRCP Profile and have the audio manager use that instead.
        if (AvrcpTargetService.get() != null) {
            AvrcpTargetService.get().sendVolumeChanged(volume);
        if (mFactory.getAvrcpTargetService() != null) {
            mFactory.getAvrcpTargetService().sendVolumeChanged(volume);
            return;
        }
    }
@@ -929,8 +931,8 @@ public class A2dpService extends ProfileService {
        }

        synchronized (mStateMachines) {
            if (AvrcpTargetService.get() != null) {
                AvrcpTargetService.get().volumeDeviceSwitched(device);
            if (mFactory.getAvrcpTargetService() != null) {
                mFactory.getAvrcpTargetService().volumeDeviceSwitched(device);
            }

            mActiveDevice = device;
+5 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.bluetooth.btservice;

import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.avrcp.AvrcpTargetService;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.hid.HidDeviceService;
@@ -48,4 +49,8 @@ public class ServiceFactory {
    public HearingAidService getHearingAidService() {
        return HearingAidService.getHearingAidService();
    }

    public AvrcpTargetService getAvrcpTargetService() {
        return AvrcpTargetService.get();
    }
}
+34 −0
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ import android.support.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.avrcp.AvrcpTargetService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;

import org.junit.After;
@@ -75,6 +77,8 @@ public class A2dpServiceTest {
    @Mock private AdapterService mAdapterService;
    @Mock private A2dpNativeInterface mA2dpNativeInterface;
    @Mock private DatabaseManager mDatabaseManager;
    @Mock private AvrcpTargetService mAvrcpTargetService;
    @Mock private ServiceFactory mFactory;

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

@@ -93,11 +97,13 @@ public class A2dpServiceTest {
        TestUtils.setAdapterService(mAdapterService);
        doReturn(MAX_CONNECTED_AUDIO_DEVICES).when(mAdapterService).getMaxConnectedAudioDevices();
        doReturn(false).when(mAdapterService).isQuietModeEnabled();
        doReturn(mAvrcpTargetService).when(mFactory).getAvrcpTargetService();

        mAdapter = BluetoothAdapter.getDefaultAdapter();

        startService();
        mA2dpService.mA2dpNativeInterface = mA2dpNativeInterface;
        mA2dpService.mFactory = mFactory;

        // Override the timeout value to speed up the test
        A2dpStateMachine.sConnectTimeoutMs = TIMEOUT_MS;    // 1s
@@ -245,6 +251,8 @@ public class A2dpServiceTest {
        });
        // Verify that setActiveDevice(null) was called during shutdown
        verify(mA2dpNativeInterface).setActiveDevice(null);
        // Verify that storeVolumeForDevice(mTestDevice) was called during shutdown
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        // Try to restart the service. Note: must be done on the main thread.
        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
            public void run() {
@@ -787,11 +795,13 @@ public class A2dpServiceTest {
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());
        Assert.assertTrue(mA2dpService.setSilenceMode(mTestDevice, true));
        verify(mA2dpNativeInterface).setSilenceDevice(mTestDevice, true);
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        Assert.assertNull(mA2dpService.getActiveDevice());

        // Test whether active device been resumeed after disable silence mode.
        Assert.assertTrue(mA2dpService.setSilenceMode(mTestDevice, false));
        verify(mA2dpNativeInterface).setSilenceDevice(mTestDevice, false);
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());

        // Test that active device should not be changed when silence a non-active device
@@ -799,11 +809,13 @@ public class A2dpServiceTest {
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());
        Assert.assertTrue(mA2dpService.setSilenceMode(otherDevice, true));
        verify(mA2dpNativeInterface).setSilenceDevice(otherDevice, true);
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());

        // Test that active device should not be changed when another device exits silence mode
        Assert.assertTrue(mA2dpService.setSilenceMode(otherDevice, false));
        verify(mA2dpNativeInterface).setSilenceDevice(otherDevice, false);
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());
    }

@@ -893,6 +905,28 @@ public class A2dpServiceTest {
                verifySupportTime, verifyNotSupportTime, verifyEnabledTime);
    }

    /**
     * Test that volume level of previous active device will be stored after set active device.
     */
    @Test
    public void testStoreVolumeAfterSetActiveDevice() {
        BluetoothDevice otherDevice = mAdapter.getRemoteDevice("05:04:03:02:01:00");
        connectDevice(otherDevice);
        connectDevice(mTestDevice);
        doReturn(true).when(mA2dpNativeInterface).setActiveDevice(any(BluetoothDevice.class));
        doReturn(true).when(mA2dpNativeInterface).setActiveDevice(null);
        Assert.assertTrue(mA2dpService.setActiveDevice(mTestDevice));

        // Test volume stored for previous active device an adjust for current active device
        Assert.assertTrue(mA2dpService.setActiveDevice(otherDevice));
        verify(mAvrcpTargetService).storeVolumeForDevice(mTestDevice);
        verify(mAvrcpTargetService).getRememberedVolumeForDevice(otherDevice);

        // Test volume store for previous active device when set active device to null
        Assert.assertTrue(mA2dpService.setActiveDevice(null));
        verify(mAvrcpTargetService).storeVolumeForDevice(otherDevice);
    }

    private void connectDevice(BluetoothDevice device) {
        connectDeviceWithCodecStatus(device, null);
    }