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

Commit ce0bccad authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "hearing-aid-set-active-device"

* changes:
  Active device manager: Integrate Hearing Aid
  Hearing Aid: change set/get active device(2/3)
parents 51324de7 ce3625bd
Loading
Loading
Loading
Loading
+61 −6
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -32,6 +33,7 @@ import android.os.Message;
import android.util.Log;

import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;

import java.util.LinkedList;
@@ -96,6 +98,7 @@ class ActiveDeviceManager {
    private static final int MESSAGE_A2DP_ACTION_ACTIVE_DEVICE_CHANGED = 4;
    private static final int MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED = 5;
    private static final int MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED = 6;
    private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 7;

    // Timeouts
    private static final int SELECT_ACTIVE_DEVICE_TIMEOUT_MS = 6000; // 6s
@@ -109,6 +112,7 @@ class ActiveDeviceManager {
    private final List<BluetoothDevice> mHfpConnectedDevices = new LinkedList<>();
    private BluetoothDevice mA2dpActiveDevice = null;
    private BluetoothDevice mHfpActiveDevice = null;
    private BluetoothDevice mHearingAidActiveDevice = null;

    // Broadcast receiver for all changes
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -136,6 +140,14 @@ class ActiveDeviceManager {
                    mHandler.obtainMessage(MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED,
                                           intent).sendToTarget();
                    break;
                case BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED,
                        intent).sendToTarget();
                    break;
                case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED,
                            intent).sendToTarget();
                    break;
                default:
                    Log.e(TAG, "Received unexpected intent, action=" + action);
                    break;
@@ -169,10 +181,12 @@ class ActiveDeviceManager {
                        Log.d(TAG, "handleMessage(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT)");
                    }
                    // Set the first connected device as active
                    if ((mA2dpActiveDevice == null) && !mA2dpConnectedDevices.isEmpty()) {
                    if ((mA2dpActiveDevice == null) && !mA2dpConnectedDevices.isEmpty()
                            && mHearingAidActiveDevice == null) {
                        setA2dpActiveDevice(mA2dpConnectedDevices.get(0));
                    }
                    if ((mHfpActiveDevice == null) && !mHfpConnectedDevices.isEmpty()) {
                    if ((mHfpActiveDevice == null) && !mHfpConnectedDevices.isEmpty()
                            && mHearingAidActiveDevice == null) {
                        setHfpActiveDevice(mHfpConnectedDevices.get(0));
                    }
                }
@@ -194,7 +208,7 @@ class ActiveDeviceManager {
                        if (mA2dpConnectedDevices.contains(device)) {
                            break;
                        }
                        if (!hasConnectedDevices()) {
                        if (!hasConnectedClassicDevices() && mHearingAidActiveDevice == null) {
                            // First connected device: select it as active and start the timer
                            mA2dpConnectedDevices.add(device);
                            Message m = obtainMessage(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT);
@@ -204,13 +218,15 @@ class ActiveDeviceManager {
                        }
                        mA2dpConnectedDevices.add(device);
                        // Check whether the active device for the other profile is same
                        if ((mA2dpActiveDevice == null) && matchesActiveDevice(device)) {
                        if ((mA2dpActiveDevice == null) && matchesActiveDevice(device)
                                && mHearingAidActiveDevice == null) {
                            setA2dpActiveDevice(device);
                            break;
                        }
                        // Check whether the active device selection timer is not running
                        if ((mA2dpActiveDevice == null)
                                && !hasMessages(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT)) {
                                && !hasMessages(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT)
                                && mHearingAidActiveDevice == null) {
                            setA2dpActiveDevice(mA2dpConnectedDevices.get(0));
                            break;
                        }
@@ -241,6 +257,9 @@ class ActiveDeviceManager {
                                + "device= " + device);
                    }
                    removeMessages(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT);
                    if (device != null && !Objects.equals(mA2dpActiveDevice, device)) {
                        setHearingAidActiveDevice(null);
                    }
                    // Just assign locally the new value
                    mA2dpActiveDevice = device;
                }
@@ -266,10 +285,31 @@ class ActiveDeviceManager {
                                + "device= " + device);
                    }
                    removeMessages(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT);
                    if (device != null && !Objects.equals(mHfpActiveDevice, device)) {
                        setHearingAidActiveDevice(null);
                    }
                    // Just assign locally the new value
                    mHfpActiveDevice = device;
                }
                break;

                case MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice device =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (DBG) {
                        Log.d(TAG, "handleMessage(MESSAGE_HA_ACTION_ACTIVE_DEVICE_CHANGED): "
                                + "device= " + device);
                    }
                    removeMessages(MESSAGE_SELECT_ACTICE_DEVICE_TIMEOUT);
                    // Just assign locally the new value
                    mHearingAidActiveDevice = device;
                    if (device != null) {
                        setA2dpActiveDevice(null);
                        setHfpActiveDevice(null);
                    }
                }
                break;
            }
        }
    }
@@ -294,6 +334,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_ACTIVE_DEVICE_CHANGED);
        mAdapterService.registerReceiver(mReceiver, filter);
    }

@@ -338,7 +379,21 @@ class ActiveDeviceManager {
        mHfpActiveDevice = device;
    }

    private boolean hasConnectedDevices() {
    private void setHearingAidActiveDevice(BluetoothDevice device) {
        if (DBG) {
            Log.d(TAG, "setHearingAidActiveDevice(" + device + ")");
        }
        final HearingAidService hearingAidService = mFactory.getHearingAidService();
        if (hearingAidService == null) {
            return;
        }
        if (!hearingAidService.setActiveDevice(device)) {
            return;
        }
        mHearingAidActiveDevice = device;
    }

    private boolean hasConnectedClassicDevices() {
        return (!mA2dpConnectedDevices.isEmpty() || !mHfpConnectedDevices.isEmpty());
    }

+58 −24
Original line number Diff line number Diff line
@@ -416,34 +416,68 @@ public class HearingAidService extends ProfileService {
    /**
     * Set the active device.
     * @param device the new active device
     * @return true on success, otherwise false
     */
    public void setActiveDevice(BluetoothDevice device) {
    public boolean setActiveDevice(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        if (DBG) {
            Log.d(TAG, "setActiveDevice:" + device);
        }
        synchronized (mStateMachines) {
            if (device == null) {
                if (mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                    reportActiveDevice(null);
                    mActiveDeviceHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
                }
            return;
                return true;
            }
            if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                Log.e(TAG, "setActiveDevice(" + device + "): failed because device not connected");
                return false;
            }
            Long deviceHiSyncId = mDeviceHiSyncIdMap.getOrDefault(device,
                    BluetoothHearingAid.HI_SYNC_ID_INVALID);
            if (deviceHiSyncId != mActiveDeviceHiSyncId) {
            reportActiveDevice(device);
                mActiveDeviceHiSyncId = deviceHiSyncId;
                reportActiveDevice(device);
            }
        }
        return true;
    }

    boolean isActiveDevice(BluetoothDevice device) {
    /**
     * Get the connected physical Hearing Aid devices that are active
     *
     * @return the list of active devices. The first element is the left active
     * device; the second element is the right active device. If either or both side
     * is not active, it will be null on that position
     */
    List<BluetoothDevice> getActiveDevices() {
        if (DBG) {
            Log.d(TAG, "isActiveDevice:" + device);
            Log.d(TAG, "getActiveDevices");
        }
        ArrayList<BluetoothDevice> activeDevices = new ArrayList<>();
        activeDevices.add(null);
        activeDevices.add(null);
        synchronized (mStateMachines) {
            if (mActiveDeviceHiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                return activeDevices;
            }
            for (BluetoothDevice device : mDeviceHiSyncIdMap.keySet()) {
                if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                    continue;
                }
                if (mDeviceHiSyncIdMap.get(device) == mActiveDeviceHiSyncId) {
                    int deviceSide = getCapabilities(device) & 1;
                    if (deviceSide == BluetoothHearingAid.SIDE_RIGHT) {
                        activeDevices.set(1, device);
                    } else {
                        activeDevices.set(0, device);
                    }
        return getConnectionState(device) == BluetoothProfile.STATE_CONNECTED
                && mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID
                && mActiveDeviceHiSyncId == mDeviceHiSyncIdMap.getOrDefault(device,
                BluetoothHearingAid.HI_SYNC_ID_INVALID);
                }
            }
        }
        return activeDevices;
    }

    void messageFromNative(HearingAidStackEvent stackEvent) {
@@ -718,21 +752,21 @@ public class HearingAidService extends ProfileService {
        }

        @Override
        public void setActiveDevice(BluetoothDevice device) {
        public boolean setActiveDevice(BluetoothDevice device) {
            HearingAidService service = getService();
            if (service == null) {
                return;
                return false;
            }
            service.setActiveDevice(device);
            return service.setActiveDevice(device);
        }

        @Override
        public boolean isActiveDevice(BluetoothDevice device) {
        public List<BluetoothDevice> getActiveDevices() {
            HearingAidService service = getService();
            if (service == null) {
                return false;
                return new ArrayList<>();
            }
            return service.isActiveDevice(device);
            return service.getActiveDevices();
        }

        @Override
+15 −15
Original line number Diff line number Diff line
@@ -614,23 +614,23 @@ public class HearingAidServiceTest {

        generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
        Assert.assertTrue(mService.isActiveDevice(mRightDevice));
        Assert.assertFalse(mService.isActiveDevice(mLeftDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice));

        generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
        Assert.assertTrue(mService.isActiveDevice(mRightDevice));
        Assert.assertTrue(mService.isActiveDevice(mLeftDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice));

        generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTED);
        Assert.assertFalse(mService.isActiveDevice(mRightDevice));
        Assert.assertTrue(mService.isActiveDevice(mLeftDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice));

        generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTED);
        Assert.assertFalse(mService.isActiveDevice(mRightDevice));
        Assert.assertFalse(mService.isActiveDevice(mLeftDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice));
    }

    @Test
@@ -642,19 +642,19 @@ public class HearingAidServiceTest {

        generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
        Assert.assertTrue(mService.isActiveDevice(mRightDevice));
        Assert.assertFalse(mService.isActiveDevice(mLeftDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice));

        generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
        Assert.assertTrue(mService.isActiveDevice(mRightDevice));
        Assert.assertTrue(mService.isActiveDevice(mLeftDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice));

        generateConnectionMessageFromNative(mSingleDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
        Assert.assertFalse(mService.isActiveDevice(mRightDevice));
        Assert.assertFalse(mService.isActiveDevice(mLeftDevice));
        Assert.assertTrue(mService.isActiveDevice(mSingleDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice));
        Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice));
        Assert.assertTrue(mService.getActiveDevices().contains(mSingleDevice));
    }

    private void connectDevice(BluetoothDevice device) {