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

Commit 691a3fd6 authored by jasonwshsu's avatar jasonwshsu
Browse files

Fix default microphone for calls sometimes not work and not show UI

Root Cause: Only setMicrophonePreferredForCalls and show UI to current device, but audioManager
might hold other device in the same set

Solution: setMicrophonePreferredForCalls to whole device set and also check if any address in device
set contain in audioManager GET_DEVICES_INPUTS list

Bug: 392902067
Test: atest BluetoothDetailsHearingDeviceInputRoutingControllerTest
Flag: EXEMPT bugfix
Change-Id: Ic5846de26df4a8db67fa8efcf474fa4509f7918a
parent 010869fc
Loading
Loading
Loading
Loading
+32 −7
Original line number Diff line number Diff line
@@ -20,11 +20,13 @@ import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceContro
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_HEARING_DEVICE_INPUT_ROUTING;

import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArraySet;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
@@ -38,6 +40,7 @@ import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper;
import com.android.settingslib.core.lifecycle.Lifecycle;

import java.util.Arrays;
import java.util.Set;

/**
 * The controller of the hearing device input routing
@@ -66,15 +69,25 @@ public class BluetoothDetailsHearingDeviceInputRoutingController extends

    @Override
    public boolean isAvailable() {
        boolean isSupportedProfile = mCachedDevice.getProfiles().stream().anyMatch(
        final Set<CachedBluetoothDevice> memberDevices = mCachedDevice.getMemberDevice();
        final AudioDeviceInfo[] inputInfos = mAudioManager.getDevices(
                AudioManager.GET_DEVICES_INPUTS);
        final Set<String> supportedInputDeviceAddresses = new ArraySet<>();
        supportedInputDeviceAddresses.add(mCachedDevice.getAddress());
        if (!memberDevices.isEmpty()) {
            memberDevices.forEach(member -> supportedInputDeviceAddresses.add(member.getAddress()));
        }

        boolean isHapHearingDevice = mCachedDevice.getProfiles().stream().anyMatch(
                profile -> profile instanceof HapClientProfile);
        boolean isSupportedInputDevice = Arrays.stream(
                mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).anyMatch(
                    info -> mCachedDevice.getAddress().equals(info.getAddress()));
        if (isSupportedProfile && !isSupportedInputDevice) {
        // Not support ASHA hearing device for input routing feature
        boolean isValidInputDevice = Arrays.stream(inputInfos).anyMatch(
                info -> supportedInputDeviceAddresses.contains(info.getAddress()));

        if (isHapHearingDevice && !isValidInputDevice) {
            Log.d(TAG, "Not supported input type hearing device.");
        }
        return isSupportedProfile && isSupportedInputDevice;
        return isHapHearingDevice && isValidInputDevice;
    }

    @Override
@@ -121,6 +134,18 @@ public class BluetoothDetailsHearingDeviceInputRoutingController extends
        if (!status) {
            Log.d(TAG, "Fail to configure setPreferredInputDeviceForCalls");
        }
        mCachedDevice.getDevice().setMicrophonePreferredForCalls(!useBuiltinMic);
        setMicrophonePreferredForCallsForDeviceSet(mCachedDevice, !useBuiltinMic);
    }

    private void setMicrophonePreferredForCallsForDeviceSet(CachedBluetoothDevice device,
            boolean enabled) {
        if (device == null) {
            return;
        }
        device.getDevice().setMicrophonePreferredForCalls(enabled);
        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
        if (!memberDevices.isEmpty()) {
            memberDevices.forEach(d -> d.getDevice().setMicrophonePreferredForCalls(enabled));
        }
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import androidx.test.core.app.ApplicationProvider;

import com.android.settings.R;
import com.android.settings.bluetooth.HearingDeviceInputRoutingPreference.InputRoutingValue;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HapClientProfile;

import org.junit.Rule;
@@ -49,6 +50,7 @@ import org.robolectric.RobolectricTestRunner;

import java.util.Collections;
import java.util.List;
import java.util.Set;

/** Tests for {@link BluetoothDetailsHearingDeviceInputRoutingController}. */

@@ -59,11 +61,14 @@ public class BluetoothDetailsHearingDeviceInputRoutingControllerTest extends
    public final MockitoRule mockito = MockitoJUnit.rule();

    private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
    private static final String TEST_ADDRESS_2 = "55:66:77:88:99:BB";

    @Mock
    private BluetoothDevice mBluetoothDevice;
    @Mock
    private HapClientProfile mHapClientProfile;
    @Mock
    private CachedBluetoothDevice mMemberCachedDevice;
    @Spy
    private AudioManager mAudioManager;

@@ -162,6 +167,18 @@ public class BluetoothDetailsHearingDeviceInputRoutingControllerTest extends
        assertThat(mController.isAvailable()).isFalse();
    }

    @Test
    public void isAvailable_validInputMember_supportHapProfile_returnTrue() {
        when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mMemberCachedDevice));
        when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
        when(mMemberCachedDevice.getAddress()).thenReturn(TEST_ADDRESS_2);
        AudioDeviceInfo[] mockInfo = new AudioDeviceInfo[] {mockTestAddressInfo(TEST_ADDRESS_2)};
        when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(mockInfo);
        when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile));

        assertThat(mController.isAvailable()).isTrue();
    }

    private AudioDeviceInfo mockTestAddressInfo(String address) {
        final AudioDeviceInfo info = mock(AudioDeviceInfo.class);
        when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);