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

Commit c61fb841 authored by jasonwshsu's avatar jasonwshsu
Browse files

Fix Audio output sometimes fails to apply when bluetooth re-enabled

Root Cause: AudioManager#getDevices(AudioManager.GET_DEVICES_OUTPUTS) is not guarantee to return the expected device after receiving profile STATE_CONNECTING broadcast. It will cause HearingAidAudioRoutingHelper#getMatchedHearingDeviceAttributes() can not find the expected output hearing device.

Solution: Listen to AudioDeviceCallback#onAudioDevicesAdded(). It was listened by HearingAidService and sent broadcast intent BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED. Use SettingsLib onActiveDeviceChanged() to handle it.

Bug: 282547878
Test: make RunSettingsLibRoboTests ROBOTEST_FILTER="(BluetoothEventManagerTest|CachedBluetoothDeviceManagerTest|HearingAidDeviceManagerTest)"
Change-Id: I47a500e855b94becf979392d67c317533e0ce2a9
parent 619bfd92
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ public class BluetoothEventManager {
                }
            }
            cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
            mDeviceManager.onActiveDeviceChanged(cachedDevice);
        }
        for (BluetoothCallback callback : mCallbacks) {
            callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
+7 −0
Original line number Diff line number Diff line
@@ -325,6 +325,13 @@ public class CachedBluetoothDeviceManager {
        return false;
    }

    /** Handles when the device been set as active/inactive. */
    public synchronized void onActiveDeviceChanged(CachedBluetoothDevice cachedBluetoothDevice) {
        if (cachedBluetoothDevice.isHearingAidDevice()) {
            mHearingAidDeviceManager.onActiveDeviceChanged(cachedBluetoothDevice);
        }
    }

    public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
        device.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
        CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
+9 −8
Original line number Diff line number Diff line
@@ -224,15 +224,9 @@ public class HearingAidDeviceManager {
                        // It is necessary to do remove and add for updating the mapping on
                        // preference and device
                        mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
                        // Only need to set first device of a set. AudioDeviceInfo for
                        // GET_DEVICES_OUTPUTS will not change device.
                        setAudioRoutingConfig(cachedDevice);
                    }
                    return true;
                }
                // Only need to set first device of a set. AudioDeviceInfo for GET_DEVICES_OUTPUTS
                // will not change device.
                setAudioRoutingConfig(cachedDevice);
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
                mainDevice = findMainDevice(cachedDevice);
@@ -258,13 +252,20 @@ public class HearingAidDeviceManager {

                    return true;
                }
                // Only need to clear when last device of a set get disconnected
                clearAudioRoutingConfig();
                break;
        }
        return false;
    }

    void onActiveDeviceChanged(CachedBluetoothDevice device) {
        if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
                BluetoothProfile.LE_AUDIO)) {
            setAudioRoutingConfig(device);
        } else {
            clearAudioRoutingConfig();
        }
    }

    private void setAudioRoutingConfig(CachedBluetoothDevice device) {
        AudioDeviceAttributes hearingDeviceAttributes =
                mRoutingHelper.getMatchedHearingDeviceAttributes(device);
+16 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@@ -395,6 +396,21 @@ public class BluetoothEventManagerTest {
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
    }

    @Test
    public void dispatchActiveDeviceChanged_callExpectedOnActiveDeviceChanged() {
        mBluetoothEventManager.registerCallback(mBluetoothCallback);
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
                Collections.singletonList(mCachedDevice1));

        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1,
                BluetoothProfile.HEARING_AID);

        verify(mCachedDeviceManager).onActiveDeviceChanged(mCachedDevice1);
        verify(mBluetoothCallback).onActiveDeviceChanged(mCachedDevice1,
                BluetoothProfile.HEARING_AID);
    }

    @Test
    public void showUnbondMessage_reasonAuthTimeout_showCorrectedErrorCode() {
        mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+18 −0
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@ package com.android.settingslib.bluetooth;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -604,4 +606,20 @@ public class CachedBluetoothDeviceManagerTest {
        verify(mDevice2).setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
        verify(mDevice2).createBond(BluetoothDevice.TRANSPORT_LE);
    }

    @Test
    public void onActiveDeviceChanged_validHiSyncId_callExpectedFunction() {
        mHearingAidDeviceManager = spy(new HearingAidDeviceManager(mContext, mLocalBluetoothManager,
                mCachedDeviceManager.mCachedDevices));
        doNothing().when(mHearingAidDeviceManager).onActiveDeviceChanged(any());
        mCachedDeviceManager.mHearingAidDeviceManager = mHearingAidDeviceManager;
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        cachedDevice1.setHearingAidInfo(
                new HearingAidInfo.Builder().setHiSyncId(HISYNCID1).build());

        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1);

        verify(mHearingAidDeviceManager).onActiveDeviceChanged(cachedDevice1);
    }
}
Loading