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

Commit 244c7586 authored by hughchen's avatar hughchen Committed by Hugh Chen
Browse files

Use corresponding profile to get active bluetooth device

- Do not use streamType to decide which active device should return.
  Base on b/80453878 comment#6, the steamType intent will only be sent
  if an action is made on stream volume or a media route is changed:
  For instance when a call to setStreamVolume() or getDeviceForStream() is made.
  It is not broadcast on actual routing changes.
  It should not be used as an indicator that the route changed during a call.
  There is no callback API and the only option is polling with getDeviceForStream().
- Use corresponding profile to get active bluetooth device
  instead of streamType
- Add test to verify the result of findActiveDevice()
  eg:
  1. A2dp device active, hearing aid device not active : return a2dp device
  2. A2dp device not active, hearing aid device not active : return null
  3. hfp device active, hearing aid device not active : return hfp device
  4. hfp device not active, hearing aid device not active : return null

Bug: 80453878
Test: make -j42 RunSettingsRoboTests
Change-Id: I5bd94899a5d508e60ce911da9689b727ad1fc20c
parent 2061c2bd
Loading
Loading
Loading
Loading
+14 −23
Original line number Diff line number Diff line
@@ -17,11 +17,6 @@
package com.android.settings.sound;

import static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION;
import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioManager.STREAM_VOICE_CALL;
import static android.media.AudioSystem.DEVICE_OUT_ALL_A2DP;
import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO;
import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;

import android.bluetooth.BluetoothDevice;
@@ -309,28 +304,16 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
    }

    /**
     * According to different stream and output device, find the active device from
     * the corresponding profile. Hearing aid device could stream both STREAM_MUSIC
     * and STREAM_VOICE_CALL.
     *
     * @param streamType the type of audio streams.
     * @return the active device. Return null if the active device is current device
     * or streamType is not STREAM_MUSIC or STREAM_VOICE_CALL.
     * Find active hearing aid device
     */
    protected BluetoothDevice findActiveDevice(int streamType) {
        if (streamType != STREAM_MUSIC && streamType != STREAM_VOICE_CALL) {
            return null;
        }
        if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_ALL_A2DP)) {
            return mProfileManager.getA2dpProfile().getActiveDevice();
        } else if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_ALL_SCO)) {
            return mProfileManager.getHeadsetProfile().getActiveDevice();
        } else if (isStreamFromOutputDevice(streamType, DEVICE_OUT_HEARING_AID)) {
    protected BluetoothDevice findActiveHearingAidDevice() {
        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();

        if (hearingAidProfile != null) {
            // The first element is the left active device; the second element is
            // the right active device. And they will have same hiSyncId. If either
            // or both side is not active, it will be null on that position.
            List<BluetoothDevice> activeDevices =
                    mProfileManager.getHearingAidProfile().getActiveDevices();
            List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
            for (BluetoothDevice btDevice : activeDevices) {
                if (btDevice != null && mConnectedDevices.contains(btDevice)) {
                    // also need to check mConnectedDevices, because one of
@@ -342,6 +325,14 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
        return null;
    }

    /**
     * Find the active device from the corresponding profile.
     *
     * @return the active device. Return null if the
     * corresponding profile don't have active device.
     */
    public abstract BluetoothDevice findActiveDevice();

    int getDefaultDeviceIndex() {
        // Default device is after all connected devices.
        return mConnectedDevices.size();
+12 −8
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@
package com.android.settings.sound;

import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
import static android.media.AudioManager.STREAM_VOICE_CALL;
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;

import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -79,12 +77,7 @@ public class HandsFreeProfileOutputPreferenceController extends
        CharSequence[] mediaValues = new CharSequence[numDevices + 1];

        // Setup devices entries, select active connected device
        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice(STREAM_VOICE_CALL));

        if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_USB_HEADSET)) {
            // If wired headset is plugged in and active, select to default device.
            mSelectedIndex = getDefaultDeviceIndex();
        }
        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());

        // Display connected devices, default device and show the active device
        setPreference(mediaOutputs, mediaValues, preference);
@@ -109,4 +102,15 @@ public class HandsFreeProfileOutputPreferenceController extends
            hfpProfile.setActiveDevice(device);
        }
    }

    @Override
    public BluetoothDevice findActiveDevice() {
        BluetoothDevice activeDevice = findActiveHearingAidDevice();
        final HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile();

        if (activeDevice == null && headsetProfile != null) {
            activeDevice = headsetProfile.getActiveDevice();
        }
        return activeDevice;
    }
}
+12 −7
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.settings.sound;
import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;

import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -91,12 +90,7 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
        CharSequence[] mediaValues = new CharSequence[numDevices + 1];

        // Setup devices entries, select active connected device
        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice(STREAM_MUSIC));

        if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_USB_HEADSET)) {
            // If wired headset is plugged in and active, select to default device.
            mSelectedIndex = getDefaultDeviceIndex();
        }
        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());

        // Display connected devices, default device and show the active device
        setPreference(mediaOutputs, mediaValues, preference);
@@ -121,4 +115,15 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
            a2dpProfile.setActiveDevice(device);
        }
    }

    @Override
    public BluetoothDevice findActiveDevice() {
        BluetoothDevice activeDevice = findActiveHearingAidDevice();
        final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();

        if (activeDevice == null && a2dpProfile != null) {
            activeDevice = a2dpProfile.getActiveDevice();
        }
        return activeDevice;
    }
}
+21 −83
Original line number Diff line number Diff line
@@ -16,14 +16,8 @@

package com.android.settings.sound;


import static android.media.AudioManager.DEVICE_OUT_BLUETOOTH_SCO;
import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_VOICE_CALL;
import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO;
import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
import static android.media.AudioSystem.STREAM_MUSIC;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
@@ -312,54 +306,11 @@ public class AudioOutputSwitchPreferenceControllerTest {
    }

    /**
     * Audio stream is not STREAM_MUSIC or STREAM_VOICE_CALL.
     * findActiveDevice should return null.
     */
    @Test
    public void findActiveDevice_streamIsRing_shouldReturnNull() {
        assertThat(mController.findActiveDevice(STREAM_RING)).isNull();
    }

    /**
     * Audio stream is STREAM_MUSIC and output device is A2dp bluetooth device.
     * findActiveDevice should return A2dp active device.
     */
    @Test
    public void findActiveDevice_streamMusicToA2dpDevice_shouldReturnActiveA2dpDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
        mHearingAidActiveDevices.clear();
        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mLeftBluetoothHapDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mBluetoothDevice);
    }

    /**
     * Audio stream is STREAM_VOICE_CALL and output device is Hands free profile bluetooth device.
     * findActiveDevice should return Hands free profile active device.
     * Left side of HAP device is active.
     * findActiveHearingAidDevice should return hearing aid device active device.
     */
    @Test
    public void findActiveDevice_streamVoiceCallToHfpDevice_shouldReturnActiveHfpDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_SCO);
        mHearingAidActiveDevices.clear();
        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mLeftBluetoothHapDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(mBluetoothDevice);
    }

    /**
     * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid profile
     * bluetooth device. And left side of HAP device is active.
     * findActiveDevice should return hearing aid device active device.
     */
    @Test
    public void findActiveDevice_streamToHapDeviceLeftActiveDevice_shouldReturnActiveHapDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
    public void findActiveHearingAidDevice_leftActiveDevice_returnLeftDeviceAsActiveHapDevice() {
        mController.mConnectedDevices.clear();
        mController.mConnectedDevices.add(mBluetoothDevice);
        mController.mConnectedDevices.add(mLeftBluetoothHapDevice);
@@ -367,46 +318,35 @@ public class AudioOutputSwitchPreferenceControllerTest {
        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
        mHearingAidActiveDevices.add(null);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mLeftBluetoothHapDevice);
        assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(
                mLeftBluetoothHapDevice);
        assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mLeftBluetoothHapDevice);
    }

    /**
     * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid profile
     * bluetooth device. And right side of HAP device is active.
     * findActiveDevice should return hearing aid device active device.
     * Right side of HAP device is active.
     * findActiveHearingAidDevice should return hearing aid device active device.
     */
    @Test
    public void findActiveDevice_streamToHapDeviceRightActiveDevice_shouldReturnActiveHapDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
    public void findActiveHearingAidDevice_rightActiveDevice_returnRightDeviceAsActiveHapDevice() {
        mController.mConnectedDevices.clear();
        mController.mConnectedDevices.add(mBluetoothDevice);
        mController.mConnectedDevices.add(mRightBluetoothHapDevice);
        mHearingAidActiveDevices.clear();
        mHearingAidActiveDevices.add(null);
        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mRightBluetoothHapDevice);
        assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(
                mRightBluetoothHapDevice);
        assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mRightBluetoothHapDevice);
    }

    /**
     * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid
     * profile bluetooth device. And both are active device.
     * findActiveDevice should return only return the active device in mConnectedDevices.
     * Both are active device.
     * findActiveHearingAidDevice only return the active device in mConnectedDevices.
     */
    @Test
    public void findActiveDevice_streamToHapDeviceTwoActiveDevice_shouldReturnActiveHapDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
    public void findActiveHearingAidDevice_twoActiveDevice_returnActiveDeviceInConnectedDevices() {
        mController.mConnectedDevices.clear();
        mController.mConnectedDevices.add(mBluetoothDevice);
        mController.mConnectedDevices.add(mRightBluetoothHapDevice);
@@ -414,32 +354,25 @@ public class AudioOutputSwitchPreferenceControllerTest {
        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_MUSIC)).isEqualTo(mRightBluetoothHapDevice);
        assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isEqualTo(
                mRightBluetoothHapDevice);
        assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mRightBluetoothHapDevice);
    }

    /**
     * Audio stream is STREAM_MUSIC or STREAM_VOICE_CALL and output device is hearing aid
     * profile bluetooth device. And none of them are active.
     * findActiveDevice should return null.
     * None of them are active.
     * findActiveHearingAidDevice should return null.
     */
    @Test
    public void findActiveDevice_streamToOtherDevice_shouldReturnActiveHapDevice() {
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
    public void findActiveHearingAidDevice_noActiveDevice_returnNull() {
        mController.mConnectedDevices.clear();
        mController.mConnectedDevices.add(mBluetoothDevice);
        mController.mConnectedDevices.add(mLeftBluetoothHapDevice);
        mHearingAidActiveDevices.clear();
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);

        assertThat(mController.findActiveDevice(STREAM_MUSIC)).isNull();
        assertThat(mController.findActiveDevice(STREAM_VOICE_CALL)).isNull();
        assertThat(mController.findActiveHearingAidDevice()).isNull();
    }

    /**
@@ -557,6 +490,11 @@ public class AudioOutputSwitchPreferenceControllerTest {
        public void setActiveBluetoothDevice(BluetoothDevice device) {
        }

        @Override
        public BluetoothDevice findActiveDevice() {
            return null;
        }

        @Override
        public String getPreferenceKey() {
            return TEST_KEY;
+17 −4
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.settings.sound;

import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@@ -286,12 +285,10 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
    @Test
    public void updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary() {
        mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        mShadowAudioManager.setOutputDevice(DEVICE_OUT_USB_HEADSET);
        mProfileConnectedDevices.clear();
        mProfileConnectedDevices.add(mBluetoothDevice);
        when(mHeadsetProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(
                mBluetoothDevice); // BT device is still activated in this case
        when(mHeadsetProfile.getActiveDevice()).thenReturn(null);

        mController.updateState(mPreference);

@@ -463,4 +460,20 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
        assertThat(mController.mConnectedDevices).containsExactly(mBluetoothDevice,
                mLeftBluetoothHapDevice, mRightBluetoothHapDevice);
    }

    @Test
    public void findActiveDevice_onlyHeadsetDeviceActive_returnHeadsetDevice() {
        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);

        assertThat(mController.findActiveDevice()).isEqualTo(mBluetoothDevice);
    }

    @Test
    public void findActiveDevice_allDevicesNotActive_returnNull() {
        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
        when(mHeadsetProfile.getActiveDevice()).thenReturn(null);

        assertThat(mController.findActiveDevice()).isNull();
    }
}
Loading