Merge "[CameraPipe] Port proper resolution selection for MeteringRepeating" into androidx-main
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
index 8aec946..db29d61 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
@@ -17,16 +17,13 @@
package androidx.camera.camera2.pipe.integration.adapter
import android.content.Context
-import android.graphics.Point
import android.hardware.camera2.CameraCaptureSession.CaptureCallback
import android.hardware.camera2.CameraDevice
-import android.hardware.display.DisplayManager
-import android.util.Size
-import android.view.Display
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.core.Log.debug
import androidx.camera.camera2.pipe.core.Log.info
import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
+import androidx.camera.camera2.pipe.integration.impl.DisplayInfoManager
import androidx.camera.camera2.pipe.integration.impl.SESSION_PHYSICAL_CAMERA_ID_OPTION
import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
import androidx.camera.core.impl.CameraCaptureCallback
@@ -48,17 +45,7 @@
@Suppress("DEPRECATION")
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
class CameraUseCaseAdapter(context: Context) : UseCaseConfigFactory {
- private val MAX_PREVIEW_SIZE = Size(1920, 1080)
-
- private val displayManager: DisplayManager by lazy {
- context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
- }
- private val defaultDisplay: Display by lazy {
- getMaxSizeDisplay()
- }
- private val previewSize: Size by lazy {
- calculatePreviewSize()
- }
+ private val displayInfoManager by lazy { DisplayInfoManager(context) }
init {
if (context === context.applicationContext) {
@@ -132,56 +119,17 @@
if (captureType == UseCaseConfigFactory.CaptureType.PREVIEW) {
mutableConfig.insertOption(
ImageOutputConfig.OPTION_MAX_RESOLUTION,
- previewSize
+ displayInfoManager.previewSize
)
}
mutableConfig.insertOption(
ImageOutputConfig.OPTION_TARGET_ROTATION,
- defaultDisplay.rotation
+ displayInfoManager.defaultDisplay.rotation
)
return OptionsBundle.from(mutableConfig)
}
- private fun getMaxSizeDisplay(): Display {
- val displays = displayManager.displays
- var maxDisplay: Display? = null
- var maxDisplaySize = -1
- for (display: Display in displays) {
- val displaySize = Point()
- // TODO(b/230400472): Use WindowManager#getCurrentWindowMetrics(). Display#getRealSize()
- // is deprecated since API level 31.
- display.getRealSize(displaySize)
- if (displaySize.x * displaySize.y > maxDisplaySize) {
- maxDisplaySize = displaySize.x * displaySize.y
- maxDisplay = display
- }
- }
- return checkNotNull(maxDisplay) { "No displays found from ${displayManager.displays}!" }
- }
-
- /**
- * Calculates the device's screen resolution, or MAX_PREVIEW_SIZE, whichever is smaller.
- */
- private fun calculatePreviewSize(): Size {
- val displaySize = Point()
- val display: Display = defaultDisplay
- display.getRealSize(displaySize)
- var displayViewSize: Size
- displayViewSize = if (displaySize.x > displaySize.y) {
- Size(displaySize.x, displaySize.y)
- } else {
- Size(displaySize.y, displaySize.x)
- }
- if (displayViewSize.width * displayViewSize.height
- > MAX_PREVIEW_SIZE.width * MAX_PREVIEW_SIZE.height
- ) {
- displayViewSize = MAX_PREVIEW_SIZE
- }
- // TODO(b/230402463): Migrate extra cropping quirk from CameraX.
- return displayViewSize
- }
-
object DefaultCaptureOptionsUnpacker : CaptureConfig.OptionUnpacker {
@OptIn(ExperimentalCamera2Interop::class)
override fun unpack(config: UseCaseConfig<*>, builder: CaptureConfig.Builder) {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManager.kt
new file mode 100644
index 0000000..1babffd
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManager.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.pipe.integration.impl
+
+import android.content.Context
+import android.graphics.Point
+import android.hardware.display.DisplayManager
+import android.util.Size
+import android.view.Display
+import androidx.annotation.RequiresApi
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Suppress("DEPRECATION") // getRealSize
+@Singleton
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class DisplayInfoManager @Inject constructor(context: Context) {
+ private val MAX_PREVIEW_SIZE = Size(1920, 1080)
+
+ private val displayManager: DisplayManager by lazy {
+ context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ }
+
+ // TODO(b/198257203): Fetch latest display information for devices where display size is not
+ // guaranteed to be fixed. (e.g. foldable devices or devices with multiple displays)
+
+ val defaultDisplay: Display by lazy {
+ getMaxSizeDisplay()
+ }
+
+ val previewSize: Size by lazy {
+ calculatePreviewSize()
+ }
+
+ private fun getMaxSizeDisplay(): Display {
+ val displays = displayManager.displays
+ var maxDisplay: Display? = null
+ var maxDisplaySize = -1
+
+ // TODO(b/211945950, b/255170076): Handle STATE_OFF displays.
+
+ for (display: Display in displays) {
+ val displaySize = Point()
+ // TODO(b/230400472): Use WindowManager#getCurrentWindowMetrics(). Display#getRealSize()
+ // is deprecated since API level 31.
+ display.getRealSize(displaySize)
+ if (displaySize.x * displaySize.y > maxDisplaySize) {
+ maxDisplaySize = displaySize.x * displaySize.y
+ maxDisplay = display
+ }
+ }
+ return checkNotNull(maxDisplay) { "No displays found from ${displayManager.displays}!" }
+ }
+
+ /**
+ * Calculates the device's screen resolution, or MAX_PREVIEW_SIZE, whichever is smaller.
+ */
+ private fun calculatePreviewSize(): Size {
+ val displaySize = Point()
+ val display: Display = defaultDisplay
+ // TODO(b/230400472): Use WindowManager#getCurrentWindowMetrics(). Display#getRealSize()
+ // is deprecated since API level 31.
+ display.getRealSize(displaySize)
+ var displayViewSize: Size
+ displayViewSize = if (displaySize.x > displaySize.y) {
+ Size(displaySize.x, displaySize.y)
+ } else {
+ Size(displaySize.y, displaySize.x)
+ }
+ if (displayViewSize.width * displayViewSize.height
+ > MAX_PREVIEW_SIZE.width * MAX_PREVIEW_SIZE.height
+ ) {
+ displayViewSize = MAX_PREVIEW_SIZE
+ }
+ // TODO(b/230402463): Migrate extra cropping quirk from CameraX.
+ return displayViewSize
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt
index 0f8323fa..684eb88 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt
@@ -43,6 +43,7 @@
import androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER
import androidx.camera.core.impl.UseCaseConfigFactory
import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import kotlin.math.min
private val DEFAULT_PREVIEW_SIZE = Size(0, 0)
@@ -55,9 +56,10 @@
class MeteringRepeating(
private val cameraProperties: CameraProperties,
config: MeteringRepeatingConfig,
+ private val displayInfoManager: DisplayInfoManager
) : UseCase(config) {
- private val meteringSurfaceSize = cameraProperties.getMinimumPreviewSize()
+ private val meteringSurfaceSize = getProperPreviewSize()
private val deferrableSurfaceLock = Any()
@@ -65,9 +67,10 @@
private var deferrableSurface: DeferrableSurface? = null
override fun getDefaultConfig(applyDefaultConfig: Boolean, factory: UseCaseConfigFactory) =
- Builder(cameraProperties).useCaseConfig
+ Builder(cameraProperties, displayInfoManager).useCaseConfig
- override fun getUseCaseConfigBuilder(config: Config) = Builder(cameraProperties)
+ override fun getUseCaseConfigBuilder(config: Config) =
+ Builder(cameraProperties, displayInfoManager)
override fun onSuggestedResolutionUpdated(suggestedResolution: Size): Size {
updateSessionConfig(createPipeline().build())
@@ -120,28 +123,57 @@
}
}
- private fun CameraProperties.getMinimumPreviewSize(): Size {
- val map = metadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
- if (map == null) {
+ private fun CameraProperties.getOutputSizes(): Array<Size>? {
+ val map = metadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP] ?: run {
error { "Can not retrieve SCALER_STREAM_CONFIGURATION_MAP." }
- return DEFAULT_PREVIEW_SIZE
+ return null
}
- val outputSizes = if (Build.VERSION.SDK_INT < 23) {
+ return if (Build.VERSION.SDK_INT < 23) {
// ImageFormat.PRIVATE is only public after Android level 23. Therefore, use
// SurfaceTexture.class to get the supported output sizes before Android level 23.
map.getOutputSizes(SurfaceTexture::class.java)
} else {
map.getOutputSizes(ImageFormat.PRIVATE)
}
+ }
+
+ private fun getProperPreviewSize(): Size {
+ val outputSizes = cameraProperties.getOutputSizes()
if (outputSizes == null) {
error { "Can not get output size list." }
return DEFAULT_PREVIEW_SIZE
}
- check(outputSizes.isNotEmpty()) { "Output sizes empty" }
- return outputSizes.minWithOrNull { size1, size2 -> size1.area().compareTo(size2.area()) }!!
+ if (outputSizes.isEmpty()) {
+ error { "Output sizes empty" }
+ return DEFAULT_PREVIEW_SIZE
+ }
+
+ // TODO(b/256805716): get supported output sizes handling quirks.
+
+ outputSizes.sortBy { size -> size.width.toLong() * size.height.toLong() }
+
+ // Find maximum supported resolution that is <= min(VGA, display resolution)
+ // Using minimum supported size could cause some issue on certain devices.
+ val previewSize = displayInfoManager.previewSize
+ val maxSizeProduct =
+ min(640L * 480L, previewSize.width.toLong() * previewSize.height.toLong())
+
+ var previousSize: Size? = null
+ for (outputSize in outputSizes) {
+ val product = outputSize.width.toLong() * outputSize.height.toLong()
+ if (product == maxSizeProduct) {
+ return outputSize
+ } else if (product > maxSizeProduct) {
+ return previousSize ?: break // fallback to minimum size.
+ }
+ previousSize = outputSize
+ }
+
+ // If not found, return the minimum size.
+ return outputSizes[0]
}
class MeteringRepeatingConfig : UseCaseConfig<MeteringRepeating>, ImageInputConfig {
@@ -157,7 +189,10 @@
override fun getInputFormat() = ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
}
- class Builder(private val cameraProperties: CameraProperties) :
+ class Builder(
+ private val cameraProperties: CameraProperties,
+ private val displayInfoManager: DisplayInfoManager
+ ) :
UseCaseConfig.Builder<MeteringRepeating, MeteringRepeatingConfig, Builder> {
override fun getMutableConfig() = MutableOptionsBundle.create()
@@ -185,7 +220,7 @@
override fun setZslDisabled(disabled: Boolean) = this
override fun build(): MeteringRepeating {
- return MeteringRepeating(cameraProperties, useCaseConfig)
+ return MeteringRepeating(cameraProperties, useCaseConfig, displayInfoManager)
}
}
}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index cdef936..537adf9 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -66,7 +66,8 @@
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") // Java version required for Dagger
private val controls: java.util.Set<UseCaseCameraControl>,
private val camera2CameraControl: Camera2CameraControl,
- cameraProperties: CameraProperties
+ cameraProperties: CameraProperties,
+ displayInfoManager: DisplayInfoManager
) {
private val lock = Any()
@@ -76,7 +77,12 @@
@GuardedBy("lock")
private val activeUseCases = mutableSetOf<UseCase>()
- private val meteringRepeating by lazy { MeteringRepeating.Builder(cameraProperties).build() }
+ private val meteringRepeating by lazy {
+ MeteringRepeating.Builder(
+ cameraProperties,
+ displayInfoManager
+ ).build()
+ }
@Volatile
private var _activeComponent: UseCaseCameraComponent? = null
@@ -285,4 +291,4 @@
private fun <T> Collection<T>.only(predicate: (T) -> Boolean): Boolean {
return isNotEmpty() && all(predicate)
}
-}
\ No newline at end of file
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt
new file mode 100644
index 0000000..f550d39
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/DisplayInfoManagerTest.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.pipe.integration.impl
+
+import android.content.Context
+import android.graphics.Point
+import android.hardware.display.DisplayManager
+import android.util.Size
+import androidx.test.core.app.ApplicationProvider
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.ShadowDisplayManager
+
+@Suppress("DEPRECATION") // getRealSize
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+class DisplayInfoManagerTest {
+ private val displayInfoManager = DisplayInfoManager(ApplicationProvider.getApplicationContext())
+
+ private fun addDisplay(width: Int, height: Int) {
+ ShadowDisplayManager.addDisplay(String.format("w%ddp-h%ddp", width, height))
+ }
+
+ @Test
+ fun defaultDisplayIsDeviceDisplay_whenOneDisplay() {
+ // Arrange
+ val displayManager = (ApplicationProvider.getApplicationContext() as Context)
+ .getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ val currentDisplaySize = Point()
+ displayManager.displays[0].getRealSize(currentDisplaySize)
+
+ // Act
+ val size = Point()
+ displayInfoManager.defaultDisplay.getRealSize(size)
+
+ // Assert
+ assertEquals(currentDisplaySize, size)
+ }
+
+ @Test
+ fun defaultDisplayIsMaxSizeDisplay_whenMultipleDisplay() {
+ // Arrange
+ addDisplay(2000, 3000)
+ addDisplay(480, 640)
+
+ // Act
+ val size = Point()
+ displayInfoManager.defaultDisplay.getRealSize(size)
+
+ // Assert
+ assertEquals(Point(2000, 3000), size)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun throwsCorrectExceptionForDefaultDisplay_whenNoDisplay() {
+ // Arrange
+ ShadowDisplayManager.removeDisplay(0)
+
+ // Act
+ val size = Point()
+ displayInfoManager.defaultDisplay.getRealSize(size)
+ }
+
+ @Test
+ fun previewSizeIsProperSize_whenDisplaySmallerThan1080P() {
+ // Arrange
+ addDisplay(480, 640)
+
+ // Act & Assert
+ assertEquals(Size(640, 480), displayInfoManager.previewSize)
+ }
+
+ @Test
+ fun previewSizeIsMaxPreviewSize_whenDisplayLargerThan1080P() {
+ // Arrange
+ addDisplay(2000, 3000)
+
+ // Act & Assert
+ assertEquals(Size(1920, 1080), displayInfoManager.previewSize)
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeatingTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeatingTest.kt
new file mode 100644
index 0000000..f40a4cf
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeatingTest.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.pipe.integration.impl
+
+import android.hardware.camera2.CameraCharacteristics
+import android.os.Build
+import android.util.Size
+import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
+import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
+import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
+import androidx.test.core.app.ApplicationProvider
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.ShadowDisplayManager
+import org.robolectric.shadows.StreamConfigurationMapBuilder
+
+@RunWith(RobolectricCameraPipeTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class MeteringRepeatingTest {
+ companion object {
+ val dummyZeroSize = Size(0, 0)
+
+ val dummySizeListWithout640x480 = listOf(
+ Size(4160, 3120),
+ Size(1920, 1080),
+ Size(1280, 720),
+ Size(320, 240),
+ Size(240, 144),
+ )
+
+ val dummySizeListWith640x480 = listOf(
+ Size(4160, 3120),
+ Size(1920, 1080),
+ Size(1280, 720),
+ Size(640, 480),
+ Size(320, 240),
+ )
+
+ val dummySizeListWithoutSmaller = listOf(
+ Size(4160, 3120),
+ Size(1920, 1080),
+ Size(1280, 720)
+ )
+
+ val dummySizeListSmallerThan640x480 = listOf(
+ Size(320, 480),
+ Size(320, 240),
+ Size(240, 144),
+ )
+
+ fun getFakeMetadata(sizeList: List<Size>): FakeCameraMetadata {
+ val shuffledList = sizeList.shuffled()
+
+ val builder = StreamConfigurationMapBuilder.newBuilder()
+ for (size in shuffledList) {
+ builder.addOutputSize(size)
+ }
+
+ return FakeCameraMetadata(
+ mapOf(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP to builder.build(),
+ )
+ )
+ }
+ }
+
+ private lateinit var meteringRepeating: MeteringRepeating
+
+ private fun addDisplay(width: Int, height: Int) {
+ ShadowDisplayManager.addDisplay(String.format("w%ddp-h%ddp", width, height))
+ }
+
+ private fun getMeteringRepeatingAndInitDisplay(outputSizeList: List<Size>): MeteringRepeating {
+ for (size in outputSizeList) {
+ addDisplay(size.width, size.height)
+ }
+
+ return MeteringRepeating.Builder(
+ FakeCameraProperties(
+ getFakeMetadata(
+ outputSizeList
+ )
+ ),
+ DisplayInfoManager(ApplicationProvider.getApplicationContext())
+ ).build()
+ }
+
+ @Test
+ fun attachedSurfaceResolutionIsLargestLessThan640x480_when640x480NotPresentInOutputSizes() {
+ meteringRepeating = getMeteringRepeatingAndInitDisplay(dummySizeListWithout640x480)
+
+ meteringRepeating.updateSuggestedResolution(dummyZeroSize)
+
+ assertEquals(Size(320, 240), meteringRepeating.attachedSurfaceResolution)
+ }
+
+ @Test
+ fun attachedSurfaceResolutionIs640x480_when640x480PresentInOutputSizes() {
+ meteringRepeating = getMeteringRepeatingAndInitDisplay(dummySizeListWith640x480)
+
+ meteringRepeating.updateSuggestedResolution(dummyZeroSize)
+
+ assertEquals(Size(640, 480), meteringRepeating.attachedSurfaceResolution)
+ }
+
+ @Test
+ fun attachedSurfaceResolutionFallsBackToMinimum_whenAllOutputSizesLargerThan640x480() {
+ meteringRepeating = getMeteringRepeatingAndInitDisplay(dummySizeListWithoutSmaller)
+
+ meteringRepeating.updateSuggestedResolution(dummyZeroSize)
+
+ assertEquals(Size(1280, 720), meteringRepeating.attachedSurfaceResolution)
+ }
+
+ @Test
+ fun attachedSurfaceResolutionIsLargestWithinPreviewSize_whenAllOutputSizesLessThan640x480() {
+ meteringRepeating = getMeteringRepeatingAndInitDisplay(dummySizeListSmallerThan640x480)
+
+ meteringRepeating.updateSuggestedResolution(dummyZeroSize)
+
+ assertEquals(Size(320, 480), meteringRepeating.attachedSurfaceResolution)
+ }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
index 865ad2c..13ef7aa 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
@@ -27,6 +27,7 @@
import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraComponentBuilder
import androidx.camera.core.ImageCapture
import androidx.camera.core.Preview
+import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -183,6 +184,7 @@
FakeCamera2CameraControlCompat(),
useCaseThreads,
ComboRequestListener()
- )
+ ),
+ displayInfoManager = DisplayInfoManager(ApplicationProvider.getApplicationContext())
)
}