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

Commit 201b3d5b authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

Send active device changed intent after connecting in AudioManager

Change will solve race condition with connecting device in AudioManager
and making active device propagated in system. This should handle audio
lact to earpiece while switching to Hearing Aid from LE audio device,
since both of devices uses communication device API.

Bug: 260223130
Tag: #feature
Test: Switch active devices from Dialer or Cached device list
Change-Id: I1bc10ffbcb380be15c52ca4124a0e91347dc4371
parent e3125b3d
Loading
Loading
Loading
Loading
+71 −6
Original line number Diff line number Diff line
@@ -29,9 +29,13 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ParcelUuid;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -73,6 +77,7 @@ public class HearingAidService extends ProfileService {
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mPreviousAudioDevice;
    private BluetoothDevice mActiveDevice;

    @VisibleForTesting
    HearingAidNativeInterface mHearingAidNativeInterface;
@@ -88,6 +93,12 @@ public class HearingAidService extends ProfileService {

    private BroadcastReceiver mBondStateChangedReceiver;
    private BroadcastReceiver mConnectionStateChangedReceiver;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private final AudioManagerOnAudioDevicesAddedCallback mAudioManagerOnAudioDevicesAddedCallback =
            new AudioManagerOnAudioDevicesAddedCallback();
    private final AudioManagerOnAudioDevicesRemovedCallback
            mAudioManagerOnAudioDevicesRemovedCallback =
            new AudioManagerOnAudioDevicesRemovedCallback();

    private final ServiceFactory mFactory = new ServiceFactory();

@@ -206,6 +217,9 @@ public class HearingAidService extends ProfileService {
            }
        }

        mAudioManager.unregisterAudioDeviceCallback(mAudioManagerOnAudioDevicesAddedCallback);
        mAudioManager.unregisterAudioDeviceCallback(mAudioManagerOnAudioDevicesRemovedCallback);

        // Clear AdapterService, HearingAidNativeInterface
        mAudioManager = null;
        mHearingAidNativeInterface = null;
@@ -593,6 +607,12 @@ public class HearingAidService extends ProfileService {
                }
                return true;
            }

            /* No action needed since this is the same device as previousely activated */
            if (device.equals(mActiveDevice)) {
                return true;
            }

            if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                Log.e(TAG, "setActiveDevice(" + device + "): failed because device not connected");
                return false;
@@ -682,6 +702,46 @@ public class HearingAidService extends ProfileService {
        }
    }

    private void notifyActiveDeviceChanged() {
        Intent intent = new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mActiveDevice);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        sendBroadcast(intent, BLUETOOTH_CONNECT);
    }

    /* Notifications of audio device disconnection events. */
    private class AudioManagerOnAudioDevicesRemovedCallback extends AudioDeviceCallback {
        @Override
        public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
            for (AudioDeviceInfo deviceInfo : removedDevices) {
                if (deviceInfo.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
                    notifyActiveDeviceChanged();
                    if (DBG) {
                        Log.d(TAG, " onAudioDevicesRemoved: device type: " + deviceInfo.getType());
                    }
                    mAudioManager.unregisterAudioDeviceCallback(this);
                }
            }
        }
    }

    /* Notifications of audio device connection events. */
    private class AudioManagerOnAudioDevicesAddedCallback extends AudioDeviceCallback {
        @Override
        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
            for (AudioDeviceInfo deviceInfo : addedDevices) {
                if (deviceInfo.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
                    notifyActiveDeviceChanged();
                    if (DBG) {
                        Log.d(TAG, " onAudioDevicesAdded: device type: " + deviceInfo.getType());
                    }
                    mAudioManager.unregisterAudioDeviceCallback(this);
                }
            }
        }
    }

    private HearingAidStateMachine getOrCreateStateMachine(BluetoothDevice device) {
        if (device == null) {
            Log.e(TAG, "getOrCreateStateMachine failed: device cannot be null");
@@ -717,21 +777,26 @@ public class HearingAidService extends ProfileService {
            Log.d(TAG, "reportActiveDevice(" + device + ")");
        }

        mActiveDevice = device;

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

        Intent intent = new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());

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

        if (device != null) {
            mAudioManager.registerAudioDeviceCallback(mAudioManagerOnAudioDevicesAddedCallback,
                    mHandler);
        } else {
            mAudioManager.registerAudioDeviceCallback(mAudioManagerOnAudioDevicesRemovedCallback,
                    mHandler);
        }

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