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

Commit 84efe977 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "AudioService: refactor BT profile management" into udc-qpr-dev

parents a41d6096 57a046e7
Loading
Loading
Loading
Loading
+17 −33
Original line number Diff line number Diff line
@@ -257,24 +257,19 @@ public class AudioDeviceBroker {
        sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE);
    }

    /*package*/ void disconnectAllBluetoothProfiles() {
        synchronized (mDeviceStateLock) {
            mBtHelper.disconnectAllBluetoothProfiles();
        }
    }

    /**
     * Handle BluetoothHeadset intents where the action is one of
     *   {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or
     *   {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}.
     * @param intent
     */
    /*package*/ void receiveBtEvent(@NonNull Intent intent) {
        synchronized (mSetModeLock) {
            synchronized (mDeviceStateLock) {
                mBtHelper.receiveBtEvent(intent);
            }
    private void onReceiveBtEvent(@NonNull Intent intent) {
        mBtHelper.onReceiveBtEvent(intent);
    }

    @GuardedBy("mDeviceStateLock")
    /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
        mBtHelper.onSetBtScoActiveDevice(btDevice);
    }

    /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
@@ -1404,14 +1399,14 @@ public class AudioDeviceBroker {
        sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT, SENDMSG_QUEUE, info);
    }

    /*package*/ void postScoAudioStateChanged(int state) {
        sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
    }

    /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
        sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice);
    }

    /*package*/ void postReceiveBtEvent(Intent intent) {
        sendLMsgNoDelay(MSG_L_RECEIVED_BT_EVENT, SENDMSG_QUEUE, intent);
    }

    /*package*/ static final class CommunicationDeviceInfo {
        final @NonNull IBinder mCb; // Identifies the requesting client for death handler
        final int mUid; // Requester UID
@@ -1807,10 +1802,10 @@ public class AudioDeviceBroker {
                    }
                    break;

                case MSG_I_SCO_AUDIO_STATE_CHANGED:
                case MSG_L_RECEIVED_BT_EVENT:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            mBtHelper.onScoAudioStateChanged(msg.arg1);
                            onReceiveBtEvent((Intent) msg.obj);
                        }
                    }
                    break;
@@ -1821,29 +1816,17 @@ public class AudioDeviceBroker {
                    }
                    break;
                case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
                    if (msg.arg1 != BluetoothProfile.HEADSET) {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            mBtHelper.onBtProfileDisconnected(msg.arg1);
                            mDeviceInventory.onBtProfileDisconnected(msg.arg1);
                        }
                    } else {
                        synchronized (mSetModeLock) {
                            synchronized (mDeviceStateLock) {
                                mBtHelper.disconnectHeadset();
                            }
                        }
                    }
                    break;
                case MSG_IL_BT_SERVICE_CONNECTED_PROFILE:
                    if (msg.arg1 != BluetoothProfile.HEADSET) {
                        synchronized (mDeviceStateLock) {
                            mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj);
                        }
                    } else {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                                mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
                            }
                            mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj);
                        }
                    }
                    break;
@@ -1978,7 +1961,6 @@ public class AudioDeviceBroker {

    private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
    private static final int MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
    private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;

    private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
    //
@@ -1994,6 +1976,8 @@ public class AudioDeviceBroker {

    private static final int MSG_PERSIST_AUDIO_DEVICE_SETTINGS = 54;

    private static final int MSG_L_RECEIVED_BT_EVENT = 55;

    private static boolean isMessageHandledUnderWakelock(int msgId) {
        switch(msgId) {
            case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
+23 −1
Original line number Diff line number Diff line
@@ -1489,8 +1489,12 @@ public class AudioDeviceInventory {
        }
    }

    /*package*/ synchronized void onBtProfileDisconnected(int profile) {
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ void onBtProfileDisconnected(int profile) {
        switch (profile) {
            case BluetoothProfile.HEADSET:
                disconnectHeadset();
                break;
            case BluetoothProfile.A2DP:
                disconnectA2dp();
                break;
@@ -1550,6 +1554,24 @@ public class AudioDeviceInventory {
        disconnectLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
    }

    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    private void disconnectHeadset() {
        boolean disconnect = false;
        synchronized (mDevicesLock) {
            for (DeviceInfo di : mConnectedDevices.values()) {
                if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
                    // There is only one HFP active device and setting the active
                    // device to null will disconnect both in and out devices
                    disconnect = true;
                    break;
                }
            }
        }
        if (disconnect) {
            mDeviceBroker.onSetBtScoActiveDevice(null);
        }
    }

    // must be called before removing the device from mConnectedDevices
    // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
    // from AudioSystem
+1 −12
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ import android.app.NotificationManager;
import android.app.UidObserver;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
@@ -1366,7 +1365,6 @@ public class AudioService extends IAudioService.Stub
        intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
        intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        intentFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -9570,7 +9568,7 @@ public class AudioService extends IAudioService.Stub
                mDockState = dockState;
            } else if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)
                    || action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                mDeviceBroker.receiveBtEvent(intent);
                mDeviceBroker.postReceiveBtEvent(intent);
            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                if (mMonitorRotation) {
                    RotationHelper.enable();
@@ -9638,15 +9636,6 @@ public class AudioService extends IAudioService.Stub
                } catch (IllegalArgumentException e) {
                    Slog.w(TAG, "Failed to apply DISALLOW_RECORD_AUDIO restriction: " + e);
                }
            } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
                sDeviceLogger.enqueue(new EventLogger.StringEvent(
                        "BluetoothAdapter ACTION_STATE_CHANGED with state " + state));
                if (state == BluetoothAdapter.STATE_OFF ||
                        state == BluetoothAdapter.STATE_TURNING_OFF) {
                    mDeviceBroker.disconnectAllBluetoothProfiles();
                }
            } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
                    action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
                handleAudioEffectBroadcast(context, intent);
+52 −56
Original line number Diff line number Diff line
@@ -191,10 +191,14 @@ public class BtHelper {
        if (adapter != null) {
            adapter.getProfileProxy(mDeviceBroker.getContext(),
                    mBluetoothProfileServiceListener, BluetoothProfile.A2DP);
            adapter.getProfileProxy(mDeviceBroker.getContext(),
                    mBluetoothProfileServiceListener, BluetoothProfile.A2DP_SINK);
            adapter.getProfileProxy(mDeviceBroker.getContext(),
                    mBluetoothProfileServiceListener, BluetoothProfile.HEARING_AID);
            adapter.getProfileProxy(mDeviceBroker.getContext(),
                    mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO);
            adapter.getProfileProxy(mDeviceBroker.getContext(),
                    mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
        }
    }

@@ -261,27 +265,27 @@ public class BtHelper {

    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void receiveBtEvent(Intent intent) {
    /*package*/ synchronized void onReceiveBtEvent(Intent intent) {
        final String action = intent.getAction();

        Log.i(TAG, "receiveBtEvent action: " + action + " mScoAudioState: " + mScoAudioState);
        Log.i(TAG, "onReceiveBtEvent action: " + action + " mScoAudioState: " + mScoAudioState);
        if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
            setBtScoActiveDevice(btDevice);
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE,
                    android.bluetooth.BluetoothDevice.class);
            onSetBtScoActiveDevice(btDevice);
        } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
            int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
            Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
            mDeviceBroker.postScoAudioStateChanged(btState);
            onScoAudioStateChanged(btState);
        }
    }

    /**
     * Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED
     * Exclusively called from AudioDeviceBroker when handling MSG_L_RECEIVED_BT_EVENT
     * as part of the serialization of the communication route selection
     */
    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    void onScoAudioStateChanged(int state) {
    private void onScoAudioStateChanged(int state) {
        boolean broadcast = false;
        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
        switch (state) {
@@ -294,10 +298,10 @@ public class BtHelper {
                    // broadcast intent if the connection was initated by AudioService
                    broadcast = true;
                }
                mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
                mDeviceBroker.setBluetoothScoOn(true, "BtHelper.onScoAudioStateChanged");
                break;
            case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
                mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
                mDeviceBroker.setBluetoothScoOn(false, "BtHelper.onScoAudioStateChanged");
                scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
                // There are two cases where we want to immediately reconnect audio:
                // 1) If a new start request was received while disconnecting: this was
@@ -431,15 +435,6 @@ public class BtHelper {
        mScoConnectionState = state;
    }

    /*package*/ synchronized void disconnectAllBluetoothProfiles() {
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP);
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP_SINK);
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEADSET);
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEARING_AID);
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO);
        mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO_BROADCAST);
    }

    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void resetBluetoothSco() {
@@ -450,18 +445,14 @@ public class BtHelper {
        mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
    }

    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void disconnectHeadset() {
        setBtScoActiveDevice(null);
        mBluetoothHeadset = null;
    }

    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onBtProfileDisconnected(int profile) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile) + " disconnected"));
        switch (profile) {
            case BluetoothProfile.HEADSET:
                mBluetoothHeadset = null;
                break;
            case BluetoothProfile.A2DP:
                mA2dp = null;
                break;
@@ -471,14 +462,10 @@ public class BtHelper {
            case BluetoothProfile.LE_AUDIO:
                mLeAudio = null;
                break;

            case BluetoothProfile.A2DP_SINK:
            case BluetoothProfile.LE_AUDIO_BROADCAST:
                // shouldn't be received here as profile doesn't involve BtHelper
                Log.e(TAG, "onBtProfileDisconnected: Not a profile handled by BtHelper "
                        + BluetoothProfile.getProfileName(profile));
                // nothing to do in BtHelper
                break;

            default:
                // Not a valid profile to disconnect
                Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect "
@@ -492,17 +479,31 @@ public class BtHelper {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
                + proxy));
        if (profile == BluetoothProfile.HEADSET) {
        switch (profile) {
            case BluetoothProfile.HEADSET:
                onHeadsetProfileConnected((BluetoothHeadset) proxy);
                return;
        }
        if (profile == BluetoothProfile.A2DP) {
            case BluetoothProfile.A2DP:
                mA2dp = (BluetoothA2dp) proxy;
        } else if (profile == BluetoothProfile.HEARING_AID) {
                break;
            case BluetoothProfile.HEARING_AID:
                mHearingAid = (BluetoothHearingAid) proxy;
        } else if (profile == BluetoothProfile.LE_AUDIO) {
                break;
            case BluetoothProfile.LE_AUDIO:
                mLeAudio = (BluetoothLeAudio) proxy;
                break;
            case BluetoothProfile.A2DP_SINK:
            case BluetoothProfile.LE_AUDIO_BROADCAST:
                // nothing to do in BtHelper
                return;
            default:
                // Not a valid profile to connect
                Log.e(TAG, "onBtProfileConnected: Not a valid profile to connect "
                        + BluetoothProfile.getProfileName(profile));
                break;
        }

        // this part is only for A2DP, LE Audio unicast and Hearing aid
        final List<BluetoothDevice> deviceList = proxy.getConnectedDevices();
        if (deviceList.isEmpty()) {
            return;
@@ -523,7 +524,7 @@ public class BtHelper {

    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
    private void onHeadsetProfileConnected(BluetoothHeadset headset) {
        // Discard timeout message
        mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
        mBluetoothHeadset = headset;
@@ -532,7 +533,7 @@ public class BtHelper {
        if (adapter != null) {
            activeDevices = adapter.getActiveDevices(BluetoothProfile.HEADSET);
        }
        setBtScoActiveDevice((activeDevices.size() > 0) ? activeDevices.get(0) : null);
        onSetBtScoActiveDevice((activeDevices.size() > 0) ? activeDevices.get(0) : null);
        // Refresh SCO audio state
        checkScoAudioState();
        if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
@@ -643,20 +644,19 @@ public class BtHelper {

    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    @GuardedBy("BtHelper.this")
    private void setBtScoActiveDevice(BluetoothDevice btDevice) {
        Log.i(TAG, "setBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
    /*package */ synchronized void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
        Log.i(TAG, "onSetBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
                + " -> " + getAnonymizedAddress(btDevice));
        final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
        if (Objects.equals(btDevice, previousActiveDevice)) {
            return;
        }
        if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
            Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
            Log.w(TAG, "onSetBtScoActiveDevice() failed to remove previous device "
                    + getAnonymizedAddress(previousActiveDevice));
        }
        if (!handleBtScoActiveDeviceChange(btDevice, true)) {
            Log.e(TAG, "setBtScoActiveDevice() failed to add new device "
            Log.e(TAG, "onSetBtScoActiveDevice() failed to add new device "
                    + getAnonymizedAddress(btDevice));
            // set mBluetoothHeadsetDevice to null when failing to add new device
            btDevice = null;
@@ -677,16 +677,14 @@ public class BtHelper {
                        case BluetoothProfile.HEADSET:
                        case BluetoothProfile.HEARING_AID:
                        case BluetoothProfile.LE_AUDIO:
                        case BluetoothProfile.A2DP_SINK:
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                    "BT profile service: connecting "
                                    + BluetoothProfile.getProfileName(profile) + " profile"));
                            mDeviceBroker.postBtProfileConnected(profile, proxy);
                            break;

                        case BluetoothProfile.A2DP_SINK:
                            // no A2DP sink functionality handled by BtHelper
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            // no broadcast functionality handled by BtHelper
                        default:
                            break;
                    }
@@ -698,16 +696,14 @@ public class BtHelper {
                        case BluetoothProfile.HEADSET:
                        case BluetoothProfile.HEARING_AID:
                        case BluetoothProfile.LE_AUDIO:
                        case BluetoothProfile.A2DP_SINK:
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                    "BT profile service: disconnecting "
                                        + BluetoothProfile.getProfileName(profile) + " profile"));
                            mDeviceBroker.postBtProfileDisconnected(profile);
                            break;

                        case BluetoothProfile.A2DP_SINK:
                            // no A2DP sink functionality handled by BtHelper
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            // no broadcast functionality handled by BtHelper
                        default:
                            break;
                    }