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

Commit f5b262f2 authored by Sungsoo Lim's avatar Sungsoo Lim Committed by Android (Google) Code Review
Browse files

Merge changes Ie911ba61,I1d019bfd into tm-qpr-dev

* changes:
  Track Hearing aid connected devices
  Activate the last connected BT device
parents 08b9ee36 57a472c3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1292,7 +1292,7 @@ public class A2dpService extends ProfileService {
    /**
     * Retrieves the most recently connected device in the A2DP connected devices list.
     */
    private BluetoothDevice getFallbackDevice() {
    public BluetoothDevice getFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        return dbManager != null ? dbManager
            .getMostRecentlyConnectedDevicesInList(getConnectedDevices())
+183 −27
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.os.Message;
import android.util.Log;

import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.le_audio.LeAudioService;
@@ -51,8 +52,10 @@ import java.util.Objects;

/**
 * The active device manager is responsible for keeping track of the
 * connected A2DP/HFP/AVRCP/HearingAid devices and select which device is
 * connected A2DP/HFP/AVRCP/HearingAid/LE audio devices and select which device is
 * active (for each profile).
 * The active device manager selects a fallback device when the currently active device
 * is disconnected, and it selects BT devices that are lastly activated one.
 *
 * Current policy (subject to change):
 * 1) If the maximum number of connected devices is one, the manager doesn't
@@ -66,24 +69,24 @@ import java.util.Objects;
 *    - BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED for A2DP
 *    - BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED for HFP
 *    - BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED for HearingAid
 *    - BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED for LE audio
 *    If such broadcast is received (e.g., triggered indirectly by user
 *    action on the UI), the device in the received broacast is marked
 *    action on the UI), the device in the received broadcast is marked
 *    as the current active device for that profile.
 * 5) If there is a HearingAid active device, then A2DP and HFP active devices
 *    must be set to null (i.e., A2DP and HFP cannot have active devices).
 *    The reason is because A2DP or HFP cannot be used together with HearingAid.
 * 5) If there is a HearingAid active device, then A2DP, HFP and LE audio active devices
 *    must be set to null (i.e., A2DP, HFP and LE audio cannot have active devices).
 *    The reason is that A2DP, HFP or LE audio cannot be used together with HearingAid.
 * 6) If there are no connected devices (e.g., during startup, or after all
 *    devices have been disconnected, the active device per profile
 *    (A2DP/HFP/HearingAid) is selected as follows:
 *    (A2DP/HFP/HearingAid/LE audio) is selected as follows:
 * 6.1) The last connected HearingAid device is selected as active.
 *      If there is an active A2DP or HFP device, those must be set to null.
 * 6.2) The last connected A2DP or HFP device is selected as active.
 *      If there is an active A2DP, HFP or LE audio device, those must be set to null.
 * 6.2) The last connected A2DP, HFP or LE audio device is selected as active.
 *      However, if there is an active HearingAid device, then the
 *      A2DP or HFP active device is not set (must remain null).
 *      A2DP, HFP, or LE audio active device is not set (must remain null).
 * 7) If the currently active device (per profile) is disconnected, the
 *    Active Device Manager just marks that the profile has no active device,
 *    but does not attempt to select a new one. Currently, the expectation is
 *    that the user will explicitly select the new active device.
 *    and the lastly activated BT device that is still connected would be selected.
 * 8) If there is already an active device, and the corresponding
 *    ACTION_ACTIVE_DEVICE_CHANGED broadcast is received, the device
 *    contained in the broadcast is marked as active. However, if
@@ -91,7 +94,7 @@ import java.util.Objects;
 *    as having no active device.
 * 9) If a wired audio device is connected, the audio output is switched
 *    by the Audio Framework itself to that device. We detect this here,
 *    and the active device for each profile (A2DP/HFP/HearingAid) is set
 *    and the active device for each profile (A2DP/HFP/HearingAid/LE audio) is set
 *    to null to reflect the output device state change. However, if the
 *    wired audio device is disconnected, we don't do anything explicit
 *    and apply the default behavior instead:
@@ -114,7 +117,8 @@ class ActiveDeviceManager {
    private static final int MESSAGE_A2DP_ACTION_ACTIVE_DEVICE_CHANGED = 3;
    private static final int MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED = 4;
    private static final int MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED = 5;
    private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 6;
    private static final int MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED = 6;
    private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 7;
    private static final int MESSAGE_LE_AUDIO_ACTION_CONNECTION_STATE_CHANGED = 8;
    private static final int MESSAGE_LE_AUDIO_ACTION_ACTIVE_DEVICE_CHANGED = 9;
    private static final int MESSAGE_HAP_ACTION_CONNECTION_STATE_CHANGED = 10;
@@ -129,6 +133,7 @@ class ActiveDeviceManager {

    private final List<BluetoothDevice> mA2dpConnectedDevices = new LinkedList<>();
    private final List<BluetoothDevice> mHfpConnectedDevices = new LinkedList<>();
    private final List<BluetoothDevice> mHearingAidConnectedDevices = new LinkedList<>();
    private final List<BluetoothDevice> mLeAudioConnectedDevices = new LinkedList<>();
    private final List<BluetoothDevice> mLeHearingAidConnectedDevices = new LinkedList<>();
    private BluetoothDevice mA2dpActiveDevice = null;
@@ -167,6 +172,10 @@ class ActiveDeviceManager {
                    mHandler.obtainMessage(MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED,
                            intent).sendToTarget();
                    break;
                case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
                    mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED,
                            intent).sendToTarget();
                    break;
                case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED,
                            intent).sendToTarget();
@@ -240,7 +249,6 @@ class ActiveDeviceManager {
                            // New connected device: select it as active
                            setA2dpActiveDevice(device);
                            setLeAudioActiveDevice(null);
                            break;
                        }
                        break;
                    }
@@ -252,10 +260,12 @@ class ActiveDeviceManager {
                                    + "device " + device + " disconnected");
                        }
                        mA2dpConnectedDevices.remove(device);
                        if (mA2dpConnectedDevices.isEmpty()
                                && Objects.equals(mA2dpActiveDevice, device)) {
                        if (Objects.equals(mA2dpActiveDevice, device)) {
                            if (mA2dpConnectedDevices.isEmpty()) {
                                setA2dpActiveDevice(null);
                            }
                            setFallbackDeviceActive();
                        }
                    }
                }
                break;
@@ -302,7 +312,6 @@ class ActiveDeviceManager {
                            // New connected device: select it as active
                            setHfpActiveDevice(device);
                            setLeAudioActiveDevice(null);
                            break;
                        }
                        break;
                    }
@@ -314,10 +323,12 @@ class ActiveDeviceManager {
                                    + "device " + device + " disconnected");
                        }
                        mHfpConnectedDevices.remove(device);
                        if (mHfpConnectedDevices.isEmpty()
                                && Objects.equals(mHfpActiveDevice, device)) {
                        if (Objects.equals(mHfpActiveDevice, device)) {
                            if (mHfpConnectedDevices.isEmpty()) {
                                setHfpActiveDevice(null);
                            }
                            setFallbackDeviceActive();
                        }
                    }
                }
                break;
@@ -339,6 +350,50 @@ class ActiveDeviceManager {
                }
                break;

                case MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice device =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
                    int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
                    if (prevState == nextState) {
                        // Nothing has changed
                        break;
                    }
                    if (nextState == BluetoothProfile.STATE_CONNECTED) {
                        // Device connected
                        if (DBG) {
                            Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE"
                                    + "_CHANGED): device " + device + " connected");
                        }
                        if (mHearingAidConnectedDevices.contains(device)) {
                            break;      // The device is already connected
                        }
                        mHearingAidConnectedDevices.add(device);
                        // New connected device: select it as active
                        setHearingAidActiveDevice(device);
                        setA2dpActiveDevice(null);
                        setHfpActiveDevice(null);
                        setLeAudioActiveDevice(null);
                        break;
                    }
                    if (prevState == BluetoothProfile.STATE_CONNECTED) {
                        // Device disconnected
                        if (DBG) {
                            Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE"
                                    + "_CHANGED): device " + device + " disconnected");
                        }
                        mHearingAidConnectedDevices.remove(device);
                        if (Objects.equals(mHearingAidActiveDevice, device)) {
                            if (mHearingAidConnectedDevices.isEmpty()) {
                                setHearingAidActiveDevice(null);
                            }
                            setFallbackDeviceActive();
                        }
                    }
                }
                break;

                case MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice device =
@@ -392,10 +447,12 @@ class ActiveDeviceManager {
                                    + "_CHANGED): device " + device + " disconnected");
                        }
                        mLeAudioConnectedDevices.remove(device);
                        if (mLeAudioConnectedDevices.isEmpty()
                                && Objects.equals(mLeAudioActiveDevice, device)) {
                        if (Objects.equals(mLeAudioActiveDevice, device)) {
                            if (mLeAudioConnectedDevices.isEmpty()) {
                                setLeAudioActiveDevice(null);
                            }
                            setFallbackDeviceActive();
                        }
                    }
                }
                break;
@@ -465,10 +522,12 @@ class ActiveDeviceManager {
                        // mLeAudioConnectedDevices should contain all of
                        // mLeHearingAidConnectedDevices. Call setLeAudioActiveDevice(null)
                        // only if there are no LE audio devices.
                        if (mLeAudioConnectedDevices.isEmpty()
                                && Objects.equals(mLeHearingAidConnectedDevices, device)) {
                        if (Objects.equals(mLeHearingAidConnectedDevices, device)) {
                            if (mLeAudioConnectedDevices.isEmpty()) {
                                setLeAudioActiveDevice(null);
                            }
                            setFallbackDeviceActive();
                        }
                    }
                }
                break;
@@ -560,6 +619,7 @@ class ActiveDeviceManager {
        filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
@@ -658,6 +718,102 @@ class ActiveDeviceManager {
        }
    }

    private void setFallbackDeviceActive() {
        if (DBG) {
            Log.d(TAG, "setFallbackDeviceActive");
        }
        DatabaseManager dbManager = mAdapterService.getDatabase();
        if (dbManager == null) {
            return;
        }

        if (!mHearingAidConnectedDevices.isEmpty()) {
            BluetoothDevice device =
                    dbManager.getMostRecentlyConnectedDevicesInList(mHearingAidConnectedDevices);
            if (device != null) {
                if (DBG) {
                    Log.d(TAG, "set hearing aid device active: " + device);
                }
                setHearingAidActiveDevice(device);
                setA2dpActiveDevice(null);
                setHfpActiveDevice(null);
                setLeAudioActiveDevice(null);
                return;
            }
        }

        A2dpService a2dpService = mFactory.getA2dpService();
        BluetoothDevice a2dpFallbackDevice = null;
        if (a2dpService != null) {
            a2dpFallbackDevice = a2dpService.getFallbackDevice();
        }

        HeadsetService headsetService = mFactory.getHeadsetService();
        BluetoothDevice headsetFallbackDevice = null;
        if (headsetService != null) {
            headsetFallbackDevice = headsetService.getFallbackDevice();
        }

        List<BluetoothDevice> connectedDevices = new LinkedList<>();
        connectedDevices.addAll(mLeAudioConnectedDevices);
        switch (mAudioManager.getMode()) {
            case AudioManager.MODE_NORMAL:
                if (a2dpFallbackDevice != null) {
                    connectedDevices.add(a2dpFallbackDevice);
                }
                break;
            case AudioManager.MODE_RINGTONE:
                if (headsetFallbackDevice != null && headsetService.isInbandRingingEnabled()) {
                    connectedDevices.add(headsetFallbackDevice);
                }
                break;
            default:
                if (headsetFallbackDevice != null) {
                    connectedDevices.add(headsetFallbackDevice);
                }
        }
        BluetoothDevice device = dbManager.getMostRecentlyConnectedDevicesInList(connectedDevices);
        if (device != null) {
            if (mAudioManager.getMode() == AudioManager.MODE_NORMAL) {
                if (Objects.equals(a2dpFallbackDevice, device)) {
                    if (DBG) {
                        Log.d(TAG, "set A2DP device active: " + device);
                    }
                    setA2dpActiveDevice(device);
                    if (headsetFallbackDevice != null) {
                        setHfpActiveDevice(device);
                        setLeAudioActiveDevice(null);
                    }
                } else {
                    if (DBG) {
                        Log.d(TAG, "set LE audio device active: " + device);
                    }
                    setLeAudioActiveDevice(device);
                    setA2dpActiveDevice(null);
                    setHfpActiveDevice(null);
                }
            } else {
                if (Objects.equals(headsetFallbackDevice, device)) {
                    if (DBG) {
                        Log.d(TAG, "set HFP device active: " + device);
                    }
                    setHfpActiveDevice(device);
                    if (a2dpFallbackDevice != null) {
                        setA2dpActiveDevice(a2dpFallbackDevice);
                        setLeAudioActiveDevice(null);
                    }
                } else {
                    if (DBG) {
                        Log.d(TAG, "set LE audio device active: " + device);
                    }
                    setLeAudioActiveDevice(device);
                    setA2dpActiveDevice(null);
                    setHfpActiveDevice(null);
                }
            }
        }
    }

    private void resetState() {
        mA2dpConnectedDevices.clear();
        mA2dpActiveDevice = null;
+0 −1
Original line number Diff line number Diff line
@@ -818,7 +818,6 @@ public class HearingAidService extends ProfileService {
                        BluetoothMetricsProto.ProfileId.HEARING_AID);
            }
            if (!mHiSyncIdConnectedMap.getOrDefault(myHiSyncId, false)) {
                setActiveDevice(device);
                mHiSyncIdConnectedMap.put(myHiSyncId, true);
            }
        }
+7 −2
Original line number Diff line number Diff line
@@ -1927,7 +1927,12 @@ public class HeadsetService extends ProfileService {
        return true;
    }

    boolean isInbandRingingEnabled() {
    /**
     * Checks if headset devices are able to get inband ringing.
     *
     * @return True if inband ringing is enabled.
     */
    public boolean isInbandRingingEnabled() {
        boolean isInbandRingingSupported = getResources().getBoolean(
                com.android.bluetooth.R.bool.config_bluetooth_hfp_inband_ringing_support);
        return isInbandRingingSupported && !SystemProperties.getBoolean(
@@ -2176,7 +2181,7 @@ public class HeadsetService extends ProfileService {
    /**
     * Retrieves the most recently connected device in the A2DP connected devices list.
     */
    private BluetoothDevice getFallbackDevice() {
    public BluetoothDevice getFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        return dbManager != null ? dbManager
            .getMostRecentlyConnectedDevicesInList(getConnectedDevices())
+132 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;

@MediumTest
@RunWith(AndroidJUnit4.class)
public class ActiveDeviceManagerTest {
@@ -473,6 +475,114 @@ public class ActiveDeviceManagerTest {
        Assert.assertEquals(null, mActiveDeviceManager.getLeAudioActiveDevice());
    }

    /**
     * An LE Audio connected. An A2DP connected. The A2DP disconnected.
     * Then the LE Audio should be the active one.
     */
    @Test
    public void leAudioAndA2dpConnectedThenA2dpDisconnected_fallbackToLeAudio() {
        leAudioConnected(mLeAudioDevice);
        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);

        a2dpConnected(mA2dpDevice);
        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);

        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
        when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer(
                invocation -> {
                    List<BluetoothDevice> devices = invocation.getArgument(0);
                    return (devices != null && devices.contains(mLeAudioDevice))
                            ? mLeAudioDevice : null;
                }
        );
        a2dpDisconnected(mA2dpDevice);
        verify(mA2dpService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(isNull());
        verify(mLeAudioService, timeout(TIMEOUT_MS).times(2)).setActiveDevice(mLeAudioDevice);
    }

    /**
     * An A2DP connected. An LE Audio connected. The LE Audio disconnected.
     * Then the A2DP should be the active one.
     */
    @Test
    public void a2dpAndLeAudioConnectedThenLeAudioDisconnected_fallbackToA2dp() {
        a2dpConnected(mA2dpDevice);
        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);

        leAudioConnected(mLeAudioDevice);
        verify(mLeAudioService, timeout(TIMEOUT_MS)).setActiveDevice(mLeAudioDevice);

        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
        when(mA2dpService.getFallbackDevice()).thenReturn(mA2dpDevice);
        when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer(
                invocation -> {
                    List<BluetoothDevice> devices = invocation.getArgument(0);
                    return (devices != null && devices.contains(mA2dpDevice)) ? mA2dpDevice : null;
                }
        );
        leAudioDisconnected(mLeAudioDevice);
        verify(mLeAudioService, timeout(TIMEOUT_MS).atLeast(1)).setActiveDevice(isNull());
        verify(mA2dpService, timeout(TIMEOUT_MS).times(2)).setActiveDevice(mA2dpDevice);
    }

    /**
     * Two Hearing Aid are connected and the current active is then disconnected.
     * Should then set active device to fallback device.
     */
    @Test
    public void hearingAidSecondDeviceDisconnected_fallbackDeviceActive() {
        hearingAidConnected(mSecondaryAudioDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);

        hearingAidConnected(mHearingAidDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);

        leAudioDisconnected(mHearingAidDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice);
    }

    /**
     * Hearing aid is connected, but active device is different BT.
     * When the active device is disconnected, the hearing aid should be the active one.
     */
    @Test
    public void activeDeviceDisconnected_fallbackToHearingAid() {
        hearingAidConnected(mHearingAidDevice);
        verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice);

        leAudioConnected(mLeAudioDevice);
        a2dpConnected(mA2dpDevice);

        a2dpActiveDeviceChanged(mA2dpDevice);
        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());

        verify(mHearingAidService).setActiveDevice(isNull());
        verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice);
        verify(mA2dpService, never()).setActiveDevice(mA2dpDevice);

        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
        when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer(
                invocation -> {
                    List<BluetoothDevice> devices = invocation.getArgument(0);
                    if (devices == null) {
                        return null;
                    } else if (devices.contains(mA2dpDevice)) {
                        return mA2dpDevice;
                    } else if (devices.contains(mLeAudioDevice)) {
                        return mLeAudioDevice;
                    } else if (devices.contains(mHearingAidDevice)) {
                        return mHearingAidDevice;
                    } else {
                        return devices.get(0);
                    }
                }
        );
        a2dpDisconnected(mA2dpDevice);
        verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
        verify(mHearingAidService, timeout(TIMEOUT_MS).times(2))
                .setActiveDevice(mHearingAidDevice);
    }

    /**
     * One LE Hearing Aid is connected.
     */
@@ -574,6 +684,28 @@ public class ActiveDeviceManagerTest {
        mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
    }

    /**
     * Helper to indicate Hearing Aid connected for a device.
     */
    private void hearingAidConnected(BluetoothDevice device) {
        Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
        mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
    }

    /**
     * Helper to indicate Hearing Aid disconnected for a device.
     */
    private void hearingAidDisconnected(BluetoothDevice device) {
        Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
        mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
    }

    /**
     * Helper to indicate Hearing Aid active device changed for a device.
     */