Create StreamConfigurationMapCompat to handle backward compatibility

 * For API < 23 and getOutputSizes(int) with format PRIVATE, call getOutputSizes(SurfaceTexture.class) instead.

Bug: 259176134
Test: ./gradlew camera:camera-camera2:testDebug
Change-Id: Ic3268dde1547b94bc0ffeacb98e454ffe138081b
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
index b6949e6..6d48e3e7 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
@@ -16,12 +16,11 @@
 
 package androidx.camera.camera2.internal
 
-import android.graphics.SurfaceTexture
 import android.hardware.camera2.CameraCharacteristics
 import android.media.CamcorderProfile
-import android.os.Build
 import android.util.Size
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
+import androidx.camera.camera2.internal.compat.StreamConfigurationMapCompat
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.impl.ImageFormatConstants
 import androidx.camera.testing.CameraUtil
@@ -155,16 +154,11 @@
     }
 
     private fun getVideoSupportedResolutions(): Array<Size> {
-        val map = cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]!!
-
-        // Before Android 23, use {@link SurfaceTexture} will finally mapped to 0x22 in
-        // StreamConfigurationMap to retrieve the output sizes information.
-        return if (Build.VERSION.SDK_INT < 23) {
-            map.getOutputSizes(SurfaceTexture::class.java) ?: emptyArray()
-        } else {
-            map.getOutputSizes(ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
-                ?: emptyArray()
-        }
+        val mapCompat = StreamConfigurationMapCompat.toStreamConfigurationMapCompat(
+            cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]!!
+        )
+        return mapCompat.getOutputSizes(ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
+            ?: emptyArray()
     }
 
     private fun CamcorderProfile.size() = Size(videoFrameWidth, videoFrameHeight)
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
index 04688d1..66d79fe3 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/MeteringRepeatingSession.java
@@ -21,7 +21,6 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.os.Build;
 import android.util.Size;
 import android.view.Surface;
 
@@ -29,6 +28,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.internal.compat.StreamConfigurationMapCompat;
 import androidx.camera.camera2.internal.compat.workaround.SupportedRepeatingSurfaceSize;
 import androidx.camera.core.Logger;
 import androidx.camera.core.UseCase;
@@ -166,13 +166,9 @@
             return new Size(0, 0);
         }
 
-        if (Build.VERSION.SDK_INT < 23) {
-            // ImageFormat.PRIVATE is only public after Android level 23. Therefore, using
-            // SurfaceTexture.class to get the supported output sizes before Android level 23.
-            outputSizes = map.getOutputSizes(SurfaceTexture.class);
-        } else {
-            outputSizes = map.getOutputSizes(ImageFormat.PRIVATE);
-        }
+        StreamConfigurationMapCompat mapCompat =
+                StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map);
+        outputSizes = mapCompat.getOutputSizes(ImageFormat.PRIVATE);
         if (outputSizes == null) {
             Logger.e(TAG, "Can not get output size list.");
             return new Size(0, 0);
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedOutputSizesCollector.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedOutputSizesCollector.java
index 589530a..f901f3b 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedOutputSizesCollector.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedOutputSizesCollector.java
@@ -24,7 +24,6 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.os.Build;
@@ -36,13 +35,13 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.internal.compat.StreamConfigurationMapCompat;
 import androidx.camera.camera2.internal.compat.workaround.ExcludedSupportedSizesContainer;
 import androidx.camera.camera2.internal.compat.workaround.ResolutionCorrector;
 import androidx.camera.camera2.internal.compat.workaround.TargetAspectRatio;
 import androidx.camera.core.AspectRatio;
 import androidx.camera.core.Logger;
 import androidx.camera.core.ResolutionSelector;
-import androidx.camera.core.impl.ImageFormatConstants;
 import androidx.camera.core.impl.ImageOutputConfig;
 import androidx.camera.core.impl.SizeCoordinate;
 import androidx.camera.core.impl.SurfaceConfig;
@@ -294,8 +293,6 @@
 
     @NonNull
     private Size[] doGetOutputSizesByFormat(int imageFormat) {
-        Size[] outputSizes;
-
         StreamConfigurationMap map =
                 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
 
@@ -303,18 +300,9 @@
             throw new IllegalArgumentException("Can not retrieve SCALER_STREAM_CONFIGURATION_MAP");
         }
 
-        if (Build.VERSION.SDK_INT < 23
-                && imageFormat == ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE) {
-            // This is a little tricky that 0x22 that is internal defined in
-            // StreamConfigurationMap.java to be equal to ImageFormat.PRIVATE that is public
-            // after Android level 23 but not public in Android L. Use {@link SurfaceTexture}
-            // or {@link MediaCodec} will finally mapped to 0x22 in StreamConfigurationMap to
-            // retrieve the output sizes information.
-            outputSizes = map.getOutputSizes(SurfaceTexture.class);
-        } else {
-            outputSizes = map.getOutputSizes(imageFormat);
-        }
-
+        StreamConfigurationMapCompat mapCompat =
+                StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map);
+        Size[] outputSizes = mapCompat.getOutputSizes(imageFormat);
         if (outputSizes == null) {
             throw new IllegalArgumentException(
                     "Can not get supported output size for the format: " + imageFormat);
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 25bf0f8..40e04f2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -36,12 +36,10 @@
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.CamcorderProfile;
 import android.media.MediaRecorder;
-import android.os.Build;
 import android.util.Pair;
 import android.util.Rational;
 import android.util.Size;
@@ -54,6 +52,7 @@
 import androidx.camera.camera2.internal.compat.CameraAccessExceptionCompat;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
 import androidx.camera.camera2.internal.compat.CameraManagerCompat;
+import androidx.camera.camera2.internal.compat.StreamConfigurationMapCompat;
 import androidx.camera.camera2.internal.compat.workaround.ExcludedSupportedSizesContainer;
 import androidx.camera.camera2.internal.compat.workaround.ExtraSupportedSurfaceCombinationsContainer;
 import androidx.camera.camera2.internal.compat.workaround.ResolutionCorrector;
@@ -63,7 +62,6 @@
 import androidx.camera.core.Logger;
 import androidx.camera.core.ResolutionSelector;
 import androidx.camera.core.impl.AttachedSurfaceInfo;
-import androidx.camera.core.impl.ImageFormatConstants;
 import androidx.camera.core.impl.ImageOutputConfig;
 import androidx.camera.core.impl.SurfaceCombination;
 import androidx.camera.core.impl.SurfaceConfig;
@@ -693,8 +691,6 @@
 
     @NonNull
     private Size[] doGetAllOutputSizesByFormat(int imageFormat) {
-        Size[] outputSizes;
-
         StreamConfigurationMap map =
                 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
 
@@ -702,18 +698,9 @@
             throw new IllegalArgumentException("Can not retrieve SCALER_STREAM_CONFIGURATION_MAP");
         }
 
-        if (Build.VERSION.SDK_INT < 23
-                && imageFormat == ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE) {
-            // This is a little tricky that 0x22 that is internal defined in
-            // StreamConfigurationMap.java to be equal to ImageFormat.PRIVATE that is public
-            // after Android level 23 but not public in Android L. Use {@link SurfaceTexture}
-            // or {@link MediaCodec} will finally mapped to 0x22 in StreamConfigurationMap to
-            // retrieve the output sizes information.
-            outputSizes = map.getOutputSizes(SurfaceTexture.class);
-        } else {
-            outputSizes = map.getOutputSizes(imageFormat);
-        }
-
+        StreamConfigurationMapCompat mapCompat =
+                StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map);
+        Size[] outputSizes = mapCompat.getOutputSizes(imageFormat);
         if (outputSizes == null) {
             throw new IllegalArgumentException(
                     "Can not get supported output size for the format: " + imageFormat);
@@ -815,7 +802,10 @@
             throw new IllegalArgumentException("Can not retrieve SCALER_STREAM_CONFIGURATION_MAP");
         }
 
-        Size[] videoSizeArr = map.getOutputSizes(MediaRecorder.class);
+        StreamConfigurationMapCompat mapCompat =
+                StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map);
+
+        Size[] videoSizeArr = mapCompat.getOutputSizes(MediaRecorder.class);
 
         if (videoSizeArr == null) {
             return RESOLUTION_480P;
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java
new file mode 100644
index 0000000..e8d40e9
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.Build;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+/**
+ * Helper for accessing features in {@link StreamConfigurationMap} in a backwards compatible
+ * fashion.
+ */
+@RequiresApi(21)
+public class StreamConfigurationMapCompat {
+
+    private final StreamConfigurationMapCompatImpl mImpl;
+
+    private StreamConfigurationMapCompat(@NonNull StreamConfigurationMap map) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            mImpl = new StreamConfigurationMapCompatApi23Impl(map);
+        } else {
+            mImpl = new StreamConfigurationMapCompatBaseImpl(map);
+        }
+    }
+
+    /**
+     * Provides a backward-compatible wrapper for {@link StreamConfigurationMap}.
+     *
+     * @param map {@link StreamConfigurationMap} class to wrap
+     * @return wrapped class
+     */
+    @NonNull
+    public static StreamConfigurationMapCompat toStreamConfigurationMapCompat(
+            @NonNull StreamConfigurationMap map) {
+        return new StreamConfigurationMapCompat(map);
+    }
+
+    /**
+     * Get a list of sizes compatible with the requested image {@code format}.
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @return an array of supported sizes, or {@code null} if the {@code format} is not a
+     *         supported output
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    @Nullable
+    public Size[] getOutputSizes(int format) {
+        return mImpl.getOutputSizes(format);
+    }
+
+    /**
+     * Get a list of sizes compatible with {@code klass} to use as an output.
+     *
+     * @param klass a non-{@code null} {@link Class} object reference
+     * @return an array of supported sizes for {@link ImageFormat#PRIVATE} format,
+     *         or {@code null} iff the {@code klass} is not a supported output.
+     *
+     * @throws NullPointerException if {@code klass} was {@code null}
+     */
+    @Nullable
+    public <T> Size[] getOutputSizes(@NonNull Class<T> klass) {
+        return mImpl.getOutputSizes(klass);
+    }
+
+    interface StreamConfigurationMapCompatImpl {
+
+        @Nullable
+        Size[] getOutputSizes(int format);
+
+        @Nullable
+        <T> Size[] getOutputSizes(@NonNull Class<T> klass);
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatApi23Impl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatApi23Impl.java
new file mode 100644
index 0000000..23716af
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatApi23Impl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat;
+
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+@RequiresApi(21)
+class StreamConfigurationMapCompatApi23Impl extends StreamConfigurationMapCompatBaseImpl {
+
+    StreamConfigurationMapCompatApi23Impl(@NonNull StreamConfigurationMap map) {
+        super(map);
+    }
+
+    @Nullable
+    @Override
+    public Size[] getOutputSizes(int format) {
+        return mStreamConfigurationMap.getOutputSizes(format);
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatBaseImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatBaseImpl.java
new file mode 100644
index 0000000..5b797a1
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatBaseImpl.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat;
+
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.impl.ImageFormatConstants;
+
+@RequiresApi(21)
+class StreamConfigurationMapCompatBaseImpl
+        implements StreamConfigurationMapCompat.StreamConfigurationMapCompatImpl {
+
+    final StreamConfigurationMap mStreamConfigurationMap;
+
+    StreamConfigurationMapCompatBaseImpl(@NonNull StreamConfigurationMap map) {
+        mStreamConfigurationMap = map;
+    }
+
+    @Nullable
+    @Override
+    public Size[] getOutputSizes(int format) {
+        Size[] sizes;
+        if (format == ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE) {
+            // This is a little tricky that 0x22 that is internal defined in
+            // StreamConfigurationMap.java to be equal to ImageFormat.PRIVATE that is public
+            // after Android level 23 but not public in Android L. Use {@link SurfaceTexture}
+            // or {@link MediaCodec} will finally mapped to 0x22 in StreamConfigurationMap to
+            // retrieve the output sizes information.
+            sizes = mStreamConfigurationMap.getOutputSizes(SurfaceTexture.class);
+        } else {
+            sizes = mStreamConfigurationMap.getOutputSizes(format);
+        }
+        return sizes;
+    }
+
+    @Nullable
+    @Override
+    public <T> Size[] getOutputSizes(@NonNull Class<T> klass) {
+        return mStreamConfigurationMap.getOutputSizes(klass);
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java
index d058add..fb2d013 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java
@@ -16,16 +16,15 @@
 
 package androidx.camera.camera2.internal.compat.quirk;
 
-import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.CamcorderProfile;
-import android.os.Build;
 import android.util.Size;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.internal.compat.StreamConfigurationMapCompat;
 import androidx.camera.camera2.internal.compat.workaround.CamcorderProfileResolutionValidator;
 import androidx.camera.core.Logger;
 import androidx.camera.core.impl.ImageFormatConstants;
@@ -69,21 +68,17 @@
 
     public CamcorderProfileResolutionQuirk(
             @NonNull CameraCharacteristicsCompat characteristicsCompat) {
+        Size[] sizes = null;
         StreamConfigurationMap map =
                 characteristicsCompat.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-        if (map == null) {
+        if (map != null) {
+            StreamConfigurationMapCompat mapCompat =
+                    StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map);
+            sizes = mapCompat.getOutputSizes(
+                    ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE);
+        } else {
             Logger.e(TAG, "StreamConfigurationMap is null");
         }
-        Size[] sizes;
-        // Before Android 23, use {@link SurfaceTexture} will finally mapped to 0x22 in
-        // StreamConfigurationMap to retrieve the output sizes information.
-        if (Build.VERSION.SDK_INT < 23) {
-            sizes = map != null ? map.getOutputSizes(SurfaceTexture.class) : null;
-        } else {
-            sizes = map != null ? map.getOutputSizes(
-                    ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE) : null;
-        }
-
         mSupportedResolutions = sizes != null ? Arrays.asList(sizes.clone())
                 : Collections.emptyList();
 
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatTest.kt
new file mode 100644
index 0000000..e602ed3
--- /dev/null
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompatTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal.compat
+
+import android.graphics.SurfaceTexture
+import android.os.Build
+import android.util.Size
+import androidx.camera.core.impl.ImageFormatConstants
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.StreamConfigurationMapBuilder
+
+/**
+ * Unit tests for [StreamConfigurationMapCompat].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class StreamConfigurationMapCompatTest {
+
+    companion object {
+        private val SIZE_480P = Size(640, 480)
+        private val SIZE_720P = Size(1080, 720)
+        private val SIZE_1080P = Size(1920, 1080)
+        private const val FORMAT_PRIVATE =
+            ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+    }
+
+    private lateinit var streamConfigurationMapCompat: StreamConfigurationMapCompat
+    private val privateFormatOutputSizes = listOf(SIZE_1080P, SIZE_720P, SIZE_480P)
+
+    @Before
+    fun setUp() {
+        val builder = StreamConfigurationMapBuilder.newBuilder().apply {
+            privateFormatOutputSizes.forEach { size ->
+                addOutputSize(FORMAT_PRIVATE, size)
+            }
+        }
+        streamConfigurationMapCompat =
+            StreamConfigurationMapCompat.toStreamConfigurationMapCompat(builder.build())
+    }
+
+    @Test
+    fun getOutputSizes_withFormat_callGetOutputSizes() {
+        assertThat(
+            streamConfigurationMapCompat.getOutputSizes(FORMAT_PRIVATE)!!.toList()
+        ).containsExactlyElementsIn(privateFormatOutputSizes)
+    }
+
+    @Test
+    fun getOutputSizes_withClass_callGetOutputSizes() {
+        assertThat(
+            streamConfigurationMapCompat.getOutputSizes(SurfaceTexture::class.java)!!.toList()
+        ).containsExactlyElementsIn(privateFormatOutputSizes)
+    }
+}