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

Commit 644b0b83 authored by Haijie Hong's avatar Haijie Hong
Browse files

Update preferred transport when HID and LeAudio profile are connected

Bug: 330581926
Test: atest CachedBluetoothDeviceTest
Change-Id: Ib7d42a74c4d174ee61efd2fa6eb7eafd963f9c40
parent 1ae8b771
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -51,3 +51,13 @@ flag {
  description: "Hide exclusively managed Bluetooth devices in BT settings menu."
  bug: "324475542"
}

flag {
    name: "enable_set_preferred_transport_for_le_audio_device"
    namespace: "bluetooth"
    description: "Enable setting preferred transport for Le Audio device"
    bug: "330581926"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settingslib.bluetooth;

import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice;

import android.annotation.CallbackExecutor;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -288,6 +290,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
                        mLocalNapRoleConnected = true;
                    }
                }
                if (enableSetPreferredTransportForLeAudioDevice()
                        && profile instanceof HidProfile) {
                    updatePreferredTransport();
                }
            } else if (profile instanceof MapProfile
                    && newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
                profile.setEnabled(mDevice, false);
@@ -300,12 +306,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
                mLocalNapRoleConnected = false;
            }

            if (enableSetPreferredTransportForLeAudioDevice()
                    && profile instanceof LeAudioProfile) {
                updatePreferredTransport();
            }

            HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, this, profile, newProfileState);
        }

        fetchActiveDevices();
    }

    private void updatePreferredTransport() {
        if (mProfiles.stream().noneMatch(p -> p instanceof LeAudioProfile)
                || mProfiles.stream().noneMatch(p -> p instanceof HidProfile)) {
            return;
        }
        // Both LeAudioProfile and HidProfile are connectable.
        if (!mProfileManager
                .getHidProfile()
                .setPreferredTransport(
                        mDevice,
                        mProfileManager.getLeAudioProfile().isEnabled(mDevice)
                                ? BluetoothDevice.TRANSPORT_LE
                                : BluetoothDevice.TRANSPORT_BREDR)) {
            Log.w(TAG, "Fail to set preferred transport");
        }
    }

    @VisibleForTesting
    void setProfileConnectedStatus(int profileId, boolean isFailed) {
        switch (profileId) {
+10 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.android.settingslib.R;

import java.util.List;
@@ -187,6 +189,14 @@ public class HidProfile implements LocalBluetoothProfile {
        }
    }

    /** Set preferred transport for the device */
    public boolean setPreferredTransport(@NonNull BluetoothDevice device, int transport) {
        if (mService != null) {
            mService.setPreferredTransport(device, transport);
        }
        return false;
    }

    protected void finalize() {
        Log.d(TAG, "finalize()");
        if (mService != null) {
+1 −2
Original line number Diff line number Diff line
@@ -572,8 +572,7 @@ public class LocalBluetoothProfileManager {
        return mSapProfile;
    }

    @VisibleForTesting
    HidProfile getHidProfile() {
    public HidProfile getHidProfile() {
        return mHidProfile;
    }

+34 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.settingslib.bluetooth;

import static com.android.settingslib.flags.Flags.FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
@@ -86,6 +88,9 @@ public class CachedBluetoothDeviceTest {
    private HapClientProfile mHapClientProfile;
    @Mock
    private LeAudioProfile mLeAudioProfile;

    @Mock
    private HidProfile mHidProfile;
    @Mock
    private BluetoothDevice mDevice;
    @Mock
@@ -104,6 +109,7 @@ public class CachedBluetoothDeviceTest {
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG);
        mSetFlagsRule.enableFlags(FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE);
        mContext = RuntimeEnvironment.application;
        mAudioManager = mContext.getSystemService(AudioManager.class);
        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
@@ -118,6 +124,8 @@ public class CachedBluetoothDeviceTest {
        when(mHearingAidProfile.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID);
        when(mLeAudioProfile.isProfileReady()).thenReturn(true);
        when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
        when(mHidProfile.isProfileReady()).thenReturn(true);
        when(mHidProfile.getProfileId()).thenReturn(BluetoothProfile.HID_HOST);
        mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice));
        mSubCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mSubDevice));
        doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
@@ -1819,6 +1827,32 @@ public class CachedBluetoothDeviceTest {
        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
    }

    @Test
    public void leAudioHidDevice_leAudioEnabled_setPreferredTransportToLE() {

        when(mProfileManager.getHidProfile()).thenReturn(mHidProfile);
        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);

        updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED);
        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);

        verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_LE);
    }

    @Test
    public void leAudioHidDevice_leAudioDisabled_setPreferredTransportToBredr() {
        when(mProfileManager.getHidProfile()).thenReturn(mHidProfile);
        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(false);

        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED);
        updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED);

        verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_BREDR);
    }

    private HearingAidInfo getLeftAshaHearingAidInfo() {
        return new HearingAidInfo.Builder()
                .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT)