Add AudioDeviceInfoBuilder
This initial version enables the construction of AudioDeviceInfo with the external device types.
PiperOrigin-RevId: 517961411
diff --git a/robolectric/src/test/java/org/robolectric/shadows/AudioDeviceInfoBuilderTest.java b/robolectric/src/test/java/org/robolectric/shadows/AudioDeviceInfoBuilderTest.java
new file mode 100644
index 0000000..e196187
--- /dev/null
+++ b/robolectric/src/test/java/org/robolectric/shadows/AudioDeviceInfoBuilderTest.java
@@ -0,0 +1,25 @@
+package org.robolectric.shadows;
+
+import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
+import static android.os.Build.VERSION_CODES.M;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.media.AudioDeviceInfo;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/** Tests for {@link AudioDeviceInfoBuilder}. */
+@RunWith(AndroidJUnit4.class)
+@Config(minSdk = M)
+public class AudioDeviceInfoBuilderTest {
+
+ @Test
+ public void canCreateAudioDeviceInfoWithDesiredType() {
+ AudioDeviceInfo audioDeviceInfo =
+ AudioDeviceInfoBuilder.newBuilder().setType(TYPE_BLUETOOTH_A2DP).build();
+
+ assertThat(audioDeviceInfo.getType()).isEqualTo(TYPE_BLUETOOTH_A2DP);
+ }
+}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/AudioDeviceInfoBuilder.java b/shadows/framework/src/main/java/org/robolectric/shadows/AudioDeviceInfoBuilder.java
new file mode 100644
index 0000000..54cccf0
--- /dev/null
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/AudioDeviceInfoBuilder.java
@@ -0,0 +1,68 @@
+package org.robolectric.shadows;
+
+import static org.robolectric.util.reflector.Reflector.reflector;
+
+import android.media.AudioDeviceInfo;
+import android.os.Build.VERSION_CODES;
+import android.util.SparseIntArray;
+import androidx.annotation.RequiresApi;
+import java.util.Optional;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
+import org.robolectric.util.reflector.Accessor;
+import org.robolectric.util.reflector.ForType;
+import org.robolectric.util.reflector.Static;
+
+/** Builder for {@link AudioDeviceInfo}. */
+@RequiresApi(VERSION_CODES.M)
+public class AudioDeviceInfoBuilder {
+
+ private int type;
+
+ private AudioDeviceInfoBuilder() {}
+
+ public static AudioDeviceInfoBuilder newBuilder() {
+ return new AudioDeviceInfoBuilder();
+ }
+
+ /**
+ * Sets the device type.
+ *
+ * @param type The device type. The possible values are the constants defined as <a
+ * href=https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/AudioDeviceInfo.java?q=AudioDeviceType>
+ * {@code AudioDeviceInfo.AudioDeviceType}</a>
+ */
+ public AudioDeviceInfoBuilder setType(int type) {
+ this.type = type;
+ return this;
+ }
+
+ public AudioDeviceInfo build() {
+ Object port = Shadow.newInstanceOf("android.media.AudioDevicePort");
+ ReflectionHelpers.setField(port, "mType", externalToInternalType(type));
+
+ return ReflectionHelpers.callConstructor(
+ AudioDeviceInfo.class, ClassParameter.from(port.getClass(), port));
+ }
+
+ /** Accessor interface for {@link AudioDeviceInfo}'s internals. */
+ @ForType(AudioDeviceInfo.class)
+ interface AudioDeviceInfoReflector {
+
+ @Static
+ @Accessor("EXT_TO_INT_DEVICE_MAPPING")
+ SparseIntArray getExtToIntDeviceMapping();
+ }
+
+ private static int externalToInternalType(int externalType) {
+ return Optional.ofNullable(
+ reflector(AudioDeviceInfoReflector.class).getExtToIntDeviceMapping().get(externalType))
+ .orElseThrow(
+ () ->
+ new IllegalArgumentException(
+ "External type "
+ + externalType
+ + " does not have a mapping to an internal type defined."));
+ }
+}