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

Commit 8d8a8589 authored by Hyundo Moon's avatar Hyundo Moon
Browse files

Suppress noisy intent when a fallback device exist (HearingAid)

This CL suppress noisy intent when both of conditions met:
 - Currently active Hearing Aid device is disconnected.
 - There is a fallback device.

The music will keep playing in this case.

Bug: 276403929
Test: 1) atest ActiveDeviceManagerTest HearingAidServiceTest \
               HearingAidStateMachineTest;
      2) Manually tested disconnecting active Hearing Aid while another
         A2DP headset is connected. Music kept playing via
         the remaining BT device.
      3) Manually tested selecting phone speaker while playing music
         through Hearing Aid. Music kept playing.
Change-Id: Ibd49d859c33e393f167a7e19d7ae542d6735f909
parent e238a382
Loading
Loading
Loading
Loading
+37 −24
Original line number Diff line number Diff line
@@ -371,7 +371,7 @@ class ActiveDeviceManager {
                }
            } else if (mPendingLeHearingAidActiveDevice.contains(device)) {
                setLeHearingAidActiveDevice(device);
                setHearingAidActiveDevice(null);
                setHearingAidActiveDevice(null, true);
                setA2dpActiveDevice(null, true);
                setHfpActiveDevice(null);
            }
@@ -394,7 +394,7 @@ class ActiveDeviceManager {
            } else {
                // New connected device: select it as active
                setLeHearingAidActiveDevice(device);
                setHearingAidActiveDevice(null);
                setHearingAidActiveDevice(null, true);
                setA2dpActiveDevice(null, true);
                setHfpActiveDevice(null);
            }
@@ -437,10 +437,9 @@ class ActiveDeviceManager {
            }
            mHearingAidConnectedDevices.remove(device);
            if (mHearingAidActiveDevices.remove(device) && mHearingAidActiveDevices.isEmpty()) {
                if (mHearingAidConnectedDevices.isEmpty()) {
                    setHearingAidActiveDevice(null);
                if (!setFallbackDeviceActiveLocked()) {
                    setHearingAidActiveDevice(null, false);
                }
                setFallbackDeviceActiveLocked();
            }
        }
    }
@@ -500,7 +499,7 @@ class ActiveDeviceManager {
            }
            if (!Objects.equals(mA2dpActiveDevice, device)) {
                if (device != null) {
                    setHearingAidActiveDevice(null);
                    setHearingAidActiveDevice(null, true);
                }
                if (Utils.isDualModeAudioEnabled()
                        && mAdapterService.isAllSupportedClassicAudioProfilesActive(device)) {
@@ -534,7 +533,7 @@ class ActiveDeviceManager {
            }
            if (!Objects.equals(mHfpActiveDevice, device)) {
                if (device != null) {
                    setHearingAidActiveDevice(null);
                    setHearingAidActiveDevice(null, true);
                }
                if (Utils.isDualModeAudioEnabled()
                        && mAdapterService.isAllSupportedClassicAudioProfilesActive(device)) {
@@ -590,7 +589,7 @@ class ActiveDeviceManager {
                    setA2dpActiveDevice(null, true);
                    setHfpActiveDevice(null);
                }
                setHearingAidActiveDevice(null);
                setHearingAidActiveDevice(null, true);
            }

            if (mLeHearingAidConnectedDevices.contains(device)) {
@@ -754,18 +753,24 @@ class ActiveDeviceManager {
        }
    }

    private void setHearingAidActiveDevice(BluetoothDevice device) {
        synchronized (mLock) {
    private void setHearingAidActiveDevice(@NonNull BluetoothDevice device) {
        setHearingAidActiveDevice(device, false);
    }

    private void setHearingAidActiveDevice(@Nullable BluetoothDevice device,
            boolean hasFallbackDevice) {
        if (DBG) {
                Log.d(TAG, "setHearingAidActiveDevice(" + device + ")");
            Log.d(TAG, "setHearingAidActiveDevice(" + device + ")"
                    + (device == null ? " hasFallbackDevice=" + hasFallbackDevice : ""));
        }
        synchronized (mLock) {
            final HearingAidService hearingAidService = mFactory.getHearingAidService();
            if (hearingAidService == null) {
                return;
            }

            if (device == null) {
                hearingAidService.setActiveDevice(null);
                hearingAidService.removeActiveDevice(!hasFallbackDevice);
                mHearingAidActiveDevices.clear();
                return;
            }
@@ -870,7 +875,7 @@ class ActiveDeviceManager {
                        Log.d(TAG, "set LE hearing aid device active: " + device);
                    }
                    setLeHearingAidActiveDevice(device);
                    setHearingAidActiveDevice(null);
                    setHearingAidActiveDevice(null, true);
                    setA2dpActiveDevice(null, true);
                    setHfpActiveDevice(null);
                }
@@ -916,14 +921,17 @@ class ActiveDeviceManager {
                        Log.d(TAG, "set A2DP device active: " + device);
                    }
                    setA2dpActiveDevice(device);
                    if (headsetFallbackDevice != null) {
                    if (Objects.equals(headsetFallbackDevice, device)) {
                        setHfpActiveDevice(device);
                    } else {
                        setHfpActiveDevice(null);
                    }
                    /* If dual mode is enabled, LEA will be made active once all supported
                        classic audio profiles are made active for the device. */
                    if (!Utils.isDualModeAudioEnabled()) {
                        setLeAudioActiveDevice(null, true);
                    }
                    }
                    setHearingAidActiveDevice(null, true);
                } else {
                    if (DBG) {
                        Log.d(TAG, "set LE audio device active: " + device);
@@ -933,6 +941,7 @@ class ActiveDeviceManager {
                        setA2dpActiveDevice(null, true);
                        setHfpActiveDevice(null);
                    }
                    setHearingAidActiveDevice(null, true);
                }
            } else {
                if (Objects.equals(headsetFallbackDevice, device)) {
@@ -940,12 +949,15 @@ class ActiveDeviceManager {
                        Log.d(TAG, "set HFP device active: " + device);
                    }
                    setHfpActiveDevice(device);
                    if (a2dpFallbackDevice != null) {
                    if (Objects.equals(a2dpFallbackDevice, device)) {
                        setA2dpActiveDevice(a2dpFallbackDevice);
                    } else {
                        setA2dpActiveDevice(null, true);
                    }
                    if (!Utils.isDualModeAudioEnabled()) {
                        setLeAudioActiveDevice(null, true);
                    }
                    }
                    setHearingAidActiveDevice(null, true);
                } else {
                    if (DBG) {
                        Log.d(TAG, "set LE audio device active: " + device);
@@ -955,6 +967,7 @@ class ActiveDeviceManager {
                        setA2dpActiveDevice(null, true);
                        setHfpActiveDevice(null);
                    }
                    setHearingAidActiveDevice(null, true);
                }
            }
            return true;
@@ -1029,7 +1042,7 @@ class ActiveDeviceManager {
        }
        setA2dpActiveDevice(null, true);
        setHfpActiveDevice(null);
        setHearingAidActiveDevice(null);
        setHearingAidActiveDevice(null, true);
        setLeAudioActiveDevice(null, true);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -5348,8 +5348,12 @@ public class AdapterService extends Service {
                || mHearingAidService.getConnectionPolicy(device)
                == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
            Log.i(TAG, "setActiveDevice: Setting active Hearing Aid " + device);
            if (device == null) {
                mHearingAidService.removeActiveDevice(false);
            } else {
                mHearingAidService.setActiveDevice(device);
            }
        }

        if (setHeadset && mHeadsetService != null && (device == null
                || mHeadsetService.getConnectionPolicy(device)
+57 −44
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ public class HearingAidService extends ProfileService {
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mPreviousAudioDevice;
    private BluetoothDevice mActiveDevice;

    @VisibleForTesting
@@ -96,7 +95,6 @@ public class HearingAidService extends ProfileService {
    private long mActiveDeviceHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;

    private BroadcastReceiver mBondStateChangedReceiver;
    private BroadcastReceiver mConnectionStateChangedReceiver;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private final AudioManagerOnAudioDevicesAddedCallback mAudioManagerOnAudioDevicesAddedCallback =
            new AudioManagerOnAudioDevicesAddedCallback();
@@ -158,8 +156,6 @@ public class HearingAidService extends ProfileService {
        registerReceiver(mBondStateChangedReceiver, filter);
        filter = new IntentFilter();
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
        registerReceiver(mConnectionStateChangedReceiver, filter);

        // Mark service as started
        setHearingAidService(this);
@@ -194,8 +190,6 @@ public class HearingAidService extends ProfileService {
        // Unregister broadcast receivers
        unregisterReceiver(mBondStateChangedReceiver);
        mBondStateChangedReceiver = null;
        unregisterReceiver(mConnectionStateChangedReceiver);
        mConnectionStateChangedReceiver = null;

        // Destroy state machines and stop handler thread
        synchronized (mStateMachines) {
@@ -609,25 +603,44 @@ public class HearingAidService extends ProfileService {
    }

    /**
     * Set the active device.
     * @param device the new active device
     * Remove the active device.
     *
     * @param stopAudio whether to stop current media playback.
     * @return true on success, otherwise false
     */
    public boolean setActiveDevice(BluetoothDevice device) {
    public boolean removeActiveDevice(boolean stopAudio) {
        if (DBG) {
            Log.d(TAG, "setActiveDevice:" + device);
            Log.d(TAG, "removeActiveDevice: stopAudio=" + stopAudio);
        }
        synchronized (mStateMachines) {
            if (device == null) {
            if (mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                    reportActiveDevice(null);
                reportActiveDevice(null, stopAudio);
                mActiveDeviceHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
            }
        }
        return true;
    }

    /**
     * Set the active device.
     *
     * @param device the new active device. Should not be null.
     * @return true on success, otherwise false
     */
    public boolean setActiveDevice(BluetoothDevice device) {
        if (device == null) {
            Log.e(TAG, "setActiveDevice: device should not be null!");
            return removeActiveDevice(true);
        }
        if (DBG) {
            Log.d(TAG, "setActiveDevice: " + device);
        }
        synchronized (mStateMachines) {
            /* No action needed since this is the same device as previousely activated */
            if (device.equals(mActiveDevice)) {
                if (DBG) {
                    Log.d(TAG, "setActiveDevice: The device is already active. Ignoring.");
                }
                return true;
            }

@@ -639,7 +652,7 @@ public class HearingAidService extends ProfileService {
                    BluetoothHearingAid.HI_SYNC_ID_INVALID);
            if (deviceHiSyncId != mActiveDeviceHiSyncId) {
                mActiveDeviceHiSyncId = deviceHiSyncId;
                reportActiveDevice(device);
                reportActiveDevice(device, false);
            }
        }
        return true;
@@ -653,9 +666,6 @@ public class HearingAidService extends ProfileService {
     * is not active, it will be null on that position
     */
    public List<BluetoothDevice> getActiveDevices() {
        if (DBG) {
            Log.d(TAG, "getActiveDevices");
        }
        ArrayList<BluetoothDevice> activeDevices = new ArrayList<>();
        activeDevices.add(null);
        activeDevices.add(null);
@@ -788,23 +798,38 @@ public class HearingAidService extends ProfileService {

    /**
     * Report the active device change to the active device manager and the media framework.
     *
     * @param device the new active device; or null if no active device
     * @param stopAudio whether to stop audio when device is null.
     */
    private void reportActiveDevice(BluetoothDevice device) {
    private void reportActiveDevice(BluetoothDevice device, boolean stopAudio) {
        if (DBG) {
            Log.d(TAG, "reportActiveDevice(" + device + ")");
            Log.d(TAG, "reportActiveDevice: device=" + device + " stopAudio=" + stopAudio);
        }

        if (device != null && stopAudio) {
            Log.e(TAG, "Illegal arguments: stopAudio should be false when device is not null!");
            stopAudio = false;
        }

        // Note: This is just a safety check for handling illegal call - setActiveDevice(null).
        if (device == null && stopAudio
                && getConnectionState(mActiveDevice) == BluetoothProfile.STATE_CONNECTED) {
            Log.e(TAG, "Illegal arguments: stopAudio should be false when the active hearing aid "
                    + "is still connected!");
            stopAudio = false;
        }

        BluetoothDevice previousAudioDevice = mActiveDevice;

        mActiveDevice = device;

        BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_ACTIVE_DEVICE_CHANGED,
                BluetoothProfile.HEARING_AID, mAdapterService.obfuscateAddress(device),
                mAdapterService.getMetricId(device));

        boolean stopAudio = device == null
                && (getConnectionState(mPreviousAudioDevice) != BluetoothProfile.STATE_CONNECTED);
        if (DBG) {
            Log.d(TAG, "Hearing Aid audio: " + mPreviousAudioDevice + " -> " + device
            Log.d(TAG, "Hearing Aid audio: " + previousAudioDevice + " -> " + device
                    + ". Stop audio: " + stopAudio);
        }

@@ -816,9 +841,8 @@ public class HearingAidService extends ProfileService {
                    mHandler);
        }

        mAudioManager.handleBluetoothActiveDeviceChanged(device, mPreviousAudioDevice,
        mAudioManager.handleBluetoothActiveDeviceChanged(device, previousAudioDevice,
                BluetoothProfileConnectionInfo.createHearingAidInfo(!stopAudio));
        mPreviousAudioDevice = device;
    }

    // Remove state machine if the bonding for a device is removed
@@ -895,8 +919,6 @@ public class HearingAidService extends ProfileService {
        return result;
    }

    @VisibleForTesting
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    synchronized void connectionStateChanged(BluetoothDevice device, int fromState,
                                                     int toState) {
        if ((device == null) || (fromState == toState)) {
@@ -918,9 +940,9 @@ public class HearingAidService extends ProfileService {
            }
        }
        if (fromState == BluetoothProfile.STATE_CONNECTED && getConnectedDevices().isEmpty()) {
            setActiveDevice(null);
            long myHiSyncId = getHiSyncId(device);
            mHiSyncIdConnectedMap.put(myHiSyncId, false);
            // ActiveDeviceManager will call removeActiveDevice().
        }
        // Check if the device is disconnected - if unbond, remove the state machine
        if (toState == BluetoothProfile.STATE_DISCONNECTED) {
@@ -934,19 +956,6 @@ public class HearingAidService extends ProfileService {
        }
    }

    private class ConnectionStateChangedReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
                return;
            }
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            int toState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
            int fromState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
            connectionStateChanged(device, fromState, toState);
        }
    }

    /**
     * Binder object: must be a static class or memory leak may occur
     */
@@ -1061,8 +1070,12 @@ public class HearingAidService extends ProfileService {
                HearingAidService service = getService(source);
                boolean result = false;
                if (service != null) {
                    if (device == null) {
                        result = service.removeActiveDevice(false);
                    } else {
                        result = service.setActiveDevice(device);
                    }
                }
                receiver.send(result);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
+2 −0
Original line number Diff line number Diff line
@@ -520,6 +520,8 @@ final class HearingAidStateMachine extends StateMachine {
        log("Connection state " + mDevice + ": " + profileStateToString(prevState)
                    + "->" + profileStateToString(newState));

        mService.connectionStateChanged(mDevice, prevState, newState);

        Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
+1 −1
Original line number Diff line number Diff line
@@ -991,7 +991,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                A2dpService.getA2dpService().removeActiveDevice(false);
            }
            if (mAdapterService.getActiveDevices(BluetoothProfile.HEARING_AID).size() > 0) {
                HearingAidService.getHearingAidService().setActiveDevice(null);
                HearingAidService.getHearingAidService().removeActiveDevice(false);
            }
            if (mLeAudioService == null) {
                mLeAudioService = LeAudioService.getLeAudioService();
Loading