summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vlad Popa <pvlad@google.com> 2023-12-04 17:17:18 -0800
committer Vlad Popa <pvlad@google.com> 2023-12-06 09:03:12 -0800
commita1e0582e5df25be78e4955a7e905ca28e1ae7b76 (patch)
tree55aaa87aed98f930b2ab9b0e87ff1e83ee4ae3e1
parent39917599b42aefea9136824fcb5b669baea5a198 (diff)
Add tests for the automatic audio device categorization
Testing the forwarded AudioDeviceBroker methods calls that query and modify the internal AdiDeviceState objects which store the audio device categorization information Test: adb shell device_config put media_audio android.media.audio.automatic_bt_device_type true Test: atest AudioDeviceBrokerTest Bug: 302323921 Change-Id: I6f0b3a50fd6ad2c16ad4b5bedd0319414d28a417
-rw-r--r--services/core/java/com/android/server/audio/AdiDeviceState.java7
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java132
4 files changed, 141 insertions, 11 deletions
diff --git a/services/core/java/com/android/server/audio/AdiDeviceState.java b/services/core/java/com/android/server/audio/AdiDeviceState.java
index b91e633bd3de..ffdab7dfbfa4 100644
--- a/services/core/java/com/android/server/audio/AdiDeviceState.java
+++ b/services/core/java/com/android/server/audio/AdiDeviceState.java
@@ -21,6 +21,8 @@ import static android.media.AudioSystem.DEVICE_NONE;
import static android.media.AudioSystem.isBluetoothDevice;
import static android.media.audio.Flags.automaticBtDeviceType;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioDeviceAttributes;
@@ -31,13 +33,16 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Objects;
/**
* Class representing all devices that were previously or are currently connected. Data is
* persisted in {@link android.provider.Settings.Secure}
*/
-/*package*/ final class AdiDeviceState {
+@VisibleForTesting(visibility = PACKAGE)
+public final class AdiDeviceState {
private static final String TAG = "AS.AdiDeviceState";
private static final String SETTING_FIELD_SEPARATOR = ",";
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 61ec04b755ce..46e9b2afe655 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -31,6 +31,8 @@ import static android.media.AudioSystem.isBluetoothScoOutDevice;
import static android.media.audio.Flags.automaticBtDeviceType;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
@@ -347,7 +349,8 @@ public class AudioDeviceInventory {
* @return the found {@link AdiDeviceState} or {@code null} otherwise.
*/
@Nullable
- AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
+ @VisibleForTesting(visibility = PACKAGE)
+ public AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
Set<Integer> deviceSet;
if (isBluetoothA2dpOutDevice(deviceType)) {
deviceSet = DEVICE_OUT_ALL_A2DP_SET;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8cec24d1bbb5..f7b7aaa60a35 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -39,6 +39,7 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.media.audio.Flags.alarmMinVolumeZero;
import static com.android.media.audio.Flags.bluetoothMacAddressAnonymization;
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
@@ -6785,7 +6786,8 @@ public class AudioService extends IAudioService.Stub
return mContentResolver;
}
- /*package*/ SettingsAdapter getSettings() {
+ @VisibleForTesting(visibility = PACKAGE)
+ public SettingsAdapter getSettings() {
return mSettings;
}
@@ -11250,7 +11252,9 @@ public class AudioService extends IAudioService.Stub
return mDeviceBroker.isBluetoothAudioDeviceCategoryFixed(address);
}
- /*package*/void onUpdatedAdiDeviceState(AdiDeviceState deviceState) {
+ /** Update the sound dose and spatializer state based on the new AdiDeviceState. */
+ @VisibleForTesting(visibility = PACKAGE)
+ public void onUpdatedAdiDeviceState(AdiDeviceState deviceState) {
if (deviceState == null) {
return;
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 0d58542ab040..cc3c880b8927 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -15,14 +15,28 @@
*/
package com.android.server.audio;
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_DEFAULT;
+import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_HEADSET;
+import static android.media.audio.Flags.automaticBtDeviceType;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -40,10 +54,10 @@ import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.Spy;
@@ -70,6 +84,9 @@ public class AudioDeviceBrokerTest {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
mMockAudioService = mock(AudioService.class);
+ SettingsAdapter mockAdapter = mock(SettingsAdapter.class);
+ when(mMockAudioService.getSettings()).thenReturn(mockAdapter);
+ when(mockAdapter.getSecureStringForUser(any(), any(), anyInt())).thenReturn("");
when(mMockAudioService.getBluetoothContextualVolumeStream())
.thenReturn(AudioSystem.STREAM_MUSIC);
@@ -82,7 +99,6 @@ public class AudioDeviceBrokerTest {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
mFakeBtDevice = adapter.getRemoteDevice("00:01:02:03:04:05");
- Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
}
@After
@@ -100,15 +116,14 @@ public class AudioDeviceBrokerTest {
@Test
public void testPostA2dpDeviceConnectionChange() throws Exception {
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
- Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+ assertNotNull("invalid null BT device", mFakeBtDevice);
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource"));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice(
- any(AudioDeviceBroker.BtDeviceInfo.class)
- );
+ any(AudioDeviceBroker.BtDeviceInfo.class));
// verify the connection was reported to AudioSystem
checkSingleSystemConnection(mFakeBtDevice);
@@ -212,7 +227,7 @@ public class AudioDeviceBrokerTest {
AudioManager.DEVICE_OUT_SPEAKER, null);
new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, null);
- Assert.fail();
+ fail();
} catch (NullPointerException e) { }
}
@@ -228,11 +243,114 @@ public class AudioDeviceBrokerTest {
final AdiDeviceState result = AdiDeviceState.fromPersistedString(persistString);
Log.i(TAG, "original:" + devState);
Log.i(TAG, "result :" + result);
- Assert.assertEquals(devState, result);
+ assertEquals(devState, result);
+ }
+
+ @Test
+ public void testIsBluetoothAudioDeviceCategoryFixed() throws Exception {
+ Log.i(TAG, "starting testIsBluetoothAudioDeviceCategoryFixed");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testIsBluetoothAudioDeviceCategoryFixed");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ final AdiDeviceState devState = new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, mFakeBtDevice.getAddress());
+ doReturn(devState).when(mSpyDevInventory).findBtDeviceStateForAddress(
+ mFakeBtDevice.getAddress(), AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.BLUETOOTH_PRIVILEGED);
+
+ // no metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_DEFAULT.getBytes()));
+ assertFalse(
+ mAudioDeviceBroker.isBluetoothAudioDeviceCategoryFixed(
+ mFakeBtDevice.getAddress()));
+
+ // metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_HEADSET.getBytes()));
+ assertTrue(mAudioDeviceBroker.isBluetoothAudioDeviceCategoryFixed(
+ mFakeBtDevice.getAddress()));
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testGetAndUpdateBtAdiDeviceStateCategoryForAddress() throws Exception {
+ Log.i(TAG, "starting testGetAndUpdateBtAdiDeviceStateCategoryForAddress");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testGetAndUpdateBtAdiDeviceStateCategoryForAddress");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ final AdiDeviceState devState = new AdiDeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ AudioManager.DEVICE_OUT_BLUETOOTH_A2DP, mFakeBtDevice.getAddress());
+ devState.setAudioDeviceCategory(AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER);
+ doReturn(devState).when(mSpyDevInventory).findBtDeviceStateForAddress(
+ eq(mFakeBtDevice.getAddress()), anyInt());
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(Manifest.permission.BLUETOOTH_PRIVILEGED);
+
+ // no metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_DEFAULT.getBytes()));
+ assertEquals(AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER,
+ mAudioDeviceBroker.getAndUpdateBtAdiDeviceStateCategoryForAddress(
+ mFakeBtDevice.getAddress()));
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS).times(0)).onUpdatedAdiDeviceState(
+ eq(devState));
+
+ // metadata set
+ assertTrue(mFakeBtDevice.setMetadata(BluetoothDevice.METADATA_DEVICE_TYPE,
+ DEVICE_TYPE_HEADSET.getBytes()));
+ assertEquals(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES,
+ mAudioDeviceBroker.getAndUpdateBtAdiDeviceStateCategoryForAddress(
+ mFakeBtDevice.getAddress()));
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS)).onUpdatedAdiDeviceState(
+ any());
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testAddAudioDeviceWithCategoryInInventoryIfNeeded() throws Exception {
+ Log.i(TAG, "starting testAddAudioDeviceWithCategoryInInventoryIfNeeded");
+
+ if (!automaticBtDeviceType()) {
+ Log.i(TAG, "Enable automaticBtDeviceType flag to run the test "
+ + "testAddAudioDeviceWithCategoryInInventoryIfNeeded");
+ return;
+ }
+ assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ mAudioDeviceBroker.addAudioDeviceWithCategoryInInventoryIfNeeded(
+ mFakeBtDevice.getAddress(), AudioManager.AUDIO_DEVICE_CATEGORY_OTHER);
+
+ verify(mMockAudioService,
+ timeout(MAX_MESSAGE_HANDLING_DELAY_MS).atLeast(1)).onUpdatedAdiDeviceState(
+ ArgumentMatchers.argThat(devState -> devState.getAudioDeviceCategory()
+ == AudioManager.AUDIO_DEVICE_CATEGORY_OTHER));
}
private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection,
boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception {
+ assertNotNull("invalid null BT device", mFakeBtDevice);
when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))
.thenReturn(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
when(mMockAudioService.isInCommunication()).thenReturn(false);