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

Commit f44cca8c authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add methods to send preferred audio profile changes to the audio framework" am: 9afe04d2

parents 011e8754 9afe04d2
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus;
import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
@@ -45,6 +46,7 @@ import android.media.AudioManager;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.HandlerThread;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -1654,4 +1656,25 @@ public class A2dpService extends ProfileService {
        mA2dpCodecConfig.switchCodecByBufferSize(
                device, isLowLatency, getCodecStatus(device).getCodecConfig().getCodecType());
    }

    /**
     * Sends the preferred audio profile change requested from a call to
     * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio
     * framework to apply the change. The audio framework will call
     * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the
     * change is successfully applied.
     *
     * @return the number of requests sent to the audio framework
     */
    public int sendPreferredAudioProfileChangeToAudioFramework() {
        synchronized (mStateMachines) {
            if (mActiveDevice == null) {
                Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device");
                return 0;
            }
            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveDevice, mActiveDevice,
                    BluetoothProfileConnectionInfo.createA2dpInfo(false, -1));
            return 1;
        }
    }
}
+40 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;

import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothLeAudioCodecConfig;
@@ -2823,6 +2824,45 @@ public class LeAudioService extends ProfileService {
        return getConnectedGroupLeadDevice(groupId);
    }

    /**
     * Sends the preferred audio profile change requested from a call to
     * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio
     * framework to apply the change. The audio framework will call
     * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the
     * change is successfully applied.
     *
     * @return the number of requests sent to the audio framework
     */
    public int sendPreferredAudioProfileChangeToAudioFramework() {
        if (mActiveAudioOutDevice == null && mActiveAudioInDevice == null) {
            Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device");
            return 0;
        }

        int audioFrameworkCalls = 0;

        if (mActiveAudioOutDevice != null) {
            int volume = getAudioDeviceGroupVolume(getGroupId(mActiveAudioOutDevice));
            final boolean suppressNoisyIntent = mActiveAudioOutDevice != null;
            Log.i(TAG, "Sending LE Audio Output active device changed for preferred profile "
                    + "change with volume=" + volume + " and suppressNoisyIntent="
                    + suppressNoisyIntent);
            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice,
                    mActiveAudioOutDevice, getLeAudioOutputProfile(suppressNoisyIntent, volume));
            audioFrameworkCalls++;
        }

        if (mActiveAudioInDevice != null) {
            Log.i(TAG, "Sending LE Audio Input active device changed for audio profile change");
            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice,
                    mActiveAudioInDevice, BluetoothProfileConnectionInfo.createLeAudioInfo(false,
                            false));
            audioFrameworkCalls++;
        }

        return audioFrameworkCalls;
    }

    /**
     * Binder object: must be a static class or memory leak may occur
     */
+20 −0
Original line number Diff line number Diff line
@@ -931,6 +931,26 @@ public class A2dpServiceTest {
                verifySupportTime, verifyNotSupportTime, verifyEnabledTime);
    }

    /**
     * Tests that {@link A2dpService#sendPreferredAudioProfileChangeToAudioFramework()} sends
     * requests to the audio framework when there is an active A2DP device.
     */
    @Test
    public void testSendPreferredAudioProfileChangeToAudioFramework() {
        doReturn(true).when(mA2dpNativeInterface).setActiveDevice(any(BluetoothDevice.class));
        Assert.assertTrue(mA2dpService.removeActiveDevice(true));
        Assert.assertNull(mA2dpService.getActiveDevice());

        // Send 0 requests when the active device is null
        Assert.assertEquals(0, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework());

        // Send 1 request when there is an A2DP active device
        connectDevice(mTestDevice);
        Assert.assertTrue(mA2dpService.setActiveDevice(mTestDevice));
        Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice());
        Assert.assertEquals(1, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework());
    }

    @Test
    public void testDumpDoesNotCrash() {
        mA2dpService.dump(new StringBuilder());
+62 −0
Original line number Diff line number Diff line
@@ -1780,4 +1780,66 @@ public class LeAudioServiceTest {
        assertThat(secondGroupDevicesById.contains(mRightDevice)).isFalse();
        assertThat(secondGroupDevicesById.equals(secondGroupDevicesByDevice)).isTrue();
    }

    /**
     * Tests that {@link LeAudioService#sendPreferredAudioProfileChangeToAudioFramework()} sends
     * requests to the audio framework for each active LEA device.
     */
    @Test
    public void testSendPreferredAudioProfileChangeToAudioFramework() {
        when(mAdapterService.isAllSupportedClassicAudioProfilesActive(any())).thenReturn(true);

        // TEST 1: Verify no requests are sent to the audio framework if there is no active device
        assertThat(mService.removeActiveDevice(false)).isTrue();
        List<BluetoothDevice> activeDevices = mService.getActiveDevices();
        assertThat(activeDevices.get(0)).isNull();
        assertThat(activeDevices.get(1)).isNull();
        assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(0);

        // TEST 2: Verify we send one request for each active direction
        int groupId = 1;
        /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 | AUDIO_DIRECTION_INPUT_BIT = 0x02; */
        int direction = 3;
        int snkAudioLocation = 3;
        int srcAudioLocation = 4;
        int availableContexts = 5;
        int nodeStatus = LeAudioStackEvent.GROUP_NODE_ADDED;
        int groupStatus = LeAudioStackEvent.GROUP_STATUS_ACTIVE;

        // Single active device
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        connectTestDevice(mSingleDevice, testGroupId);

        // Add device to group
        LeAudioStackEvent nodeStatusChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED);
        nodeStatusChangedEvent.device = mSingleDevice;
        nodeStatusChangedEvent.valueInt1 = groupId;
        nodeStatusChangedEvent.valueInt2 = nodeStatus;
        mService.messageFromNative(nodeStatusChangedEvent);

        assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();

        // Add location support
        LeAudioStackEvent audioConfChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
        audioConfChangedEvent.device = mSingleDevice;
        audioConfChangedEvent.valueInt1 = direction;
        audioConfChangedEvent.valueInt2 = groupId;
        audioConfChangedEvent.valueInt3 = snkAudioLocation;
        audioConfChangedEvent.valueInt4 = srcAudioLocation;
        audioConfChangedEvent.valueInt5 = availableContexts;
        mService.messageFromNative(audioConfChangedEvent);

        // Set group and device as active
        LeAudioStackEvent groupStatusChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
        groupStatusChangedEvent.device = mSingleDevice;
        groupStatusChangedEvent.valueInt1 = groupId;
        groupStatusChangedEvent.valueInt2 = groupStatus;
        mService.messageFromNative(groupStatusChangedEvent);

        assertThat(mService.getActiveDevices().contains(mSingleDevice)).isTrue();
        assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(2);
    }
}