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

Commit 0ac49b2b authored by Angela Wang's avatar Angela Wang Committed by Android (Google) Code Review
Browse files

Merge "Sync the preset for device that doesn't support synchronization" into main

parents c24f4371 9b80c536
Loading
Loading
Loading
Loading
+16 −0
Original line number Original line Diff line number Diff line
@@ -175,6 +175,22 @@ public class CachedBluetoothDeviceManager {
        return null;
        return null;
    }
    }


    /**
     * Sync device status of the pair of the hearing aid if needed.
     *
     * @param device the remote device
     */
    public synchronized void syncDeviceWithinHearingAidSetIfNeeded(CachedBluetoothDevice device,
            int state, int profileId) {
        if (profileId == BluetoothProfile.HAP_CLIENT
                || profileId == BluetoothProfile.HEARING_AID
                || profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
            if (state == BluetoothProfile.STATE_CONNECTED) {
                mHearingAidDeviceManager.syncDeviceIfNeeded(device);
            }
        }
    }

    /**
    /**
     * Search for existing sub device {@link CachedBluetoothDevice}.
     * Search for existing sub device {@link CachedBluetoothDevice}.
     *
     *
+39 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,8 @@
 */
 */
package com.android.settingslib.bluetooth;
package com.android.settingslib.bluetooth;


import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile;
@@ -108,6 +110,10 @@ public class HearingAidDeviceManager {
        return hiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
        return hiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
    }
    }


    private boolean isValidGroupId(int groupId) {
        return groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
    }

    private CachedBluetoothDevice getCachedDevice(long hiSyncId) {
    private CachedBluetoothDevice getCachedDevice(long hiSyncId) {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
@@ -258,6 +264,27 @@ public class HearingAidDeviceManager {
        }
        }
    }
    }


    void syncDeviceIfNeeded(CachedBluetoothDevice device) {
        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
        final HapClientProfile hap = profileManager.getHapClientProfile();
        // Sync preset if device doesn't support synchronization on the remote side
        if (hap != null && !hap.supportsSynchronizedPresets(device.getDevice())) {
            final CachedBluetoothDevice mainDevice = findMainDevice(device);
            if (mainDevice != null) {
                int mainPresetIndex = hap.getActivePresetIndex(mainDevice.getDevice());
                int presetIndex = hap.getActivePresetIndex(device.getDevice());
                if (mainPresetIndex != BluetoothHapClient.PRESET_INDEX_UNAVAILABLE
                        && mainPresetIndex != presetIndex) {
                    if (DEBUG) {
                        Log.d(TAG, "syncing preset from " + presetIndex + "->"
                                + mainPresetIndex + ", device=" + device);
                    }
                    hap.selectPreset(device.getDevice(), mainPresetIndex);
                }
            }
        }
    }

    private void setAudioRoutingConfig(CachedBluetoothDevice device) {
    private void setAudioRoutingConfig(CachedBluetoothDevice device) {
        AudioDeviceAttributes hearingDeviceAttributes =
        AudioDeviceAttributes hearingDeviceAttributes =
                mRoutingHelper.getMatchedHearingDeviceAttributes(device);
                mRoutingHelper.getMatchedHearingDeviceAttributes(device);
@@ -326,7 +353,19 @@ public class HearingAidDeviceManager {
    }
    }


    CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
    CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
        if (device == null || mCachedDevices == null) {
            return null;
        }

        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            if (isValidGroupId(cachedDevice.getGroupId())) {
                Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
                for (CachedBluetoothDevice memberDevice : memberSet) {
                    if (memberDevice != null && memberDevice.equals(device)) {
                        return cachedDevice;
                    }
                }
            }
            if (isValidHiSyncId(cachedDevice.getHiSyncId())) {
            if (isValidHiSyncId(cachedDevice.getHiSyncId())) {
                CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                if (subDevice != null && subDevice.equals(device)) {
                if (subDevice != null && subDevice.equals(device)) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -408,6 +408,8 @@ public class LocalBluetoothProfileManager {
            boolean needDispatchProfileConnectionState = true;
            boolean needDispatchProfileConnectionState = true;
            if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
            if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
                    || cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
                    || cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
                mDeviceManager.syncDeviceWithinHearingAidSetIfNeeded(cachedDevice, newState,
                        mProfile.getProfileId());
                needDispatchProfileConnectionState = !mDeviceManager
                needDispatchProfileConnectionState = !mDeviceManager
                        .onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
                        .onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
                        mProfile.getProfileId());
                        mProfile.getProfileId());
+74 −11
Original line number Original line Diff line number Diff line
@@ -72,14 +72,18 @@ public class HearingAidDeviceManagerTest {
    @Rule
    @Rule
    public MockitoRule mMockitoRule = MockitoJUnit.rule();
    public MockitoRule mMockitoRule = MockitoJUnit.rule();


    private final static long HISYNCID1 = 10;
    private static final long HISYNCID1 = 10;
    private final static long HISYNCID2 = 11;
    private static final long HISYNCID2 = 11;
    private final static String DEVICE_NAME_1 = "TestName_1";
    private static final int GROUP_ID_1 = 20;
    private final static String DEVICE_NAME_2 = "TestName_2";
    private static final int GROUP_ID_2 = 21;
    private final static String DEVICE_ALIAS_1 = "TestAlias_1";
    private static final int PRESET_INDEX_1 = 1;
    private final static String DEVICE_ALIAS_2 = "TestAlias_2";
    private static final int PRESET_INDEX_2 = 2;
    private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
    private static final String DEVICE_NAME_1 = "TestName_1";
    private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
    private static final String DEVICE_NAME_2 = "TestName_2";
    private static final String DEVICE_ALIAS_1 = "TestAlias_1";
    private static final String DEVICE_ALIAS_2 = "TestAlias_2";
    private static final String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
    private static final String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
    private final BluetoothClass DEVICE_CLASS =
    private final BluetoothClass DEVICE_CLASS =
            createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
            createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
    private final Context mContext = ApplicationProvider.getApplicationContext();
    private final Context mContext = ApplicationProvider.getApplicationContext();
@@ -706,14 +710,73 @@ public class HearingAidDeviceManagerTest {
    }
    }


    @Test
    @Test
    public void findMainDevice() {
    public void findMainDevice_sameHiSyncId() {
        when(mCachedDevice1.getHiSyncId()).thenReturn(HISYNCID1);
        when(mCachedDevice1.getHiSyncId()).thenReturn(HISYNCID1);
        when(mCachedDevice2.getHiSyncId()).thenReturn(HISYNCID1);
        when(mCachedDevice2.getHiSyncId()).thenReturn(HISYNCID1);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDevice1.setSubDevice(mCachedDevice2);
        mCachedDevice1.setSubDevice(mCachedDevice2);


        assertThat(mHearingAidDeviceManager.findMainDevice(mCachedDevice2)).
        assertThat(mHearingAidDeviceManager.findMainDevice(mCachedDevice2)).isEqualTo(
                isEqualTo(mCachedDevice1);
                mCachedDevice1);
    }

    @Test
    public void findMainDevice_sameGroupId() {
        when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
        when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_2);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDevice1.addMemberDevice(mCachedDevice2);

        assertThat(mHearingAidDeviceManager.findMainDevice(mCachedDevice2)).isEqualTo(
                mCachedDevice1);
    }

    @Test
    public void syncDeviceWithinSet_synchronized_differentPresetIndex_shouldNotSync() {
        when(mHapClientProfile.getActivePresetIndex(mDevice1)).thenReturn(PRESET_INDEX_1);
        when(mHapClientProfile.getActivePresetIndex(mDevice2)).thenReturn(PRESET_INDEX_2);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice1)).thenReturn(true);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice2)).thenReturn(true);
        when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
        when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_2);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDevice1.addMemberDevice(mCachedDevice2);

        mHearingAidDeviceManager.syncDeviceIfNeeded(mCachedDevice1);

        verify(mHapClientProfile, never()).selectPreset(any(), anyInt());
    }

    @Test
    public void syncDeviceWithinSet_unsynchronized_samePresetIndex_shouldNotSync() {
        when(mHapClientProfile.getActivePresetIndex(mDevice1)).thenReturn(PRESET_INDEX_1);
        when(mHapClientProfile.getActivePresetIndex(mDevice2)).thenReturn(PRESET_INDEX_1);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice1)).thenReturn(false);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice2)).thenReturn(false);
        when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
        when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_2);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDevice1.addMemberDevice(mCachedDevice2);

        mHearingAidDeviceManager.syncDeviceIfNeeded(mCachedDevice1);

        verify(mHapClientProfile, never()).selectPreset(any(), anyInt());
    }

    @Test
    public void syncDeviceWithinSet_unsynchronized_differentPresetIndex_shouldSync() {
        when(mHapClientProfile.getActivePresetIndex(mDevice1)).thenReturn(PRESET_INDEX_1);
        when(mHapClientProfile.getActivePresetIndex(mDevice2)).thenReturn(PRESET_INDEX_2);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice1)).thenReturn(false);
        when(mHapClientProfile.supportsSynchronizedPresets(mDevice2)).thenReturn(false);
        when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
        when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_2);
        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
        mCachedDevice1.addMemberDevice(mCachedDevice2);

        mHearingAidDeviceManager.syncDeviceIfNeeded(mCachedDevice2);

        verify(mHapClientProfile).selectPreset(mDevice2, PRESET_INDEX_1);
    }
    }


    private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) {
    private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) {
+28 −2
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPan;
@@ -55,7 +56,9 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
@Config(shadows = {ShadowBluetoothAdapter.class})
public class LocalBluetoothProfileManagerTest {
public class LocalBluetoothProfileManagerTest {
    private final static long HISYNCID = 10;
    private static final long HISYNCID = 10;

    private static final int GROUP_ID = 1;
    @Mock
    @Mock
    private LocalBluetoothManager mBtManager;
    private LocalBluetoothManager mBtManager;
    @Mock
    @Mock
@@ -201,7 +204,8 @@ public class LocalBluetoothProfileManagerTest {
     * CachedBluetoothDeviceManager method
     * CachedBluetoothDeviceManager method
     */
     */
    @Test
    @Test
    public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldDispatchDeviceManager() {
    public void
            stateChangedHandler_receiveHearingAidConnectionStateChanged_dispatchDeviceManager() {
        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                new int[] {BluetoothProfile.HEARING_AID}));
                new int[] {BluetoothProfile.HEARING_AID}));
        mProfileManager.updateLocalProfiles();
        mProfileManager.updateLocalProfiles();
@@ -218,6 +222,28 @@ public class LocalBluetoothProfileManagerTest {
                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
    }
    }


    /**
     * Verify BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED with uuid intent will dispatch
     * to {@link CachedBluetoothDeviceManager} method
     */
    @Test
    public void stateChangedHandler_receiveHapClientConnectionStateChanged_dispatchDeviceManager() {
        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                new int[] {BluetoothProfile.HAP_CLIENT}));
        mProfileManager.updateLocalProfiles();
        when(mCachedBluetoothDevice.getGroupId()).thenReturn(GROUP_ID);

        mIntent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);

        mContext.sendBroadcast(mIntent);

        verify(mDeviceManager).syncDeviceWithinHearingAidSetIfNeeded(mCachedBluetoothDevice,
                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HAP_CLIENT);
    }

    /**
    /**
     * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
     * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
     * profile connection state changed callback
     * profile connection state changed callback