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

Commit 838a95fe authored by Pavlin Radoslavov's avatar Pavlin Radoslavov
Browse files

Update A2dpService.connect() to check correctly for A2DP Sink UUID

Previously, the A2DP Sink UUID check was applied only if the
remote device contained A2DP Source UUID as well.

Also:
 - Use AdapterService to obtain the UUIDs of a device.
   This makes it easier to write UUID-related unit tests.
 - Added a new unit test.

Bug: 73207565
Test: Manual. New unit test added:
runtest bluetooth --test-class com.android.bluetooth.a2dp.A2dpServiceTest \
                  --test-method testOutgoingConnectMissingAudioSinkUuid
Change-Id: I651a6b176956042681834cba0ff74819bee3e73e
parent e1291229
Loading
Loading
Loading
Loading
+9 −16
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.provider.Settings;
import android.support.annotation.GuardedBy;
import android.support.annotation.VisibleForTesting;
@@ -58,7 +57,10 @@ public class A2dpService extends ProfileService {
    private static final boolean DBG = true;
    private static final String TAG = "A2dpService";

    private static A2dpService sA2dpService;

    private BluetoothAdapter mAdapter;
    private AdapterService mAdapterService;
    private HandlerThread mStateMachinesThread;
    private Avrcp mAvrcp;

@@ -84,14 +86,6 @@ public class A2dpService extends ProfileService {
        mA2dpNativeInterface = A2dpNativeInterface.getInstance();
    }

    private static A2dpService sA2dpService;
    static final ParcelUuid[] A2DP_SOURCE_UUID = {
            BluetoothUuid.AudioSource
    };
    static final ParcelUuid[] A2DP_SOURCE_SINK_UUIDS = {
            BluetoothUuid.AudioSource, BluetoothUuid.AudioSink
    };

    @Override
    protected IProfileServiceBinder initBinder() {
        return new BluetoothA2dpBinder(this);
@@ -103,9 +97,9 @@ public class A2dpService extends ProfileService {
            Log.d(TAG, "start()");
        }

        AdapterService adapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
        mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
                "AdapterService cannot be null when A2dpService starts");
        mMaxConnectedAudioDevices = adapterService.getMaxConnectedAudioDevices();
        mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
        if (DBG) {
            Log.d(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);
        }
@@ -215,9 +209,8 @@ public class A2dpService extends ProfileService {
        if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
            return false;
        }
        ParcelUuid[] featureUuids = device.getUuids();
        if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID))
                && !(BluetoothUuid.containsAllUuids(featureUuids, A2DP_SOURCE_SINK_UUIDS))) {
        if (!BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
                                         BluetoothUuid.AudioSink)) {
            Log.e(TAG, "Cannot connect to " + device + " : Remote does not have A2DP Sink UUID");
            return false;
        }
@@ -298,8 +291,8 @@ public class A2dpService extends ProfileService {
        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
        synchronized (mStateMachines) {
            for (BluetoothDevice device : bondedDevices) {
                ParcelUuid[] featureUuids = device.getUuids();
                if (!BluetoothUuid.isUuidPresent(featureUuids, BluetoothUuid.AudioSink)) {
                if (!BluetoothUuid.isUuidPresent(mAdapterService.getRemoteUuids(device),
                                                 BluetoothUuid.AudioSink)) {
                    continue;
                }
                int connectionState = BluetoothProfile.STATE_DISCONNECTED;
+22 −0
Original line number Diff line number Diff line
@@ -22,11 +22,13 @@ import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Looper;
import android.os.ParcelUuid;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ServiceTestRule;
@@ -100,6 +102,8 @@ public class A2dpServiceTest {
        // Get a device for testing
        mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
        mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_UNDEFINED);
        doReturn(new ParcelUuid[]{BluetoothUuid.AudioSink}).when(mAdapterService)
                .getRemoteUuids(any(BluetoothDevice.class));
    }

    @After
@@ -196,6 +200,24 @@ public class A2dpServiceTest {
                            mA2dpService.getPriority(mTestDevice));
    }

    /**
     * Test that an outgoing connection to device that does not have A2DP Sink UUID is rejected
     */
    @Test
    public void testOutgoingConnectMissingAudioSinkUuid() {
        // Update the device priority so okToConnect() returns true
        mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
        doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
        doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));

        // Return AudioSource UUID instead of AudioSink
        doReturn(new ParcelUuid[]{BluetoothUuid.AudioSource}).when(mAdapterService)
                .getRemoteUuids(any(BluetoothDevice.class));

        // Send a connect request
        Assert.assertFalse("Connect expected to fail", mA2dpService.connect(mTestDevice));
    }

    /**
     * Test that an outgoing connection times out
     */