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

Commit 94610acf authored by wescande's avatar wescande Committed by William Escande
Browse files

A2DP switch device refactor

Replace 3 hidden api by a common one.

Test: Manual
Tag: #refactor
Bug: 190422401
Merged-In: I21bd61187a8f2490c3345a61974e0a1f1563637f
Change-Id: I21bd61187a8f2490c3345a61974e0a1f1563637f
parent d51bc18a
Loading
Loading
Loading
Loading
+17 −21
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.BtProfileConnectionInfo;
import android.os.HandlerThread;
import android.util.Log;

@@ -462,13 +463,10 @@ public class A2dpService extends ProfileService {
            // device, the user has explicitly switched the output to the local device and music
            // should continue playing. Otherwise, the remote device has been indeed disconnected
            // and audio should be suspended before switching the output to the local device.
            boolean suppressNoisyIntent = !forceStopPlayingAudio
                    && (getConnectionState(previousActiveDevice)
                    == BluetoothProfile.STATE_CONNECTED);
            Log.i(TAG, "removeActiveDevice: suppressNoisyIntent=" + suppressNoisyIntent);
            mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
                    previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
                    BluetoothProfile.A2DP, suppressNoisyIntent, -1);
            boolean stopAudio = forceStopPlayingAudio || (getConnectionState(previousActiveDevice)
                        != BluetoothProfile.STATE_CONNECTED);
            mAudioManager.handleBluetoothActiveDeviceChanged(null, previousActiveDevice,
                    BtProfileConnectionInfo.a2dpInfo(!stopAudio, -1));

            synchronized (mStateMachines) {
                // Make sure the Active device in native layer is set to null and audio is off
@@ -552,13 +550,6 @@ public class A2dpService extends ProfileService {
            // This needs to happen before we inform the audio manager that the device
            // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why.
            updateAndBroadcastActiveDevice(device);
            // Make sure the Audio Manager knows the previous Active device is disconnected,
            // and the new Active device is connected.
            if (previousActiveDevice != null) {
                mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
                        previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
                        BluetoothProfile.A2DP, true, -1);
            }

            BluetoothDevice newActiveDevice = null;
            synchronized (mStateMachines) {
@@ -583,13 +574,13 @@ public class A2dpService extends ProfileService {
                rememberedVolume = mFactory.getAvrcpTargetService()
                        .getRememberedVolumeForDevice(newActiveDevice);
            }
            mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
                    newActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
                    true, rememberedVolume);
            // Inform the Audio Service about the codec configuration
            // Make sure the Audio Manager knows the previous Active device is disconnected,
            // and the new Active device is connected.
            // And inform the Audio Service about the codec configuration
            // change, so the Audio Service can reset accordingly the audio
            // feeding parameters in the Audio HAL to the Bluetooth stack.
            mAudioManager.handleBluetoothA2dpDeviceConfigChange(newActiveDevice);
            mAudioManager.handleBluetoothActiveDeviceChanged(newActiveDevice, previousActiveDevice,
                    BtProfileConnectionInfo.a2dpInfo(true, rememberedVolume));
        }
        return true;
    }
@@ -972,8 +963,13 @@ public class A2dpService extends ProfileService {
        // Inform the Audio Service about the codec configuration change,
        // so the Audio Service can reset accordingly the audio feeding
        // parameters in the Audio HAL to the Bluetooth stack.
        if (isActiveDevice(device) && !sameAudioFeedingParameters) {
            mAudioManager.handleBluetoothA2dpDeviceConfigChange(device);
        // Until we are able to detect from device_port_proxy if the config has changed or not,
        // the Bluetooth stack can only disable the audio session and need to ask audioManager to
        // restart the session even if feeding parameter are the same. (sameAudioFeedingParameters
        // is left unused until there)
        if (isActiveDevice(device)) {
            mAudioManager.handleBluetoothActiveDeviceChanged(device, device,
                    BtProfileConnectionInfo.a2dpInfo(false, -1));
        }
    }

+9 −23
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.BtProfileConnectionInfo;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.util.Log;
@@ -694,31 +695,16 @@ public class HearingAidService extends ProfileService {
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());

        if (device == null) {
            if (DBG) {
                Log.d(TAG, "Set Hearing Aid audio to disconnected");
            }
            boolean suppressNoisyIntent =
                    (getConnectionState(mPreviousAudioDevice) == BluetoothProfile.STATE_CONNECTED);
            mAudioManager.setBluetoothHearingAidDeviceConnectionState(
                    mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
                    suppressNoisyIntent, 0);
            mPreviousAudioDevice = null;
        } else {
        boolean stopAudio = device == null
                && (getConnectionState(mPreviousAudioDevice) != BluetoothProfile.STATE_CONNECTED);
        if (DBG) {
                Log.d(TAG, "Set Hearing Aid audio to connected");
            Log.d(TAG, "Hearing Aid audio: " + mPreviousAudioDevice + " -> " + device
                    + ". Stop audio: " + stopAudio);
        }
            if (mPreviousAudioDevice != null) {
                mAudioManager.setBluetoothHearingAidDeviceConnectionState(
                        mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
                        true, 0);
            }
            mAudioManager.setBluetoothHearingAidDeviceConnectionState(
                    device, BluetoothProfile.STATE_CONNECTED,
                    true, 0);
        mAudioManager.handleBluetoothActiveDeviceChanged(device, mPreviousAudioDevice,
                BtProfileConnectionInfo.hearingAidInfo(!stopAudio));
        mPreviousAudioDevice = device;
    }
    }

    // Remove state machine if the bonding for a device is removed
    private class BondStateChangedReceiver extends BroadcastReceiver {
+58 −70
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.media.AudioManager;
import android.media.BtProfileConnectionInfo;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelUuid;
@@ -93,8 +94,8 @@ public class LeAudioService extends ProfileService {
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mPreviousAudioOutDevice;
    private BluetoothDevice mPreviousAudioInDevice;
    private BluetoothDevice mActiveAudioOutDevice;
    private BluetoothDevice mActiveAudioInDevice;
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
@@ -664,49 +665,44 @@ public class LeAudioService extends ProfileService {
        boolean newSupportedByDeviceInput = (newSupportedAudioDirections
                & AUDIO_DIRECTION_INPUT_BIT) != 0;

        if (device != null && mPreviousAudioInDevice != null) {
            int previousGroupId = getGroupId(mPreviousAudioInDevice);
        if (device != null && mActiveAudioInDevice != null) {
            int previousGroupId = getGroupId(mActiveAudioInDevice);
            if (previousGroupId == groupId) {
                /* This is thes same group as aleady notified to the system.
                * Therefore do not change the device we have connected to the group,
                * unless, previous one is disconnected now
                */
                if (mPreviousAudioInDevice.isConnected())
                    device = mPreviousAudioInDevice;
                if (mActiveAudioInDevice.isConnected()) {
                    device = mActiveAudioInDevice;
                }
            }

        /* Disconnect input:
         * - If active input device changed (to none or any)
         * - If device stops supporting input
         */
        boolean inActiveDeviceReplace = (device != mPreviousAudioInDevice);
        if (inActiveDeviceReplace && (mPreviousAudioInDevice != null)) {
            mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                    mPreviousAudioInDevice, BluetoothProfile.STATE_DISCONNECTED);
        }

        mPreviousAudioInDevice = device;
        BluetoothDevice previousInDevice = mActiveAudioInDevice;

        if (device == null) {
            Log.d(TAG,  " device is null.");
            return inActiveDeviceReplace;
        }

        if (inActiveDeviceReplace == false ||
             (oldSupportedByDeviceInput == newSupportedByDeviceInput)) {
            Log.d(TAG,  " Nothing to do.");
            return inActiveDeviceReplace;
        /*
         * Do not update input if neither previous nor current device support input
         */
        if (!oldSupportedByDeviceInput && !newSupportedByDeviceInput) {
            Log.d(TAG, "updateActiveInDevice: Device does not support input.");
            return false;
        }

        /* Connect input:
         * - If active input device changed
         * - If device starts support input
        /*
         * Update input if:
         * - Device changed
         *     OR
         * - Device stops / starts supporting input
         */
        mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                   device, BluetoothProfile.STATE_CONNECTED);

        return inActiveDeviceReplace;
        if (!Objects.equals(device, previousInDevice)
                || (oldSupportedByDeviceInput != newSupportedByDeviceInput)) {
            mActiveAudioInDevice = newSupportedByDeviceInput ? device : null;
            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice, previousInDevice,
                    BtProfileConnectionInfo.leAudio(false, false));
            return true;
        }
        Log.d(TAG, "updateActiveInDevice: Nothing to do.");
        return false;
    }

    private boolean updateActiveOutDevice(BluetoothDevice device, Integer groupId,
@@ -722,53 +718,46 @@ public class LeAudioService extends ProfileService {
        boolean newSupportedByDeviceOutput = (newSupportedAudioDirections
                & AUDIO_DIRECTION_OUTPUT_BIT) != 0;


        if (device != null && mPreviousAudioOutDevice != null) {
            int previousGroupId = getGroupId(mPreviousAudioOutDevice);
        if (device != null && mActiveAudioOutDevice != null) {
            int previousGroupId = getGroupId(mActiveAudioOutDevice);
            if (previousGroupId == groupId) {
                /* This is the same group as already notified to the system.
                * Therefore do not change the device we have connected to the group,
                * unless, previous one is disconnected now
                */
             if (mPreviousAudioOutDevice.isConnected())
                device = mPreviousAudioOutDevice;
                if (mActiveAudioOutDevice.isConnected()) {
                    device = mActiveAudioOutDevice;
                }
            }

         /* Disconnect output:
         * - If active output device changed (to none or any)
         * - If device stops supporting output
         */
        boolean outActiveDeviceReplace = (device != mPreviousAudioOutDevice);
        if (outActiveDeviceReplace && (mPreviousAudioOutDevice != null)) {
            boolean suppressNoisyIntent =
                    (getConnectionState(mPreviousAudioOutDevice) ==
                    BluetoothProfile.STATE_CONNECTED);
            mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
                    mPreviousAudioOutDevice, BluetoothProfile.STATE_DISCONNECTED,
                    suppressNoisyIntent);
        }

        mPreviousAudioOutDevice = device;
        BluetoothDevice previousOutDevice = mActiveAudioOutDevice;

        if (device == null) {
            Log.d(TAG,  " device is null.");
            return outActiveDeviceReplace;
        }

        if (outActiveDeviceReplace == false ||
            (oldSupportedByDeviceOutput == newSupportedByDeviceOutput)) {
            Log.d(TAG,  " Nothing to do.");
            return outActiveDeviceReplace;
        /*
         * Do not update output if neither previous nor current device support output
         */
        if (!oldSupportedByDeviceOutput && !newSupportedByDeviceOutput) {
            Log.d(TAG, "updateActiveOutDevice: Device does not support output.");
            return false;
        }

        /* Connect output:
         * - If active output device changed
         * - If device starts support output
        /*
         * Update output if:
         * - Device changed
         *     OR
         * - Device stops / starts supporting output
         */
         mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
                    device, BluetoothProfile.STATE_CONNECTED, true);
        return outActiveDeviceReplace;
        if (!Objects.equals(device, previousOutDevice)
                || (oldSupportedByDeviceOutput != newSupportedByDeviceOutput)) {
            mActiveAudioOutDevice = newSupportedByDeviceOutput ? device : null;
            final boolean suppressNoisyIntent = (mActiveAudioOutDevice != null)
                    || (getConnectionState(previousOutDevice) == BluetoothProfile.STATE_CONNECTED);
            mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice,
                    previousOutDevice, BtProfileConnectionInfo.leAudio(suppressNoisyIntent, true));
            return true;
        }
        Log.d(TAG, "updateActiveOutDevice: Nothing to do.");
        return false;
    }

    /**
@@ -786,13 +775,12 @@ public class LeAudioService extends ProfileService {

        boolean outReplaced =
            updateActiveOutDevice(device, groupId, oldActiveContexts, newActiveContexts);

        boolean inReplaced =
            updateActiveInDevice(device, groupId, oldActiveContexts, newActiveContexts);

        if (outReplaced || inReplaced) {
            Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mPreviousAudioOutDevice);
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mActiveAudioOutDevice);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            sendBroadcast(intent, BLUETOOTH_CONNECT);
+5 −6
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.BtProfileConnectionInfo;
import android.os.Looper;
import android.os.ParcelUuid;

@@ -521,9 +522,8 @@ public class HearingAidServiceTest {
        Assert.assertTrue(mService.getConnectedDevices().contains(mRightDevice));

        // Verify the audio is routed to Hearing Aid Profile
        verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState(
                any(BluetoothDevice.class), eq(BluetoothProfile.STATE_CONNECTED),
                eq(true), eq(0));
        verify(mAudioManager).handleBluetoothActiveDeviceChanged(
                any(BluetoothDevice.class), eq(null), any(BtProfileConnectionInfo.class));

        // Send a disconnect request
        Assert.assertTrue("Disconnect failed", mService.disconnect(mLeftDevice));
@@ -570,9 +570,8 @@ public class HearingAidServiceTest {
        Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice));

        // Verify the audio is not routed to Hearing Aid Profile
        verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState(
                any(BluetoothDevice.class), eq(BluetoothProfile.STATE_DISCONNECTED),
                eq(false), eq(0));
        verify(mAudioManager).handleBluetoothActiveDeviceChanged(
                eq(null), any(BluetoothDevice.class), any(BtProfileConnectionInfo.class));
    }

    /**