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

Commit 5249cb65 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I96957880,If7fa258b into tm-qpr-dev

* changes:
  McsService: Fix authorization issues
  LeAudioService: Fix failing unit test
parents 00f9385d 50d18fd5
Loading
Loading
Loading
Loading
+73 −12
Original line number Diff line number Diff line
@@ -115,17 +115,21 @@ public class LeAudioService extends ProfileService {
    private volatile BluetoothDevice mActiveAudioOutDevice;
    private volatile BluetoothDevice mActiveAudioInDevice;
    private LeAudioCodecConfig mLeAudioCodecConfig;
    private Object mGroupLock = new Object();
    private final Object mGroupLock = new Object();
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
    boolean mLeAudioNativeIsInitialized = false;
    boolean mBluetoothEnabled = false;
    BluetoothDevice mHfpHandoverDevice = null;
    LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null;
    @VisibleForTesting
    AudioManager mAudioManager;
    LeAudioTmapGattServer mTmapGattServer;

    @VisibleForTesting
    McpService mMcpService;

    @VisibleForTesting
    VolumeControlService mVolumeControlService;

@@ -330,6 +334,7 @@ public class LeAudioService extends ProfileService {
        mLeAudioNativeInterface.cleanup();
        mLeAudioNativeInterface = null;
        mLeAudioNativeIsInitialized = false;
        mBluetoothEnabled = false;
        mHfpHandoverDevice = null;

        mActiveAudioOutDevice = null;
@@ -391,6 +396,7 @@ public class LeAudioService extends ProfileService {

        mAdapterService = null;
        mAudioManager = null;
        mMcpService = null;
        mVolumeControlService = null;

        return true;
@@ -895,7 +901,13 @@ public class LeAudioService extends ProfileService {
        return false;
    }

    private void notifyActiveDeviceChanged() {
    /**
     * Send broadcast intent about LeAudio active device.
     * This is called when AudioManager confirms, LeAudio device
     * is added or removed.
     */
    @VisibleForTesting
    void notifyActiveDeviceChanged() {
        Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
                mActiveAudioOutDevice != null ? mActiveAudioOutDevice : mActiveAudioInDevice);
@@ -1683,11 +1695,6 @@ public class LeAudioService extends ProfileService {
            } else {
                Log.e(TAG, "no descriptors for group: " + myGroupId);
            }

            McpService mcpService = mServiceFactory.getMcpService();
            if (mcpService != null) {
                mcpService.setDeviceAuthorized(device, true);
            }
        }
        // Check if the device is disconnected - if unbond, remove the state machine
        if (toState == BluetoothProfile.STATE_DISCONNECTED) {
@@ -1699,11 +1706,6 @@ public class LeAudioService extends ProfileService {
                removeStateMachine(device);
            }

            McpService mcpService = mServiceFactory.getMcpService();
            if (mcpService != null) {
                mcpService.setDeviceAuthorized(device, false);
            }

            int myGroupId = getGroupId(device);
            LeAudioGroupDescriptor descriptor = getGroupDescriptor(myGroupId);
            if (descriptor == null) {
@@ -1971,6 +1973,50 @@ public class LeAudioService extends ProfileService {
        }
    }

    McpService getMcpService() {
        if (mMcpService != null) {
            return mMcpService;
        }

        mMcpService = mServiceFactory.getMcpService();
        return mMcpService;
    }

    /**
     * This function is called when the framework registers
     * a callback with the service for this first time.
     * This is used as an indication that Bluetooth has been enabled.
     * 
     * It is used to authorize all known LeAudio devices in the services
     * which requires that e.g. GMCS
     */
    @VisibleForTesting
    void handleBluetoothEnabled() {
        if (DBG) {
            Log.d(TAG, "handleBluetoothEnabled ");
        }

        mBluetoothEnabled = true;

        synchronized (mGroupLock) {
            if (mDeviceGroupIdMap.isEmpty()) {
                return;
            }
        }

        McpService mcpService = getMcpService();
        if (mcpService == null) {
            Log.e(TAG, "mcpService not available ");
            return;
        }

        synchronized (mGroupLock) {
            for (Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
                mcpService.setDeviceAuthorized(entry.getKey(), true);
            }
        }
    }

    private LeAudioGroupDescriptor getGroupDescriptor(int groupId) {
        synchronized (mGroupLock) {
            return mGroupDescriptors.get(groupId);
@@ -1990,6 +2036,13 @@ public class LeAudioService extends ProfileService {
            }
            notifyGroupNodeAdded(device, groupId);
        }

        if (mBluetoothEnabled) {
            McpService mcpService = getMcpService();
            if (mcpService != null) {
                mcpService.setDeviceAuthorized(device, true);
            }
        }
    }

    private void notifyGroupNodeAdded(BluetoothDevice device, int groupId) {
@@ -2033,6 +2086,11 @@ public class LeAudioService extends ProfileService {
            }
            notifyGroupNodeRemoved(device, groupId);
        }

        McpService mcpService = getMcpService();
        if (mcpService != null) {
            mcpService.setDeviceAuthorized(device, false);
        }
    }

    private void notifyGroupNodeRemoved(BluetoothDevice device, int groupId) {
@@ -2668,6 +2726,9 @@ public class LeAudioService extends ProfileService {

                enforceBluetoothPrivilegedPermission(service);
                service.mLeAudioCallbacks.register(callback);
                if (!service.mBluetoothEnabled) {
                    service.handleBluetoothEnabled();
                }
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
+80 −4
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.vc.VolumeControlService;

import org.junit.After;
@@ -110,11 +111,12 @@ public class LeAudioServiceTest {
    private BroadcastReceiver mLeAudioIntentReceiver;

    @Mock private AdapterService mAdapterService;
    @Mock private AudioManager mAudioManager;
    @Mock private DatabaseManager mDatabaseManager;
    @Mock private LeAudioNativeInterface mNativeInterface;
    @Mock private AudioManager mAudioManager;
    @Mock private VolumeControlService mVolumeControlService;
    @Mock private LeAudioTmapGattServer mTmapGattServer;
    @Mock private McpService mMcpService;
    @Mock private VolumeControlService mVolumeControlService;
    @Spy private LeAudioObjectsFactory mObjectsFactory = LeAudioObjectsFactory.getInstance();
    @Spy private ServiceFactory mServiceFactory = new ServiceFactory();

@@ -188,6 +190,7 @@ public class LeAudioServiceTest {
        LeAudioNativeInterface.setInstance(mNativeInterface);
        startService();
        mService.mAudioManager = mAudioManager;
        mService.mMcpService = mMcpService;
        mService.mServiceFactory = mServiceFactory;
        when(mServiceFactory.getVolumeControlService()).thenReturn(mVolumeControlService);

@@ -869,6 +872,24 @@ public class LeAudioServiceTest {
        verifyNoConnectionStateIntent(TIMEOUT_MS, device);
    }

    private void generateGroupNodeAdded(BluetoothDevice device, int groupId) {
        LeAudioStackEvent nodeGroupAdded =
        new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED);
        nodeGroupAdded.device = device;
        nodeGroupAdded.valueInt1 = groupId;
        nodeGroupAdded.valueInt2 = LeAudioStackEvent.GROUP_NODE_ADDED;
        mService.messageFromNative(nodeGroupAdded);
    }

    private void generateGroupNodeRemoved(BluetoothDevice device, int groupId) {
        LeAudioStackEvent nodeGroupRemoved =
        new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED);
        nodeGroupRemoved.device = device;
        nodeGroupRemoved.valueInt1 = groupId;
        nodeGroupRemoved.valueInt2 = LeAudioStackEvent.GROUP_NODE_REMOVED;
        mService.messageFromNative(nodeGroupRemoved);
    }

    private void verifyNoConnectionStateIntent(int timeoutMs, BluetoothDevice device) {
        Intent intent = TestUtils.waitForNoIntent(timeoutMs, mDeviceQueueMap.get(device));
        assertThat(intent).isNull();
@@ -1113,8 +1134,16 @@ public class LeAudioServiceTest {
                         BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL, 3);
        injectGroupStatusChange(testGroupId, BluetoothLeAudio.GROUP_STATUS_ACTIVE);

        String action = BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED;
        /* Expect 2 calles to Audio Manager - one for output and second for input as this is
         * Conversational use case */
        verify(mAudioManager, times(2)).handleBluetoothActiveDeviceChanged(any(), any(),
                        any(BluetoothProfileConnectionInfo.class));
        /* Since LeAudioService called AudioManager - assume Audio manager calles properly callback
        * mAudioManager.onAudioDeviceAdded
        */
        mService.notifyActiveDeviceChanged();

        String action = BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED;
        Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
        assertThat(intent).isNotNull();
        assertThat(action).isEqualTo(intent.getAction());
@@ -1325,7 +1354,10 @@ public class LeAudioServiceTest {
        assertThat(mService.getActiveDevices().contains(leadDevice)).isTrue();
        verify(mAudioManager, times(1)).handleBluetoothActiveDeviceChanged(eq(leadDevice), any(),
                        any(BluetoothProfileConnectionInfo.class));

        /* Since LeAudioService called AudioManager - assume Audio manager calles properly callback
         * mAudioManager.onAudioDeviceAdded
         */
        mService.notifyActiveDeviceChanged();
        doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService).getBondState(leadDevice);
        verifyActiveDeviceStateIntent(AUDIO_MANAGER_DEVICE_ADD_TIMEOUT_MS, leadDevice);
        injectNoVerifyDeviceDisconnected(leadDevice);
@@ -1391,6 +1423,10 @@ public class LeAudioServiceTest {
        assertThat(mService.getActiveDevices().contains(leadDevice)).isTrue();
        verify(mAudioManager, times(1)).handleBluetoothActiveDeviceChanged(eq(leadDevice), any(),
                        any(BluetoothProfileConnectionInfo.class));
        /* Since LeAudioService called AudioManager - assume Audio manager calles properly callback
         * mAudioManager.onAudioDeviceAdded
         */
        mService.notifyActiveDeviceChanged();

        verifyActiveDeviceStateIntent(AUDIO_MANAGER_DEVICE_ADD_TIMEOUT_MS, leadDevice);
        /* We don't want to distribute DISCONNECTION event, instead will try to reconnect
@@ -1556,4 +1592,44 @@ public class LeAudioServiceTest {
        StringBuilder sb = new StringBuilder();
        mService.dump(sb);
    }

    /**
     * Test setting authorization for LeAudio device in the McpService
     */
    @Test
    public void testAuthorizeMcpServiceWhenDeviceConnecting() {
        int groupId = 1;

        mService.handleBluetoothEnabled();
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        connectTestDevice(mLeftDevice, groupId);
        connectTestDevice(mRightDevice, groupId);
        verify(mMcpService, times(1)).setDeviceAuthorized(mLeftDevice, true);
        verify(mMcpService, times(1)).setDeviceAuthorized(mRightDevice, true);
    }

    /**
     * Test setting authorization for LeAudio device in the McpService
     */
    @Test
    public void testAuthorizeMcpServiceOnBluetoothEnableAndNodeRemoval() {
        int groupId = 1;

        generateGroupNodeAdded(mLeftDevice, groupId);
        generateGroupNodeAdded(mRightDevice, groupId);

        verify(mMcpService, times(0)).setDeviceAuthorized(mLeftDevice, true);
        verify(mMcpService, times(0)).setDeviceAuthorized(mRightDevice, true);

        mService.handleBluetoothEnabled();

        verify(mMcpService, times(1)).setDeviceAuthorized(mLeftDevice, true);
        verify(mMcpService, times(1)).setDeviceAuthorized(mRightDevice, true);

        generateGroupNodeRemoved(mLeftDevice, groupId);
        verify(mMcpService, times(1)).setDeviceAuthorized(mLeftDevice, false);

        generateGroupNodeRemoved(mRightDevice, groupId);
        verify(mMcpService, times(1)).setDeviceAuthorized(mRightDevice, false);
    }
}