Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +23 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.annotation.RequiresPermission; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus; import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; Loading @@ -45,6 +46,7 @@ import android.media.AudioManager; import android.media.BluetoothProfileConnectionInfo; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.sysprop.BluetoothProperties; import android.util.Log; Loading Loading @@ -1654,4 +1656,25 @@ public class A2dpService extends ProfileService { mA2dpCodecConfig.switchCodecByBufferSize( device, isLowLatency, getCodecStatus(device).getCodecConfig().getCodecType()); } /** * Sends the preferred audio profile change requested from a call to * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio * framework to apply the change. The audio framework will call * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the * change is successfully applied. * * @return the number of requests sent to the audio framework */ public int sendPreferredAudioProfileChangeToAudioFramework() { synchronized (mStateMachines) { if (mActiveDevice == null) { Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device"); return 0; } mAudioManager.handleBluetoothActiveDeviceChanged(mActiveDevice, mActiveDevice, BluetoothProfileConnectionInfo.createA2dpInfo(false, -1)); return 1; } } } android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +40 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothLeAudioCodecConfig; Loading Loading @@ -2823,6 +2824,45 @@ public class LeAudioService extends ProfileService { return getConnectedGroupLeadDevice(groupId); } /** * Sends the preferred audio profile change requested from a call to * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio * framework to apply the change. The audio framework will call * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the * change is successfully applied. * * @return the number of requests sent to the audio framework */ public int sendPreferredAudioProfileChangeToAudioFramework() { if (mActiveAudioOutDevice == null && mActiveAudioInDevice == null) { Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device"); return 0; } int audioFrameworkCalls = 0; if (mActiveAudioOutDevice != null) { int volume = getAudioDeviceGroupVolume(getGroupId(mActiveAudioOutDevice)); final boolean suppressNoisyIntent = mActiveAudioOutDevice != null; Log.i(TAG, "Sending LE Audio Output active device changed for preferred profile " + "change with volume=" + volume + " and suppressNoisyIntent=" + suppressNoisyIntent); mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice, mActiveAudioOutDevice, getLeAudioOutputProfile(suppressNoisyIntent, volume)); audioFrameworkCalls++; } if (mActiveAudioInDevice != null) { Log.i(TAG, "Sending LE Audio Input active device changed for audio profile change"); mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice, mActiveAudioInDevice, BluetoothProfileConnectionInfo.createLeAudioInfo(false, false)); audioFrameworkCalls++; } return audioFrameworkCalls; } /** * Binder object: must be a static class or memory leak may occur */ Loading android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -931,6 +931,26 @@ public class A2dpServiceTest { verifySupportTime, verifyNotSupportTime, verifyEnabledTime); } /** * Tests that {@link A2dpService#sendPreferredAudioProfileChangeToAudioFramework()} sends * requests to the audio framework when there is an active A2DP device. */ @Test public void testSendPreferredAudioProfileChangeToAudioFramework() { doReturn(true).when(mA2dpNativeInterface).setActiveDevice(any(BluetoothDevice.class)); Assert.assertTrue(mA2dpService.removeActiveDevice(true)); Assert.assertNull(mA2dpService.getActiveDevice()); // Send 0 requests when the active device is null Assert.assertEquals(0, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework()); // Send 1 request when there is an A2DP active device connectDevice(mTestDevice); Assert.assertTrue(mA2dpService.setActiveDevice(mTestDevice)); Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice()); Assert.assertEquals(1, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework()); } @Test public void testDumpDoesNotCrash() { mA2dpService.dump(new StringBuilder()); Loading android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -1780,4 +1780,66 @@ public class LeAudioServiceTest { assertThat(secondGroupDevicesById.contains(mRightDevice)).isFalse(); assertThat(secondGroupDevicesById.equals(secondGroupDevicesByDevice)).isTrue(); } /** * Tests that {@link LeAudioService#sendPreferredAudioProfileChangeToAudioFramework()} sends * requests to the audio framework for each active LEA device. */ @Test public void testSendPreferredAudioProfileChangeToAudioFramework() { when(mAdapterService.isAllSupportedClassicAudioProfilesActive(any())).thenReturn(true); // TEST 1: Verify no requests are sent to the audio framework if there is no active device assertThat(mService.removeActiveDevice(false)).isTrue(); List<BluetoothDevice> activeDevices = mService.getActiveDevices(); assertThat(activeDevices.get(0)).isNull(); assertThat(activeDevices.get(1)).isNull(); assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(0); // TEST 2: Verify we send one request for each active direction int groupId = 1; /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 | AUDIO_DIRECTION_INPUT_BIT = 0x02; */ int direction = 3; int snkAudioLocation = 3; int srcAudioLocation = 4; int availableContexts = 5; int nodeStatus = LeAudioStackEvent.GROUP_NODE_ADDED; int groupStatus = LeAudioStackEvent.GROUP_STATUS_ACTIVE; // Single active device doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class)); connectTestDevice(mSingleDevice, testGroupId); // Add device to group LeAudioStackEvent nodeStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED); nodeStatusChangedEvent.device = mSingleDevice; nodeStatusChangedEvent.valueInt1 = groupId; nodeStatusChangedEvent.valueInt2 = nodeStatus; mService.messageFromNative(nodeStatusChangedEvent); assertThat(mService.setActiveDevice(mSingleDevice)).isTrue(); // Add location support LeAudioStackEvent audioConfChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED); audioConfChangedEvent.device = mSingleDevice; audioConfChangedEvent.valueInt1 = direction; audioConfChangedEvent.valueInt2 = groupId; audioConfChangedEvent.valueInt3 = snkAudioLocation; audioConfChangedEvent.valueInt4 = srcAudioLocation; audioConfChangedEvent.valueInt5 = availableContexts; mService.messageFromNative(audioConfChangedEvent); // Set group and device as active LeAudioStackEvent groupStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); groupStatusChangedEvent.device = mSingleDevice; groupStatusChangedEvent.valueInt1 = groupId; groupStatusChangedEvent.valueInt2 = groupStatus; mService.messageFromNative(groupStatusChangedEvent); assertThat(mService.getActiveDevices().contains(mSingleDevice)).isTrue(); assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(2); } } Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +23 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.annotation.RequiresPermission; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus; import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; Loading @@ -45,6 +46,7 @@ import android.media.AudioManager; import android.media.BluetoothProfileConnectionInfo; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.sysprop.BluetoothProperties; import android.util.Log; Loading Loading @@ -1654,4 +1656,25 @@ public class A2dpService extends ProfileService { mA2dpCodecConfig.switchCodecByBufferSize( device, isLowLatency, getCodecStatus(device).getCodecConfig().getCodecType()); } /** * Sends the preferred audio profile change requested from a call to * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio * framework to apply the change. The audio framework will call * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the * change is successfully applied. * * @return the number of requests sent to the audio framework */ public int sendPreferredAudioProfileChangeToAudioFramework() { synchronized (mStateMachines) { if (mActiveDevice == null) { Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device"); return 0; } mAudioManager.handleBluetoothActiveDeviceChanged(mActiveDevice, mActiveDevice, BluetoothProfileConnectionInfo.createA2dpInfo(false, -1)); return 1; } } }
android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +40 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothLeAudioCodecConfig; Loading Loading @@ -2823,6 +2824,45 @@ public class LeAudioService extends ProfileService { return getConnectedGroupLeadDevice(groupId); } /** * Sends the preferred audio profile change requested from a call to * {@link BluetoothAdapter#setPreferredAudioProfiles(BluetoothDevice, Bundle)} to the audio * framework to apply the change. The audio framework will call * {@link BluetoothAdapter#notifyActiveDeviceChangeApplied(BluetoothDevice)} once the * change is successfully applied. * * @return the number of requests sent to the audio framework */ public int sendPreferredAudioProfileChangeToAudioFramework() { if (mActiveAudioOutDevice == null && mActiveAudioInDevice == null) { Log.e(TAG, "sendPreferredAudioProfileChangeToAudioFramework: no active device"); return 0; } int audioFrameworkCalls = 0; if (mActiveAudioOutDevice != null) { int volume = getAudioDeviceGroupVolume(getGroupId(mActiveAudioOutDevice)); final boolean suppressNoisyIntent = mActiveAudioOutDevice != null; Log.i(TAG, "Sending LE Audio Output active device changed for preferred profile " + "change with volume=" + volume + " and suppressNoisyIntent=" + suppressNoisyIntent); mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioOutDevice, mActiveAudioOutDevice, getLeAudioOutputProfile(suppressNoisyIntent, volume)); audioFrameworkCalls++; } if (mActiveAudioInDevice != null) { Log.i(TAG, "Sending LE Audio Input active device changed for audio profile change"); mAudioManager.handleBluetoothActiveDeviceChanged(mActiveAudioInDevice, mActiveAudioInDevice, BluetoothProfileConnectionInfo.createLeAudioInfo(false, false)); audioFrameworkCalls++; } return audioFrameworkCalls; } /** * Binder object: must be a static class or memory leak may occur */ Loading
android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -931,6 +931,26 @@ public class A2dpServiceTest { verifySupportTime, verifyNotSupportTime, verifyEnabledTime); } /** * Tests that {@link A2dpService#sendPreferredAudioProfileChangeToAudioFramework()} sends * requests to the audio framework when there is an active A2DP device. */ @Test public void testSendPreferredAudioProfileChangeToAudioFramework() { doReturn(true).when(mA2dpNativeInterface).setActiveDevice(any(BluetoothDevice.class)); Assert.assertTrue(mA2dpService.removeActiveDevice(true)); Assert.assertNull(mA2dpService.getActiveDevice()); // Send 0 requests when the active device is null Assert.assertEquals(0, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework()); // Send 1 request when there is an A2DP active device connectDevice(mTestDevice); Assert.assertTrue(mA2dpService.setActiveDevice(mTestDevice)); Assert.assertEquals(mTestDevice, mA2dpService.getActiveDevice()); Assert.assertEquals(1, mA2dpService.sendPreferredAudioProfileChangeToAudioFramework()); } @Test public void testDumpDoesNotCrash() { mA2dpService.dump(new StringBuilder()); Loading
android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -1780,4 +1780,66 @@ public class LeAudioServiceTest { assertThat(secondGroupDevicesById.contains(mRightDevice)).isFalse(); assertThat(secondGroupDevicesById.equals(secondGroupDevicesByDevice)).isTrue(); } /** * Tests that {@link LeAudioService#sendPreferredAudioProfileChangeToAudioFramework()} sends * requests to the audio framework for each active LEA device. */ @Test public void testSendPreferredAudioProfileChangeToAudioFramework() { when(mAdapterService.isAllSupportedClassicAudioProfilesActive(any())).thenReturn(true); // TEST 1: Verify no requests are sent to the audio framework if there is no active device assertThat(mService.removeActiveDevice(false)).isTrue(); List<BluetoothDevice> activeDevices = mService.getActiveDevices(); assertThat(activeDevices.get(0)).isNull(); assertThat(activeDevices.get(1)).isNull(); assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(0); // TEST 2: Verify we send one request for each active direction int groupId = 1; /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 | AUDIO_DIRECTION_INPUT_BIT = 0x02; */ int direction = 3; int snkAudioLocation = 3; int srcAudioLocation = 4; int availableContexts = 5; int nodeStatus = LeAudioStackEvent.GROUP_NODE_ADDED; int groupStatus = LeAudioStackEvent.GROUP_STATUS_ACTIVE; // Single active device doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class)); connectTestDevice(mSingleDevice, testGroupId); // Add device to group LeAudioStackEvent nodeStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_NODE_STATUS_CHANGED); nodeStatusChangedEvent.device = mSingleDevice; nodeStatusChangedEvent.valueInt1 = groupId; nodeStatusChangedEvent.valueInt2 = nodeStatus; mService.messageFromNative(nodeStatusChangedEvent); assertThat(mService.setActiveDevice(mSingleDevice)).isTrue(); // Add location support LeAudioStackEvent audioConfChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED); audioConfChangedEvent.device = mSingleDevice; audioConfChangedEvent.valueInt1 = direction; audioConfChangedEvent.valueInt2 = groupId; audioConfChangedEvent.valueInt3 = snkAudioLocation; audioConfChangedEvent.valueInt4 = srcAudioLocation; audioConfChangedEvent.valueInt5 = availableContexts; mService.messageFromNative(audioConfChangedEvent); // Set group and device as active LeAudioStackEvent groupStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); groupStatusChangedEvent.device = mSingleDevice; groupStatusChangedEvent.valueInt1 = groupId; groupStatusChangedEvent.valueInt2 = groupStatus; mService.messageFromNative(groupStatusChangedEvent); assertThat(mService.getActiveDevices().contains(mSingleDevice)).isTrue(); assertThat(mService.sendPreferredAudioProfileChangeToAudioFramework()).isEqualTo(2); } }