diff --git a/buildSrc-tests/lint-baseline.xml b/buildSrc-tests/lint-baseline.xml index 4046076b0dbb4..a3907916dc416 100644 --- a/buildSrc-tests/lint-baseline.xml +++ b/buildSrc-tests/lint-baseline.xml @@ -1,5 +1,5 @@ - + + errorLine1=" !System.getenv().containsKey("ANDROIDX_PROJECTS") &&" + errorLine2=" ~~~~~~"> @@ -310,8 +310,8 @@ + errorLine1=" !System.getenv().containsKey("PROJECT_PREFIX")" + errorLine2=" ~~~~~~"> @@ -319,8 +319,8 @@ + errorLine1=" System.getenv().containsKey("SSH_CLIENT") && !System.getenv().containsKey("DISPLAY")" + errorLine2=" ~~~~~~"> @@ -328,8 +328,8 @@ + errorLine1=" System.getenv().containsKey("SSH_CLIENT") && !System.getenv().containsKey("DISPLAY")" + errorLine2=" ~~~~~~"> @@ -337,8 +337,8 @@ + errorLine1=" return if (System.getenv("QT_QPA_PLATFORM") == "wayland") {" + errorLine2=" ~~~~~~"> @@ -346,8 +346,8 @@ + errorLine1=" val canonicalSdkPath = File(System.getenv("HOME"), relativeSdkPath)" + errorLine2=" ~~~~~~"> diff --git a/camera/camera-camera2-pipe/lint-baseline.xml b/camera/camera-camera2-pipe/lint-baseline.xml index 4f7577102ca2a..56ef9054d012b 100644 --- a/camera/camera-camera2-pipe/lint-baseline.xml +++ b/camera/camera-camera2-pipe/lint-baseline.xml @@ -1,23 +1,5 @@ - - - - - - - - - + 0) { "Width ($width) must be > 0" } require(height > 0) { "Height ($height) must be > 0" } require(capacity > 0) { "Capacity ($capacity) must be > 0" } - require(capacity <= IMAGEREADER_MAX_CAPACITY) { - "Capacity for creating new ImageSources is restricted to " + - "$IMAGEREADER_MAX_CAPACITY. Android has undocumented internal limits that " + - "are different depending on which device the ImageReader is created on." - } // Warnings for unsupported features: if (usageFlags != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { @@ -337,12 +320,6 @@ public class AndroidMultiResolutionImageReader( plaformApiCompat: PlatformApiCompat?, ): ImageReaderWrapper { require(capacity > 0) { "Capacity ($capacity) must be > 0" } - require(capacity <= AndroidImageReader.IMAGEREADER_MAX_CAPACITY) { - "Capacity for creating new ImageSources is restricted to " + - "${AndroidImageReader.IMAGEREADER_MAX_CAPACITY}. Android has undocumented " + - "internal limits that are different depending on which device the " + - "MultiResolutionImageReader is created on." - } if (enableConcurrentOutputs) { require(plaformApiCompat?.isMultiResolutionConcurrentReadersEnabled() == true) { "Concurrent MultiResolutionImageReaders are not supported on this device" diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageWriter.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageWriter.kt index 1c80885c3697e..be86a68b21c64 100644 --- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageWriter.kt +++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageWriter.kt @@ -25,7 +25,6 @@ import androidx.camera.camera2.pipe.InputStreamId import androidx.camera.camera2.pipe.StreamFormat import androidx.camera.camera2.pipe.compat.Api29Compat import androidx.camera.camera2.pipe.core.Log -import androidx.camera.camera2.pipe.media.AndroidImageReader.Companion.IMAGEREADER_MAX_CAPACITY import kotlin.reflect.KClass import kotlinx.atomicfu.atomic @@ -101,11 +100,6 @@ private constructor( handler: Handler, ): ImageWriterWrapper { require(maxImages > 0) { "Max images ($maxImages) must be > 0" } - require(maxImages <= IMAGEREADER_MAX_CAPACITY) { - "Max images for ImageWriters is restricted to " + - "$IMAGEREADER_MAX_CAPACITY to prevent overloading downstream " + - "consumer components." - } // Create and configure a new ImageWriter val imageWriter = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && format != null) { diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageReaderImageSource.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageReaderImageSource.kt index fdf0fb940fffc..b12a1d9c0c3cd 100644 --- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageReaderImageSource.kt +++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/ImageReaderImageSource.kt @@ -16,9 +16,11 @@ package androidx.camera.camera2.pipe.media +import android.hardware.camera2.CameraCharacteristics import android.media.ImageReader import android.os.Build import android.view.Surface +import androidx.camera.camera2.pipe.CameraMetadata import androidx.camera.camera2.pipe.CameraPipe import androidx.camera.camera2.pipe.CameraStream import androidx.camera.camera2.pipe.ImageSourceConfig @@ -26,8 +28,6 @@ import androidx.camera.camera2.pipe.OutputId import androidx.camera.camera2.pipe.StreamId import androidx.camera.camera2.pipe.core.Log import androidx.camera.camera2.pipe.core.Threads -import androidx.camera.camera2.pipe.media.AndroidImageReader.Companion.IMAGEREADER_MAX_CAPACITY -import androidx.camera.camera2.pipe.media.ImageReaderImageSource.Companion.IMAGE_SOURCE_CAPACITY import androidx.camera.camera2.pipe.media.OutputImage.Companion.toLogString import javax.inject.Inject import kotlin.reflect.KClass @@ -35,9 +35,24 @@ import kotlinx.atomicfu.atomic internal class ImageReaderImageSources @Inject -constructor(private val threads: Threads, cameraPipeConfig: CameraPipe.Config) : ImageSources { +constructor( + private val threads: Threads, + cameraPipeConfig: CameraPipe.Config, + cameraMetadata: CameraMetadata, +) : ImageSources { private val platformApiCompat = cameraPipeConfig.platformApiCompat + // See: b/172464059 + // + // The ImageReader has an internal limit of 64 images by design, but depending on the device + // specific camera HAL (Which can be different per device) there is an additional number of + // images that are reserved by the Camera HAL which reduces this number. If, for example, + // the HAL reserves 8 images, you have a maximum of 56 (64 - 8). + private val maxImageReaderCapacity by lazy { + ImageReaderImageSource.BUFFER_QUEUE_MAX_CAPACITY - + checkNotNull(cameraMetadata[CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH]) + } + override fun createImageSource( cameraStream: CameraStream, imageSourceConfig: ImageSourceConfig, @@ -62,11 +77,6 @@ constructor(private val threads: Threads, cameraPipeConfig: CameraPipe.Config) : ): ImageSource { require(cameraStream.outputs.isNotEmpty()) { "$cameraStream must have outputs." } require(capacity > 0) { "Capacity ($capacity) must be > 0" } - require(capacity <= IMAGE_SOURCE_CAPACITY) { - "Capacity for creating new ImageReaderImageSources is restricted to " + - "$IMAGE_SOURCE_CAPACITY. Android has undocumented internal limits that can vary " + - "per device." - } if (enableConcurrentOutputs) { check(cameraStream.outputs.size > 1) { "Cannot enable concurrent outputs for a single output camera stream." @@ -76,13 +86,7 @@ constructor(private val threads: Threads, cameraPipeConfig: CameraPipe.Config) : val handlerProvider = { threads.camera2Handler } val executorProvider = { threads.lightweightExecutor } - // Increase the internal capacity of the ImageReader so that the final capacity of the - // ImageSource matches the requested capacity. - // - // As an example, if the consumer requests "40", the ImageReader will be created with - // a capacity of "42", which will allow the consumer to hold exactly 40 images without - // stalling the camera pipeline. - val imageReaderCapacity = capacity + ImageReaderImageSource.IMAGE_SOURCE_CAPACITY_MARGIN + val imageReaderCapacity = clampImageReaderCapacity(capacity, maxImageReaderCapacity) if (cameraStream.outputs.size == 1) { val output = cameraStream.outputs.single() @@ -146,6 +150,22 @@ constructor(private val threads: Threads, cameraPipeConfig: CameraPipe.Config) : // but it was not possible to create it due to the SDK the code is running on. throw IllegalStateException("Failed to create an ImageSource for $cameraStream!") } + + private fun clampImageReaderCapacity(desired: Int, maxImageReaderCapacity: Int): Int { + // Increase the internal capacity of the ImageReader so that the final capacity of the + // ImageSource matches the requested capacity. + // + // As an example, if the consumer requests "40", the ImageReader will be created with + // a capacity of "42", which will allow the consumer to hold exactly 40 images without + // stalling the camera pipeline. + return maxOf( + 1 + ImageReaderImageSource.IMAGE_SOURCE_CAPACITY_MARGIN, + minOf( + desired + ImageReaderImageSource.IMAGE_SOURCE_CAPACITY_MARGIN, + maxImageReaderCapacity, + ), + ) + } } /** An ImageReaderImageSource implements an [ImageSource] using an [ImageReader] */ @@ -154,9 +174,8 @@ public class ImageReaderImageSource( private val maxImages: Int, ) : ImageSource { public companion object { + public const val BUFFER_QUEUE_MAX_CAPACITY: Int = 64 public const val IMAGE_SOURCE_CAPACITY_MARGIN: Int = 2 - public const val IMAGE_SOURCE_CAPACITY: Int = - IMAGEREADER_MAX_CAPACITY - IMAGE_SOURCE_CAPACITY_MARGIN public fun create(imageReader: ImageReaderWrapper): ImageSource { // Reduce the maxImages of the ImageSource relative to the ImageReader to ensure there diff --git a/camera/camera-testing/lint-baseline.xml b/camera/camera-testing/lint-baseline.xml index eed1991450185..5ce5af7b6607a 100644 --- a/camera/camera-testing/lint-baseline.xml +++ b/camera/camera-testing/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/car/app/app-samples/showcase/automotive/lint-baseline.xml b/car/app/app-samples/showcase/automotive/lint-baseline.xml new file mode 100644 index 0000000000000..b6b01e1ded10c --- /dev/null +++ b/car/app/app-samples/showcase/automotive/lint-baseline.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/car/app/app/lint-baseline.xml b/car/app/app/lint-baseline.xml index 0b7e401932944..39f751b8e95e7 100644 --- a/car/app/app/lint-baseline.xml +++ b/car/app/app/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - + + + + + + + diff --git a/compose/animation/animation-graphics/lint-baseline.xml b/compose/animation/animation-graphics/lint-baseline.xml index aeca42043cd1f..d0153641798ce 100644 --- a/compose/animation/animation-graphics/lint-baseline.xml +++ b/compose/animation/animation-graphics/lint-baseline.xml @@ -1,5 +1,5 @@ - + - + - - - - - - - - - + - + - + - + + + + + + + + + + + + + + + + diff --git a/compose/material3/material3/lint-baseline.xml b/compose/material3/material3/lint-baseline.xml index 646d439dc5207..29c2d288bf115 100644 --- a/compose/material3/material3/lint-baseline.xml +++ b/compose/material3/material3/lint-baseline.xml @@ -1,5 +1,5 @@ - + - + + + + + - + - - - - - - - - + errorLine1="@Preview @Composable private fun SimplePathPreview() = RemotePreview { SimplePath() }" + errorLine2=" ~~~~~~~~~~~~~"> @@ -31,8 +13,8 @@ + errorLine1="@Preview @Composable private fun SimplePathPreview() = RemotePreview { SimplePath() }" + errorLine2=" ~~~~~~~~~~~~~~~~"> @@ -40,8 +22,8 @@ + errorLine1="private fun CanvasCalendarMonthPreview() = RemotePreview { CanvasCalendarMonth() }" + errorLine2=" ~~~~~~~~~~~~~"> @@ -49,8 +31,8 @@ + errorLine1="private fun CanvasCalendarMonthPreview() = RemotePreview { CanvasCalendarMonth() }" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -58,8 +40,8 @@ + errorLine1="@Preview @Composable private fun ScrollViewDemoPreview() = RemotePreview { ScrollViewDemo() }" + errorLine2=" ~~~~~~~~~~~~~"> @@ -67,64 +49,10 @@ + errorLine1="@Preview @Composable private fun ScrollViewDemoPreview() = RemotePreview { ScrollViewDemo() }" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/compose/test-utils/lint-baseline.xml b/compose/test-utils/lint-baseline.xml index df199942d568c..02d7b5f36df3f 100644 --- a/compose/test-utils/lint-baseline.xml +++ b/compose/test-utils/lint-baseline.xml @@ -1,5 +1,5 @@ - + - + - - - - - - - - diff --git a/compose/ui/ui-test/lint-baseline.xml b/compose/ui/ui-test/lint-baseline.xml index d975a0b534885..c23fbc37e2de4 100644 --- a/compose/ui/ui-test/lint-baseline.xml +++ b/compose/ui/ui-test/lint-baseline.xml @@ -1,23 +1,5 @@ - - - - - - - - - + - - - - - - - - - - - diff --git a/compose/ui/ui-text/lint-baseline.xml b/compose/ui/ui-text/lint-baseline.xml index 3231e1898cb5d..fd0816cfdf317 100644 --- a/compose/ui/ui-text/lint-baseline.xml +++ b/compose/ui/ui-text/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/compose/ui/ui-tooling-preview/samples/lint-baseline.xml b/compose/ui/ui-tooling-preview/samples/lint-baseline.xml new file mode 100644 index 0000000000000..c897742f1cba1 --- /dev/null +++ b/compose/ui/ui-tooling-preview/samples/lint-baseline.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/compose/ui/ui-viewbinding/samples/build.gradle b/compose/ui/ui-viewbinding/samples/build.gradle index 475b6b8267ce2..9b9d6ac784041 100644 --- a/compose/ui/ui-viewbinding/samples/build.gradle +++ b/compose/ui/ui-viewbinding/samples/build.gradle @@ -54,7 +54,7 @@ androidx { type = SoftwareType.SAMPLES inceptionYear = "2019" description = "Contains the sample code for the Androidx Compose UI Simple Unit Classes" - kotlinTarget = KotlinTarget.KOTLIN_2_2 + kotlinTarget = KotlinTarget.KOTLIN_2_3 } android { diff --git a/compose/ui/ui-viewbinding/samples/lint-baseline.xml b/compose/ui/ui-viewbinding/samples/lint-baseline.xml deleted file mode 100644 index 18bd60167d68b..0000000000000 --- a/compose/ui/ui-viewbinding/samples/lint-baseline.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/UiDemos.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/UiDemos.kt index b4362818ec5e2..ba10b54f760ea 100644 --- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/UiDemos.kt +++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/UiDemos.kt @@ -25,7 +25,6 @@ import androidx.compose.integration.demos.common.ComposableDemo import androidx.compose.integration.demos.common.DemoCategory import androidx.compose.ui.demos.accessibility.AccessibilityClippingDemo import androidx.compose.ui.demos.accessibility.AccessibilityShapeOffscreenDemo -import androidx.compose.ui.demos.accessibility.AccessibilitySiblingBoundsDemo import androidx.compose.ui.demos.accessibility.LinearProgressIndicatorDemo import androidx.compose.ui.demos.accessibility.NestedContainersFalseDemo import androidx.compose.ui.demos.accessibility.NestedContainersTrueDemo @@ -346,7 +345,6 @@ val AccessibilityDemos = ComposableDemo("Scrolling Tooltip scene") { SampleScrollingTooltipScreen() }, ComposableDemo("Accessibility Shapes") { AccessibilityShapeOffscreenDemo() }, ComposableDemo("Accessibility Clipping Demo") { AccessibilityClippingDemo() }, - ComposableDemo("Accessibility Sibling Bounds Demo") { AccessibilitySiblingBoundsDemo() }, ), ) diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/accessibility/AccessibilitySiblingBoundsDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/accessibility/AccessibilitySiblingBoundsDemo.kt deleted file mode 100644 index 254f4d31af877..0000000000000 --- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/accessibility/AccessibilitySiblingBoundsDemo.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2026 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.compose.ui.demos.accessibility - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp - -@Composable -fun AccessibilitySiblingBoundsDemo() { - Column( - Modifier.fillMaxSize().padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - Text( - "Each blue box below is 26dp tall and clickable, with only 2dp spacing between" + - " them. Because they are smaller than the 48dp minimum touch target, their" + - " accessibility bounds are expanded. Use TalkBack or the a11y inspector to" + - " verify that each box's reported bounds are at least as large as the visible" + - " box. The touch target expansion of one sibling should not clip another's" + - " bounds." - ) - - Column( - modifier = Modifier.padding(16.dp), - verticalArrangement = Arrangement.spacedBy(2.dp), - ) { - repeat(10) { - Box( - Modifier.fillMaxWidth() - .height(26.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color.Blue) - .clickable { /* Needed to make it use touch bounds expansion. */ } - ) - } - } - } -} diff --git a/compose/ui/ui/lint-baseline.xml b/compose/ui/ui/lint-baseline.xml index 921994ede7c03..618a3f0c232c0 100644 --- a/compose/ui/ui/lint-baseline.xml +++ b/compose/ui/ui/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - - - - - + + + + + - - - - + + + + diff --git a/compose/ui/ui/src/androidDeviceTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidDeviceTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt index 4571fa70db9ca..52ab09f0c99f7 100644 --- a/compose/ui/ui/src/androidDeviceTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt +++ b/compose/ui/ui/src/androidDeviceTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt @@ -4598,75 +4598,6 @@ class AndroidAccessibilityTest { } } - @Test - fun testBounds_smallClickableSiblings_notClippedByTouchTargetExpansion() { - // Small clickable siblings (smaller than 48dp min touch target) in a Column with - // tight spacing should each retain at least their layout bounds height, even - // though their expanded touch targets overlap with adjacent siblings. - setContent { - CompositionLocalProvider(LocalDensity provides Density(1f)) { - Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { - repeat(3) { i -> - Box(Modifier.size(100.dp, 30.dp).clickable {}.testTag("item$i")) - } - } - } - } - - val id0 = rule.onNodeWithTag("item0").semanticsId() - val id1 = rule.onNodeWithTag("item1").semanticsId() - val id2 = rule.onNodeWithTag("item2").semanticsId() - - val bounds0 = Rect() - val bounds1 = Rect() - val bounds2 = Rect() - rule.runOnIdle { - createAccessibilityNodeInfo(id0).getBoundsInScreen(bounds0) - createAccessibilityNodeInfo(id1).getBoundsInScreen(bounds1) - createAccessibilityNodeInfo(id2).getBoundsInScreen(bounds2) - } - - // Each item's reported bounds should be at least as tall as its layout height - // (30px). Before the fix, items' bounds were clipped by the touch target - // expansion of later siblings, resulting in heights smaller than the layout size. - assertThat(bounds0.height()).isAtLeast(30) - assertThat(bounds1.height()).isAtLeast(30) - assertThat(bounds2.height()).isAtLeast(30) - } - - @Test - fun testBounds_smallClickableSiblings_row_notClippedByTouchTargetExpansion() { - // Same as above but in a Row — verifies horizontal touch target expansion - // doesn't clip siblings' layout bounds. - setContent { - CompositionLocalProvider(LocalDensity provides Density(1f)) { - Row(horizontalArrangement = Arrangement.spacedBy(2.dp)) { - repeat(3) { i -> - Box(Modifier.size(30.dp, 100.dp).clickable {}.testTag("item$i")) - } - } - } - } - - val id0 = rule.onNodeWithTag("item0").semanticsId() - val id1 = rule.onNodeWithTag("item1").semanticsId() - val id2 = rule.onNodeWithTag("item2").semanticsId() - - val bounds0 = Rect() - val bounds1 = Rect() - val bounds2 = Rect() - rule.runOnIdle { - createAccessibilityNodeInfo(id0).getBoundsInScreen(bounds0) - createAccessibilityNodeInfo(id1).getBoundsInScreen(bounds1) - createAccessibilityNodeInfo(id2).getBoundsInScreen(bounds2) - } - - // Each item's reported bounds should be at least as wide as its layout width (30px). - assertThat(bounds0.width()).isAtLeast(30) - assertThat(bounds1.width()).isAtLeast(30) - assertThat(bounds2.width()).isAtLeast(30) - } - @Test fun testPaneAppear() { var isPaneVisible by mutableStateOf(false) diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt index e9b2ffcbd03e9..c2dcf424429d9 100644 --- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt +++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt @@ -214,14 +214,12 @@ internal fun SemanticsOwner.getAllUncoveredSemanticsNodesToIntObjectMap( return } - val touchBounds = currentNode.touchBoundsInRoot // Use unclipped bounds for intersection and reporting within this context only if the // node is fully off-screen. Otherwise, continue using the clipped bounds. val currentBounds = - touchBounds + currentNode.touchBoundsInRoot .run { if (isEmpty) currentNode.unclippedBoundsInRoot else this } .roundToIntRect() - region.set(currentBounds) if (region.intersect(unaccountedSpace)) { // For nodes that are partially visible in the root, we will continue reporting @@ -243,16 +241,7 @@ internal fun SemanticsOwner.getAllUncoveredSemanticsNodesToIntObjectMap( ) } if (currentNode.isImportantForAccessibility()) { - // Use layout bounds (without touch target expansion) for the - // subtraction so that minimum touch target padding doesn't cause - // adjacent siblings to clip each other's reported bounds. - val layoutBounds = - if (touchBounds.isEmpty) { - currentBounds // already using unclippedBoundsInRoot - } else { - currentNode.boundsInRoot.roundToIntRect() - } - unaccountedSpace.difference(layoutBounds) + unaccountedSpace.difference(currentBounds) } } } @@ -320,10 +309,7 @@ internal fun SemanticsOwner.getAllUncoveredSemanticsNodesToIntObjectMap( } } if (currentNode.isImportantForAccessibility()) { - // Use layout bounds (without touch target expansion) for the - // subtraction so that minimum touch target padding doesn't cause - // adjacent siblings to clip each other's reported bounds. - unaccountedSpace.difference(currentNode.boundsInRoot.roundToIntRect()) + unaccountedSpace.difference(touchBoundsInRoot) } } else { if (currentNode.isFake) { diff --git a/constraintlayout/constraintlayout-compose/lint-baseline.xml b/constraintlayout/constraintlayout-compose/lint-baseline.xml index b3f1bce1c2fdf..fc65c152054b1 100644 --- a/constraintlayout/constraintlayout-compose/lint-baseline.xml +++ b/constraintlayout/constraintlayout-compose/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + errorLine1=" return fetchActiveWidgets().filter {" + errorLine2=" ~~~~~~"> @@ -13,8 +13,8 @@ + errorLine1=" result.map { instance ->" + errorLine2=" ~~~"> diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70a83e8ddecaa..bd7811773552c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,14 +2,14 @@ # ----------------------------------------------------------------------------- # All of the following should be updated in sync. # ----------------------------------------------------------------------------- -androidGradlePlugin = "9.2.0-alpha05" +androidGradlePlugin = "9.2.0-alpha07" # NOTE: When updating the lint version we also need to update the `api` version # supported by `IssueRegistry`'s.' For e.g. r.android.com/1331903 -androidLint = "32.2.0-alpha05" +androidLint = "32.2.0-alpha07" # Once you have a chosen version of AGP to upgrade to, go to # https://developer.android.com/studio/archive and find the matching version of Studio. -androidStudioIj = "2025.3.4.1" -androidStudioName = "panda4-canary1" +androidStudioIj = "2025.3.4.3" +androidStudioName = "panda4-canary3" # For IntelliJ download via intellij gradle task intelliJVersion = "2026.1" # ----------------------------------------------------------------------------- diff --git a/health/connect/connect-client/lint-baseline.xml b/health/connect/connect-client/lint-baseline.xml index 381356704607d..8b0418946c6bf 100644 --- a/health/connect/connect-client/lint-baseline.xml +++ b/health/connect/connect-client/lint-baseline.xml @@ -1,23 +1,5 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraryversions.toml b/libraryversions.toml index ad1edb25f5f56..8463e51a0bdd3 100644 --- a/libraryversions.toml +++ b/libraryversions.toml @@ -69,7 +69,7 @@ EXIFINTERFACE = "1.4.0-rc01" FRAGMENT = "1.9.0-alpha01" FUTURES = "1.4.0-alpha01" GLANCE = "1.3.0-alpha01" -GLANCE_WEAR = "1.0.0-alpha07" +GLANCE_WEAR = "1.0.0-alpha08" GRAPHICS_CORE = "1.1.0-beta01" GRAPHICS_FILTERS = "1.0.0-alpha01" GRAPHICS_PATH = "1.1.0-rc01" diff --git a/lifecycle/lifecycle-runtime-compose/lint-baseline.xml b/lifecycle/lifecycle-runtime-compose/lint-baseline.xml index 137e3082b99c6..3c56c5d28fb8b 100644 --- a/lifecycle/lifecycle-runtime-compose/lint-baseline.xml +++ b/lifecycle/lifecycle-runtime-compose/lint-baseline.xml @@ -1,5 +1,5 @@ - + - - - - - + - - - - - + - - - - - - - - - + + errorLine1=" state.insert(0, REFRESH, pages[1], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -193,8 +193,8 @@ + errorLine1=" state.insert(0, REFRESH, pages[1], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -202,8 +202,8 @@ + errorLine1=" state.insert(0, PREPEND, pages[0], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -211,8 +211,8 @@ + errorLine1=" state.insert(0, PREPEND, pages[0], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -220,8 +220,8 @@ + errorLine1=" state.insert(0, APPEND, pages[2], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -229,8 +229,8 @@ + errorLine1=" state.insert(0, APPEND, pages[2], null)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> diff --git a/pdf/pdf-viewer/lint-baseline.xml b/pdf/pdf-viewer/lint-baseline.xml deleted file mode 100644 index 3b4ad8c98ecf5..0000000000000 --- a/pdf/pdf-viewer/lint-baseline.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/samples/AndroidXDemos/build.gradle b/samples/AndroidXDemos/build.gradle index 53300883e3799..700de2678084e 100644 --- a/samples/AndroidXDemos/build.gradle +++ b/samples/AndroidXDemos/build.gradle @@ -36,6 +36,7 @@ android { buildTypes { release { minifyEnabled = true + shrinkResources = true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt") } } diff --git a/samples/MediaRoutingDemo/build.gradle b/samples/MediaRoutingDemo/build.gradle index f12b0266bf327..26ddb15f413a2 100644 --- a/samples/MediaRoutingDemo/build.gradle +++ b/samples/MediaRoutingDemo/build.gradle @@ -28,6 +28,7 @@ android { buildTypes { release { minifyEnabled = true + shrinkResources = true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt") } } diff --git a/security/security-state/lint-baseline.xml b/security/security-state/lint-baseline.xml index f63f520080bc9..a0a0f33c6ed1b 100644 --- a/security/security-state/lint-baseline.xml +++ b/security/security-state/lint-baseline.xml @@ -1,14 +1,5 @@ - - - - - + - + + + + + + + + diff --git a/wear/compose/compose-material/samples/lint-baseline.xml b/wear/compose/compose-material/samples/lint-baseline.xml index ac3d5172ad18e..846d164045ea1 100644 --- a/wear/compose/compose-material/samples/lint-baseline.xml +++ b/wear/compose/compose-material/samples/lint-baseline.xml @@ -1,14 +1,5 @@ - - - - - + - + - - - - - - - - diff --git a/wear/compose/compose-navigation3/samples/lint-baseline.xml b/wear/compose/compose-navigation3/samples/lint-baseline.xml new file mode 100644 index 0000000000000..32009c8a6df8d --- /dev/null +++ b/wear/compose/compose-navigation3/samples/lint-baseline.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/wear/compose/remote/remote-material3/samples/lint-baseline.xml b/wear/compose/remote/remote-material3/samples/lint-baseline.xml new file mode 100644 index 0000000000000..9968e96da431e --- /dev/null +++ b/wear/compose/remote/remote-material3/samples/lint-baseline.xml @@ -0,0 +1,1264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wear/tiles/tiles/lint-baseline.xml b/wear/tiles/tiles/lint-baseline.xml index 81f58a8fd2981..98f5d0098f0f3 100644 --- a/wear/tiles/tiles/lint-baseline.xml +++ b/wear/tiles/tiles/lint-baseline.xml @@ -1,5 +1,5 @@ - + + errorLine1=" resources.toProto().toByteArray(), Base64.DEFAULT));" + errorLine2=" ~~~~~~~"> @@ -14638,8 +14638,8 @@ + errorLine1=" .hasRendererSchemaVersion()) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> diff --git a/wear/tiles/tiles/snippet-samples/lint-baseline.xml b/wear/tiles/tiles/snippet-samples/lint-baseline.xml new file mode 100644 index 0000000000000..24ac071649806 --- /dev/null +++ b/wear/tiles/tiles/snippet-samples/lint-baseline.xml @@ -0,0 +1,652 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wear/watchface/watchface-complications-data-source/lint-baseline.xml b/wear/watchface/watchface-complications-data-source/lint-baseline.xml index 9013c0bcd031d..b946ea48e3e39 100644 --- a/wear/watchface/watchface-complications-data-source/lint-baseline.xml +++ b/wear/watchface/watchface-complications-data-source/lint-baseline.xml @@ -1,5 +1,5 @@ - + + errorLine1=" bundle?.getInt(BUNDLE_KEY_IS_SAFE_FOR_WATCHFACE, TargetWatchFaceSafety.UNKNOWN)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> @@ -40,8 +40,8 @@ + errorLine1=" ?: TargetWatchFaceSafety.UNKNOWN" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> @@ -49,8 +49,8 @@ + errorLine1=" bundle?.getInt(BUNDLE_KEY_IS_SAFE_FOR_WATCHFACE, TargetWatchFaceSafety.UNKNOWN)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> @@ -58,8 +58,8 @@ + errorLine1=" ?: TargetWatchFaceSafety.UNKNOWN" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> diff --git a/work/integration-tests/testapp/lint-baseline.xml b/work/integration-tests/testapp/lint-baseline.xml index ab8f3ac9bcd77..79a6f8d55d806 100644 --- a/work/integration-tests/testapp/lint-baseline.xml +++ b/work/integration-tests/testapp/lint-baseline.xml @@ -1,5 +1,5 @@ - + + + + + - "This device does not have a front-facing (selfie) camera" - is IllegalArgumentException -> - "${config.cameraFacingDirection} is not supported." - else -> throw (e) - } - throw UnsupportedOperationException(message, e) - } - } - - if (Build.VERSION.SDK_INT >= 27) { - setTextureUpdateModeToHardwareBuffer(arConfig) - } else { - setTextureUpdateModeToExternalOES(arConfig) - } - - arConfig.planeFindingMode = - if (config.planeTracking == PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) { - PlaneFindingMode.HORIZONTAL_AND_VERTICAL - } else { - PlaneFindingMode.DISABLED - } - - if (config.handTracking != HandTrackingMode.DISABLED) { - throw UnsupportedOperationException() - } - - arConfig.depthMode = - when (config.depthEstimation) { - DepthEstimationMode.SMOOTH_ONLY, - DepthEstimationMode.SMOOTH_AND_RAW -> DepthMode.AUTOMATIC - DepthEstimationMode.RAW_ONLY -> DepthMode.RAW_DEPTH_ONLY - else -> DepthMode.DISABLED - } - - perceptionManager.setDepthEstimationMode(config.depthEstimation) - - if (config.anchorPersistence != AnchorPersistenceMode.DISABLED) { - throw UnsupportedOperationException() - } - - arConfig.augmentedFaceMode = - when (config.faceTracking) { - FaceTrackingMode.MESHES -> AugmentedFaceMode.MESH3D - FaceTrackingMode.DISABLED -> AugmentedFaceMode.DISABLED - else -> throw UnsupportedOperationException() - } - - arConfig.geospatialMode = - if (config.geospatial == androidx.xr.runtime.GeospatialMode.VPS_AND_GPS) { - GeospatialMode.ENABLED - } else { - GeospatialMode.DISABLED - } - - try { - _session.configure(arConfig) - } catch (e: FineLocationPermissionNotGrantedException) { - throw SecurityException(e) - } catch (e: ARCore1xGooglePlayServicesLocationLibraryNotLinkedException) { - throw LibraryNotLinkedException("com.google.android.gms:play-services-location", e) - } catch (e: UnsupportedConfigurationException) { - throw UnsupportedOperationException(e) - } - this.config = config } - override fun resume() { - _session.resume() - } + override fun resume() {} override suspend fun update(): ComparableTimeMark { - // Delay for average time between frames based on camera config fps setting. This frees up - // the thread this method is scheduled to run on to do other work. Note that this can result - // in the emission of duplicated CoreStates by the core Session if the underlying ARCore 1.x - // Session has not produced a new frame by the time the delay has expired. - val avgFps = - (_session.cameraConfig.fpsRange.lower + _session.cameraConfig.fpsRange.upper) / 2 - val delayTime = (1000L / avgFps).milliseconds - delay(delayTime) - - perceptionManager.update() - return timeSource.markNow() } - override fun pause() { - _session.pause() - } - - override fun stop() { - perceptionManager.dispose() - _session.close() - } - - // Verify that ARCore is installed and using the current version. - // This implementation is derived from - // https://developers.google.com/ar/develop/java/session-config#verify_that_arcore_is_installed_and_up_to_date - internal fun checkARCoreSupportedAndUpToDate(context: Context) { - when (arCoreApkInstance.checkAvailability(context)) { - Availability.SUPPORTED_INSTALLED -> { - return - } - Availability.SUPPORTED_APK_TOO_OLD, - Availability.SUPPORTED_NOT_INSTALLED -> { - throw ApkNotInstalledException(ARCORE_PACKAGE_NAME) - } - Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE -> { - XrLog.error { - "Session cannot be created because ARCore is not supported on this device." - } - throw UnsupportedDeviceException() - } - Availability.UNKNOWN_CHECKING -> { - throw ApkCheckAvailabilityInProgressException(ARCORE_PACKAGE_NAME) - } - Availability.UNKNOWN_ERROR, - Availability.UNKNOWN_TIMED_OUT -> { - throw ApkCheckAvailabilityErrorException(ARCORE_PACKAGE_NAME) - } - } - } - - private fun setTextureUpdateModeToExternalOES(config: ArConfig) { - config.textureUpdateMode = TextureUpdateMode.BIND_TO_TEXTURE_EXTERNAL_OES - } + override fun pause() {} - @RequiresApi(27) - private fun setTextureUpdateModeToHardwareBuffer(config: ArConfig) { - config.textureUpdateMode = TextureUpdateMode.EXPOSE_HARDWARE_BUFFER - } - - private companion object { - const private val ARCORE_PACKAGE_NAME = "com.google.ar.core" - } + override fun stop() {} } diff --git a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntime.kt b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntime.kt index e2c668b5984c1..3905959fa7b32 100644 --- a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntime.kt +++ b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntime.kt @@ -16,8 +16,12 @@ package androidx.xr.arcore.playservices +import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi import androidx.annotation.RestrictTo import androidx.xr.arcore.runtime.PerceptionRuntime +import androidx.xr.runtime.AnchorPersistenceMode import androidx.xr.runtime.CameraFacingDirection import androidx.xr.runtime.Config import androidx.xr.runtime.Config.ConfigMode @@ -25,42 +29,171 @@ import androidx.xr.runtime.DepthEstimationMode import androidx.xr.runtime.DeviceTrackingMode import androidx.xr.runtime.FaceTrackingMode import androidx.xr.runtime.GeospatialMode +import androidx.xr.runtime.HandTrackingMode import androidx.xr.runtime.PlaneTrackingMode +import androidx.xr.runtime.XrLog +import androidx.xr.runtime.internal.ApkCheckAvailabilityErrorException +import androidx.xr.runtime.internal.ApkCheckAvailabilityInProgressException +import androidx.xr.runtime.internal.ApkNotInstalledException +import androidx.xr.runtime.internal.LibraryNotLinkedException +import androidx.xr.runtime.internal.UnsupportedDeviceException +import com.google.ar.core.ArCoreApk +import com.google.ar.core.ArCoreApk.Availability +import com.google.ar.core.Config as ArConfig import com.google.ar.core.Config as ArCoreConfig +import com.google.ar.core.Config.AugmentedFaceMode +import com.google.ar.core.Config.DepthMode +import com.google.ar.core.Config.GeospatialMode as ArGeospatialMode +import com.google.ar.core.Config.PlaneFindingMode +import com.google.ar.core.Config.TextureUpdateMode +import com.google.ar.core.Session +import com.google.ar.core.exceptions.FineLocationPermissionNotGrantedException +import com.google.ar.core.exceptions.GooglePlayServicesLocationLibraryNotLinkedException as ARCore1xGooglePlayServicesLocationLibraryNotLinkedException +import com.google.ar.core.exceptions.UnsupportedConfigurationException import kotlin.time.ComparableTimeMark +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.delay /** * Implementation of the [androidx.xr.arcore.runtime.PerceptionRuntime] interface using ARCore. * + * @property context The [Context] instance * @property lifecycleManager that manages the lifecycle of the ARCore session * @property perceptionManager that manages the perception capabilities of a runtime using ARCore + * @property timeSource the [ArCoreTimeSource] instance + * @property config the current [Config] of the session */ @RestrictTo(RestrictTo.Scope.LIBRARY) public class ArCoreRuntime internal constructor( + private val context: Context, override val lifecycleManager: ArCoreManager, override val perceptionManager: ArCorePerceptionManager, + internal val timeSource: ArCoreTimeSource, + private val arCoreApkInstance: ArCoreApk = ArCoreApk.getInstance(), ) : PerceptionRuntime { - override var config: Config = Config() + + internal lateinit var _session: Session + + /** + * The underlying [Session] instance. + * + * @sample androidx.xr.arcore.samples.getARCoreSession + */ + @UnsupportedArCoreCompatApi public fun session(): Session = _session + + // TODO(b/392660855): Disable all features by default once this API is fully implemented. + public override var config: Config = Config() + private set(value) { + this.lifecycleManager.configure(config) + field = value + } override fun initialize() { - lifecycleManager.create() + checkARCoreSupportedAndUpToDate(context) + _session = Session(context) + perceptionManager.session = _session + perceptionManager.geospatial.arCoreSession = _session } override fun resume() { - lifecycleManager.resume() + _session.resume() } override fun pause() { - lifecycleManager.pause() + _session.pause() } - override suspend fun update(): ComparableTimeMark? { - return lifecycleManager.update() + override suspend fun update(): ComparableTimeMark { + // Delay for average time between frames based on camera config fps setting. This frees up + // the thread this method is scheduled to run on to do other work. Note that this can result + // in the emission of duplicated CoreStates by the core Session if the underlying ARCore 1.x + // Session has not produced a new frame by the time the delay has expired. + val avgFps = + (_session.cameraConfig.fpsRange.lower + _session.cameraConfig.fpsRange.upper) / 2 + val delayTime = (1000L / avgFps).milliseconds + delay(delayTime) + + perceptionManager.update() + + return timeSource.markNow() } override fun configure(config: Config) { - lifecycleManager.configure(config) + val arConfig = _session.config + + if (config.cameraFacingDirection != this.config.cameraFacingDirection) { + try { + perceptionManager.setCameraFacingDirection(config.cameraFacingDirection) + } catch (e: Exception) { + val message = + when (e) { + is UnsupportedDeviceException -> + "This device does not have a front-facing (selfie) camera" + is IllegalArgumentException -> + "${config.cameraFacingDirection} is not supported." + else -> throw (e) + } + throw UnsupportedOperationException(message, e) + } + } + + if (Build.VERSION.SDK_INT >= 27) { + setTextureUpdateModeToHardwareBuffer(arConfig) + } else { + setTextureUpdateModeToExternalOES(arConfig) + } + + arConfig.planeFindingMode = + if (config.planeTracking == PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) { + PlaneFindingMode.HORIZONTAL_AND_VERTICAL + } else { + PlaneFindingMode.DISABLED + } + + if (config.handTracking != HandTrackingMode.DISABLED) { + throw UnsupportedOperationException() + } + + arConfig.depthMode = + when (config.depthEstimation) { + DepthEstimationMode.SMOOTH_ONLY, + DepthEstimationMode.SMOOTH_AND_RAW -> DepthMode.AUTOMATIC + DepthEstimationMode.RAW_ONLY -> DepthMode.RAW_DEPTH_ONLY + else -> DepthMode.DISABLED + } + + perceptionManager.setDepthEstimationMode(config.depthEstimation) + + if (config.anchorPersistence != AnchorPersistenceMode.DISABLED) { + throw UnsupportedOperationException() + } + + arConfig.augmentedFaceMode = + when (config.faceTracking) { + FaceTrackingMode.MESHES -> AugmentedFaceMode.MESH3D + FaceTrackingMode.DISABLED -> AugmentedFaceMode.DISABLED + else -> throw UnsupportedOperationException() + } + + arConfig.geospatialMode = + if (config.geospatial == GeospatialMode.VPS_AND_GPS) { + ArGeospatialMode.ENABLED + } else { + ArGeospatialMode.DISABLED + } + + try { + _session.configure(arConfig) + } catch (e: FineLocationPermissionNotGrantedException) { + throw SecurityException(e) + } catch (e: ARCore1xGooglePlayServicesLocationLibraryNotLinkedException) { + throw LibraryNotLinkedException("com.google.android.gms:play-services-location", e) + } catch (e: UnsupportedConfigurationException) { + throw UnsupportedOperationException(e) + } + + this.config = config } override fun isSupported(configMode: ConfigMode): Boolean { @@ -73,7 +206,45 @@ internal constructor( } override fun destroy() { - lifecycleManager.stop() + perceptionManager.dispose() + _session.close() + } + + // Verify that ARCore is installed and using the current version. + // This implementation is derived from + // https://developers.google.com/ar/develop/java/session-config#verify_that_arcore_is_installed_and_up_to_date + internal fun checkARCoreSupportedAndUpToDate(context: Context) { + when (arCoreApkInstance.checkAvailability(context)) { + Availability.SUPPORTED_INSTALLED -> { + return + } + Availability.SUPPORTED_APK_TOO_OLD, + Availability.SUPPORTED_NOT_INSTALLED -> { + throw ApkNotInstalledException(ARCORE_PACKAGE_NAME) + } + Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE -> { + XrLog.error { + "Session cannot be created because ARCore is not supported on this device." + } + throw UnsupportedDeviceException() + } + Availability.UNKNOWN_CHECKING -> { + throw ApkCheckAvailabilityInProgressException(ARCORE_PACKAGE_NAME) + } + Availability.UNKNOWN_ERROR, + Availability.UNKNOWN_TIMED_OUT -> { + throw ApkCheckAvailabilityErrorException(ARCORE_PACKAGE_NAME) + } + } + } + + private fun setTextureUpdateModeToExternalOES(config: ArConfig) { + config.textureUpdateMode = TextureUpdateMode.BIND_TO_TEXTURE_EXTERNAL_OES + } + + @RequiresApi(27) + private fun setTextureUpdateModeToHardwareBuffer(config: ArConfig) { + config.textureUpdateMode = TextureUpdateMode.EXPOSE_HARDWARE_BUFFER } private fun isDepthModeSupportedInArCore1x(depthEstimationMode: DepthEstimationMode): Boolean { @@ -84,7 +255,7 @@ internal constructor( DepthEstimationMode.RAW_ONLY -> ArCoreConfig.DepthMode.RAW_DEPTH_ONLY else -> ArCoreConfig.DepthMode.DISABLED } - return lifecycleManager._session.isDepthModeSupported(arCoreDepthMode) + return _session.isDepthModeSupported(arCoreDepthMode) } private fun isGeoSpatialModeSupportedInArCore1x(geospatialMode: GeospatialMode): Boolean { @@ -93,10 +264,12 @@ internal constructor( GeospatialMode.VPS_AND_GPS -> ArCoreConfig.GeospatialMode.ENABLED else -> ArCoreConfig.GeospatialMode.DISABLED } - return lifecycleManager._session.isGeospatialModeSupported(arCoreGeospatialMode) + return _session.isGeospatialModeSupported(arCoreGeospatialMode) } internal companion object { + const private val ARCORE_PACKAGE_NAME = "com.google.ar.core" + internal val SUPPORTED_CONFIG_MODES: Set = setOf( CameraFacingDirection.WORLD, diff --git a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeFactory.kt b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeFactory.kt index 1b0ec977044b2..a27cffb392c46 100644 --- a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeFactory.kt +++ b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeFactory.kt @@ -34,7 +34,6 @@ public class ArCoreRuntimeFactory() : PerceptionRuntimeFactory { // b/396235304 -- Provide a way to configure the session. val timeSource = ArCoreTimeSource() val perceptionManager = ArCorePerceptionManager(timeSource) - val manager = ArCoreManager(context, perceptionManager, timeSource) - return ArCoreRuntime(manager, perceptionManager) + return ArCoreRuntime(context, ArCoreManager(timeSource), perceptionManager, timeSource) } } diff --git a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreManagerTest.kt b/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreManagerTest.kt deleted file mode 100644 index 565321649796b..0000000000000 --- a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreManagerTest.kt +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright 2024 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.xr.arcore.playservices - -import android.app.Activity -import android.util.Range -import androidx.kruth.assertThrows -import androidx.test.ext.junit.rules.ActivityScenarioRule -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.xr.runtime.AnchorPersistenceMode -import androidx.xr.runtime.Config -import androidx.xr.runtime.DepthEstimationMode -import androidx.xr.runtime.FaceTrackingMode -import androidx.xr.runtime.HandTrackingMode -import androidx.xr.runtime.PlaneTrackingMode -import androidx.xr.runtime.internal.ApkCheckAvailabilityErrorException -import androidx.xr.runtime.internal.ApkCheckAvailabilityInProgressException -import androidx.xr.runtime.internal.ApkNotInstalledException -import androidx.xr.runtime.internal.LibraryNotLinkedException -import androidx.xr.runtime.internal.UnsupportedDeviceException -import com.google.ar.core.ArCoreApk -import com.google.ar.core.ArCoreApk.Availability -import com.google.ar.core.Camera -import com.google.ar.core.CameraConfig -import com.google.ar.core.Config as ArConfig -import com.google.ar.core.Config.PlaneFindingMode -import com.google.ar.core.Config.TextureUpdateMode -import com.google.ar.core.Frame -import com.google.ar.core.Pose as ARCorePose -import com.google.ar.core.Session -import com.google.ar.core.exceptions.FineLocationPermissionNotGrantedException -import com.google.ar.core.exceptions.GooglePlayServicesLocationLibraryNotLinkedException as ARCore1xGooglePlayServicesLocationLibraryNotLinkedException -import com.google.ar.core.exceptions.SessionNotPausedException -import com.google.ar.core.exceptions.UnsupportedConfigurationException -import com.google.common.truth.Truth.assertThat -import kotlin.test.assertFailsWith -import kotlin.time.Duration.Companion.nanoseconds -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.any -import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.doNothing -import org.mockito.kotlin.doThrow -import org.mockito.kotlin.mock -import org.mockito.kotlin.times -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever - -@OptIn(ExperimentalCoroutinesApi::class) -@RunWith(AndroidJUnit4::class) -class ArCoreManagerTest { - - private lateinit var mockSession: Session - private lateinit var mockCamera: Camera - private lateinit var mockCameraPose: ARCorePose - - private val timeSource = ArCoreTimeSource() - - private lateinit var underTest: ArCoreManager - private lateinit var mockArCoreApk: ArCoreApk - - @get:Rule val activityRule = ActivityScenarioRule(Activity::class.java) - - private companion object { - private const val MIN_FPS: Int = 25 - private const val MAX_FPS: Int = 35 - } - - @Before - fun setUp() { - activityRule.scenario.onActivity { - val perceptionManager = ArCorePerceptionManager(timeSource) - mockArCoreApk = mock() - underTest = ArCoreManager(it, perceptionManager, timeSource, mockArCoreApk) - } - - mockSession = mock() - mockCamera = mock() - mockCameraPose = mock() - whenever(mockCamera.pose).thenReturn(mockCameraPose) - } - - @Test - fun configure_supportsDefaultConfiguration() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config() - underTest.configure(config) - - assertThat(underTest.config).isEqualTo(config) - } - - @Test - @org.robolectric.annotation.Config(maxSdk = 26) - fun configure_setsTextureUpdateMode_toValue_BIND_TO_TEXTURE_EXTERNAL_OES() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - underTest.configure(Config()) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).setTextureUpdateMode(argumentCaptor.capture()) - assert(argumentCaptor.firstValue == TextureUpdateMode.BIND_TO_TEXTURE_EXTERNAL_OES) - } - - @Test - @org.robolectric.annotation.Config(minSdk = 27) - fun configure_setsTextureUpdateMode_toValue_EXPOSE_HARDWARE_BUFFER() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - underTest.configure(Config()) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).setTextureUpdateMode(argumentCaptor.capture()) - assert(argumentCaptor.firstValue == TextureUpdateMode.EXPOSE_HARDWARE_BUFFER) - } - - @Test - fun configure_faceTracking_setsAugmentedFaceMode_toValue_Disabled() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(faceTracking = FaceTrackingMode.DISABLED) - underTest.configure(config) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).augmentedFaceMode = argumentCaptor.capture() - assert(argumentCaptor.firstValue == ArConfig.AugmentedFaceMode.DISABLED) - assertThat(underTest.config.faceTracking).isEqualTo(FaceTrackingMode.DISABLED) - } - - @Test - fun configure_faceTracking_setsAugmentedFaceMode_toValue_Mesh3D() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(faceTracking = FaceTrackingMode.MESHES) - underTest.configure(config) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).augmentedFaceMode = argumentCaptor.capture() - assert(argumentCaptor.firstValue == ArConfig.AugmentedFaceMode.MESH3D) - assertThat(underTest.config.faceTracking).isEqualTo(FaceTrackingMode.MESHES) - } - - @Test - fun configure_faceTracking_setsAugmentedFaceMode_toValue_User_throwsUnsupportedOperationException() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(faceTracking = FaceTrackingMode.BLEND_SHAPES) - - assertThrows { underTest.configure(config) } - } - - @Test - fun configure_planeTracking_setsPlaneFindingMode_toValue_Disabled() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(planeTracking = PlaneTrackingMode.DISABLED) - underTest.configure(config) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).setPlaneFindingMode(argumentCaptor.capture()) - assert(argumentCaptor.firstValue == PlaneFindingMode.DISABLED) - assertThat(underTest.config.planeTracking).isEqualTo(PlaneTrackingMode.DISABLED) - } - - @Test - fun configure_planeTracking_setsPlaneFindingMode_toValue_HorizontalAndVertical() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) - underTest.configure(config) - - val argumentCaptor = argumentCaptor() - verify(mockArConfig).setPlaneFindingMode(argumentCaptor.capture()) - assert(argumentCaptor.firstValue == PlaneFindingMode.HORIZONTAL_AND_VERTICAL) - assertThat(underTest.config.planeTracking) - .isEqualTo(PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) - } - - @Test - fun configure_handTracking_throwsUnsupportedOperationException() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(handTracking = HandTrackingMode.BOTH) - assertFailsWith { underTest.configure(config) } - } - - @Test - fun configure_depthEstimation_throwsUnsupportedOperationException() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(depthEstimation = DepthEstimationMode.SMOOTH_AND_RAW) - underTest.configure(config) - - assertThat(underTest.config.depthEstimation).isEqualTo(DepthEstimationMode.SMOOTH_AND_RAW) - } - - @Test - fun configure_anchorPersistence_throwsUnsupportedOperationException() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - - val config = Config(anchorPersistence = AnchorPersistenceMode.LOCAL) - assertFailsWith { underTest.configure(config) } - } - - @Test - fun configure_throwsSecurityException_whenFineLocationPermissionNotGranted() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - whenever(mockSession.configure(any())) - .doThrow(FineLocationPermissionNotGrantedException("Test Exception")) - - val config = Config() - assertFailsWith { underTest.configure(config) } - - verify(mockSession).configure(mockArConfig) - } - - @Test - fun configure_throwsGooglePlayServicesLocationLibraryNotLinkedException() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - whenever(mockSession.configure(any())) - .doThrow(ARCore1xGooglePlayServicesLocationLibraryNotLinkedException("Test Exception")) - - val config = Config() - assertFailsWith { underTest.configure(config) } - verify(mockSession).configure(mockArConfig) - } - - @Test - fun configure_throwsUnsupportedOperationException_whenUnsupportedConfiguration() { - val mockArConfig = mock() - underTest._session = mockSession - whenever(mockSession.config).thenReturn(mockArConfig) - whenever(mockSession.configure(any())) - .doThrow(UnsupportedConfigurationException("Test Exception")) - - val config = Config() - assertFailsWith { underTest.configure(config) } - verify(mockSession).configure(mockArConfig) - } - - @Test - fun resume_callsSessionResume() { - underTest._session = mockSession - - underTest.resume() - - verify(mockSession).resume() - } - - @Test - fun resumeCalledTwice_doesThrowSessionNotPausedException() { - doNothing().doThrow(SessionNotPausedException()).whenever(mockSession).resume() - underTest._session = mockSession - - underTest.resume() - - assertFailsWith { underTest.resume() } - verify(mockSession, times(2)).resume() - } - - @Test - fun update_updatesPerceptionManager() { - val mockFrame = mock() - val mockCameraConfig = mock() - whenever(mockFrame.camera).thenReturn(mockCamera) - whenever(mockSession.update()).thenReturn(mockFrame) - whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) - whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) - underTest._session = mockSession - underTest.perceptionManager.session = mockSession - underTest.resume() - - runTest { - underTest.update() - - verify(mockSession).update() - } - } - - @Test - fun update_returnsTimeMarkFromTimeSource() { - val mockFrame1 = mock() - val mockFrame2 = mock() - val mockCameraConfig = mock() - val firstTimestampNs = - 1000L // first timestamp becomes the zero time mark for the time source - val secondTimestampNs = 2000L - whenever(mockFrame1.timestamp).thenReturn(firstTimestampNs) - whenever(mockFrame2.timestamp).thenReturn(secondTimestampNs) - whenever(mockFrame1.camera).thenReturn(mockCamera) - whenever(mockFrame2.camera).thenReturn(mockCamera) - whenever(mockSession.update()).thenReturn(mockFrame1, mockFrame2) - whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) - whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) - underTest._session = mockSession - underTest.perceptionManager.session = mockSession - underTest.resume() - - runTest { - val timeMark1 = underTest.update() - val timeMark2 = underTest.update() - - assertThat(timeMark2.minus(timeMark1)) - .isEqualTo((secondTimestampNs - firstTimestampNs).nanoseconds) - } - } - - @Test - fun update_delaysForExpectedTimeBetweenFrames() { - val mockFrame = mock() - whenever(mockFrame.camera).thenReturn(mockCamera) - whenever(mockSession.update()).thenReturn(mockFrame) - val mockCameraConfig = mock() - whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) - whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) - underTest._session = mockSession - underTest.perceptionManager.session = mockSession - underTest.resume() - - runTest { - var updateHasReturned: Boolean = false - launch { - underTest.update() - updateHasReturned = true - } - - val avgFps = (MIN_FPS + MAX_FPS) / 2 - advanceTimeBy(1000L / avgFps / 2) - assertThat(updateHasReturned).isFalse() - advanceTimeBy(1000L / avgFps) - assertThat(updateHasReturned).isTrue() - } - } - - @Test - fun pause_doesNotThrowIllegalStateException() { - underTest._session = mockSession - - underTest.resume() - underTest.pause() - - verify(mockSession).pause() - } - - @Test - fun stop_doesNotThrowIllegalStateException() { - underTest._session = mockSession - - underTest.stop() - - verify(mockSession).close() - } - - @Test - fun stopCalledTwice_doesThrowIllegalStateException() { - underTest._session = mockSession - doNothing().doThrow(IllegalStateException()).whenever(mockSession).close() - - underTest.stop() - - assertFailsWith { underTest.stop() } - verify(mockSession, times(2)).close() - } - - @Test - fun create_throwsArCoreNotInstalledException() { - activityRule.scenario.onActivity { - whenever(mockArCoreApk.checkAvailability(it)) - .thenReturn(Availability.SUPPORTED_NOT_INSTALLED) - - assertFailsWith { underTest.create() } - verify(mockArCoreApk).checkAvailability(it) - } - } - - @Test - fun create_throwsArCoreUnsupportedDeviceException() { - activityRule.scenario.onActivity { - whenever(mockArCoreApk.checkAvailability(it)) - .thenReturn(Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE) - - assertFailsWith { underTest.create() } - verify(mockArCoreApk).checkAvailability(it) - } - } - - @Test - fun create_throwsArCoreCheckAvailabilityInProgressException() { - activityRule.scenario.onActivity { - whenever(mockArCoreApk.checkAvailability(it)).thenReturn(Availability.UNKNOWN_CHECKING) - - assertFailsWith { underTest.create() } - verify(mockArCoreApk).checkAvailability(it) - } - } - - @Test - fun create_throwsArCoreCheckAvailabilityErrorException() { - activityRule.scenario.onActivity { - whenever(mockArCoreApk.checkAvailability(it)).thenReturn(Availability.UNKNOWN_ERROR) - - assertFailsWith { underTest.create() } - verify(mockArCoreApk).checkAvailability(it) - } - } -} diff --git a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeTest.kt b/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeTest.kt index 45630cee1e37a..b540f3b2c876d 100644 --- a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeTest.kt +++ b/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreRuntimeTest.kt @@ -17,34 +17,457 @@ package androidx.xr.arcore.playservices import android.app.Activity -import androidx.kruth.assertThat +import android.util.Range +import androidx.kruth.assertThrows import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.xr.runtime.AnchorPersistenceMode import androidx.xr.runtime.Config import androidx.xr.runtime.DepthEstimationMode +import androidx.xr.runtime.FaceTrackingMode +import androidx.xr.runtime.HandTrackingMode +import androidx.xr.runtime.PlaneTrackingMode +import androidx.xr.runtime.internal.ApkCheckAvailabilityErrorException +import androidx.xr.runtime.internal.ApkCheckAvailabilityInProgressException +import androidx.xr.runtime.internal.ApkNotInstalledException +import androidx.xr.runtime.internal.LibraryNotLinkedException +import androidx.xr.runtime.internal.UnsupportedDeviceException import com.google.ar.core.ArCoreApk +import com.google.ar.core.ArCoreApk.Availability +import com.google.ar.core.Camera +import com.google.ar.core.CameraConfig +import com.google.ar.core.Config as ArConfig import com.google.ar.core.Config.DepthMode import com.google.ar.core.Config.GeospatialMode +import com.google.ar.core.Config.PlaneFindingMode +import com.google.ar.core.Config.TextureUpdateMode +import com.google.ar.core.Frame +import com.google.ar.core.Pose as ARCorePose import com.google.ar.core.Session +import com.google.ar.core.exceptions.FineLocationPermissionNotGrantedException +import com.google.ar.core.exceptions.GooglePlayServicesLocationLibraryNotLinkedException as ARCore1xGooglePlayServicesLocationLibraryNotLinkedException +import com.google.ar.core.exceptions.SessionNotPausedException +import com.google.ar.core.exceptions.UnsupportedConfigurationException +import com.google.common.truth.Truth.assertThat +import kotlin.test.assertFailsWith +import kotlin.time.Duration.Companion.nanoseconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doThrow import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +@OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) class ArCoreRuntimeTest { - private lateinit var underTest: ArCoreRuntime - private lateinit var arCoreManager: ArCoreManager - private lateinit var mockArCoreApk: ArCoreApk + private lateinit var mockSession: Session + private lateinit var mockCamera: Camera + private lateinit var mockCameraPose: ARCorePose private val timeSource = ArCoreTimeSource() + private lateinit var underTest: ArCoreRuntime + private lateinit var mockArCoreApk: ArCoreApk + @get:Rule val activityRule = ActivityScenarioRule(Activity::class.java) + private class FakeConfigMode private constructor() : Config.ConfigMode() { + companion object { + @JvmField val UNSUPPORTED_BY_ARCORE: FakeConfigMode = FakeConfigMode() + } + } + + private companion object { + private const val MIN_FPS: Int = 25 + private const val MAX_FPS: Int = 35 + } + + @Before + fun setUp() { + activityRule.scenario.onActivity { + val perceptionManager = ArCorePerceptionManager(timeSource) + mockArCoreApk = mock() + underTest = + ArCoreRuntime( + context = it, + ArCoreManager(ArCoreTimeSource()), + perceptionManager, + timeSource, + mockArCoreApk, + ) + } + + mockSession = mock() + mockCamera = mock() + mockCameraPose = mock() + whenever(mockCamera.pose).thenReturn(mockCameraPose) + } + + @Test + fun configure_supportsDefaultConfiguration() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config() + underTest.configure(config) + + assertThat(underTest.config).isEqualTo(config) + } + + @Test + @org.robolectric.annotation.Config(maxSdk = 26) + fun configure_setsTextureUpdateMode_toValue_BIND_TO_TEXTURE_EXTERNAL_OES() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + underTest.configure(Config()) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).setTextureUpdateMode(argumentCaptor.capture()) + assert(argumentCaptor.firstValue == TextureUpdateMode.BIND_TO_TEXTURE_EXTERNAL_OES) + } + + @Test + @org.robolectric.annotation.Config(minSdk = 27) + fun configure_setsTextureUpdateMode_toValue_EXPOSE_HARDWARE_BUFFER() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + underTest.configure(Config()) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).setTextureUpdateMode(argumentCaptor.capture()) + assert(argumentCaptor.firstValue == TextureUpdateMode.EXPOSE_HARDWARE_BUFFER) + } + + @Test + fun configure_faceTracking_setsAugmentedFaceMode_toValue_Disabled() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(faceTracking = FaceTrackingMode.DISABLED) + underTest.configure(config) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).augmentedFaceMode = argumentCaptor.capture() + assert(argumentCaptor.firstValue == ArConfig.AugmentedFaceMode.DISABLED) + assertThat(underTest.config.faceTracking).isEqualTo(FaceTrackingMode.DISABLED) + } + + @Test + fun configure_faceTracking_setsAugmentedFaceMode_toValue_Mesh3D() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(faceTracking = FaceTrackingMode.MESHES) + underTest.configure(config) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).augmentedFaceMode = argumentCaptor.capture() + assert(argumentCaptor.firstValue == ArConfig.AugmentedFaceMode.MESH3D) + assertThat(underTest.config.faceTracking).isEqualTo(FaceTrackingMode.MESHES) + } + + @Test + fun configure_faceTracking_setsAugmentedFaceMode_toValue_User_throwsUnsupportedOperationException() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(faceTracking = FaceTrackingMode.BLEND_SHAPES) + + assertThrows { underTest.configure(config) } + } + + @Test + fun configure_planeTracking_setsPlaneFindingMode_toValue_Disabled() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(planeTracking = PlaneTrackingMode.DISABLED) + underTest.configure(config) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).setPlaneFindingMode(argumentCaptor.capture()) + assert(argumentCaptor.firstValue == PlaneFindingMode.DISABLED) + assertThat(underTest.config.planeTracking).isEqualTo(PlaneTrackingMode.DISABLED) + } + + @Test + fun configure_planeTracking_setsPlaneFindingMode_toValue_HorizontalAndVertical() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) + underTest.configure(config) + + val argumentCaptor = argumentCaptor() + verify(mockArConfig).setPlaneFindingMode(argumentCaptor.capture()) + assert(argumentCaptor.firstValue == PlaneFindingMode.HORIZONTAL_AND_VERTICAL) + assertThat(underTest.config.planeTracking) + .isEqualTo(PlaneTrackingMode.HORIZONTAL_AND_VERTICAL) + } + + @Test + fun configure_handTracking_throwsUnsupportedOperationException() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(handTracking = HandTrackingMode.BOTH) + assertFailsWith { underTest.configure(config) } + } + + @Test + fun configure_depthEstimation_throwsUnsupportedOperationException() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(depthEstimation = DepthEstimationMode.SMOOTH_AND_RAW) + underTest.configure(config) + + assertThat(underTest.config.depthEstimation).isEqualTo(DepthEstimationMode.SMOOTH_AND_RAW) + } + + @Test + fun configure_anchorPersistence_throwsUnsupportedOperationException() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + + val config = Config(anchorPersistence = AnchorPersistenceMode.LOCAL) + assertFailsWith { underTest.configure(config) } + } + + @Test + fun configure_throwsSecurityException_whenFineLocationPermissionNotGranted() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + whenever(mockSession.configure(any())) + .doThrow(FineLocationPermissionNotGrantedException("Test Exception")) + + val config = Config() + assertFailsWith { underTest.configure(config) } + + verify(mockSession).configure(mockArConfig) + } + + @Test + fun configure_throwsGooglePlayServicesLocationLibraryNotLinkedException() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + whenever(mockSession.configure(any())) + .doThrow(ARCore1xGooglePlayServicesLocationLibraryNotLinkedException("Test Exception")) + + val config = Config() + assertFailsWith { underTest.configure(config) } + verify(mockSession).configure(mockArConfig) + } + + @Test + fun configure_throwsUnsupportedOperationException_whenUnsupportedConfiguration() { + val mockArConfig = mock() + underTest._session = mockSession + whenever(mockSession.config).thenReturn(mockArConfig) + whenever(mockSession.configure(any())) + .doThrow(UnsupportedConfigurationException("Test Exception")) + + val config = Config() + assertFailsWith { underTest.configure(config) } + verify(mockSession).configure(mockArConfig) + } + + @Test + fun resume_callsSessionResume() { + underTest._session = mockSession + + underTest.resume() + + verify(mockSession).resume() + } + + @Test + fun resumeCalledTwice_doesThrowSessionNotPausedException() { + doNothing().doThrow(SessionNotPausedException()).whenever(mockSession).resume() + underTest._session = mockSession + + underTest.resume() + + assertFailsWith { underTest.resume() } + verify(mockSession, times(2)).resume() + } + + @Test + fun update_updatesPerceptionManager() { + val mockFrame = mock() + val mockCameraConfig = mock() + whenever(mockFrame.camera).thenReturn(mockCamera) + whenever(mockSession.update()).thenReturn(mockFrame) + whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) + whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) + underTest._session = mockSession + underTest.perceptionManager.session = mockSession + underTest.resume() + + runTest { + underTest.update() + + verify(mockSession).update() + } + } + + @Test + fun update_returnsTimeMarkFromTimeSource() { + val mockFrame1 = mock() + val mockFrame2 = mock() + val mockCameraConfig = mock() + val firstTimestampNs = + 1000L // first timestamp becomes the zero time mark for the time source + val secondTimestampNs = 2000L + whenever(mockFrame1.timestamp).thenReturn(firstTimestampNs) + whenever(mockFrame2.timestamp).thenReturn(secondTimestampNs) + whenever(mockFrame1.camera).thenReturn(mockCamera) + whenever(mockFrame2.camera).thenReturn(mockCamera) + whenever(mockSession.update()).thenReturn(mockFrame1, mockFrame2) + whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) + whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) + underTest._session = mockSession + underTest.perceptionManager.session = mockSession + underTest.resume() + + runTest { + val timeMark1 = underTest.update() + val timeMark2 = underTest.update() + + assertThat(timeMark2.minus(timeMark1)) + .isEqualTo((secondTimestampNs - firstTimestampNs).nanoseconds) + } + } + + @Test + fun update_delaysForExpectedTimeBetweenFrames() { + val mockFrame = mock() + whenever(mockFrame.camera).thenReturn(mockCamera) + whenever(mockSession.update()).thenReturn(mockFrame) + val mockCameraConfig = mock() + whenever(mockSession.cameraConfig).thenReturn(mockCameraConfig) + whenever(mockCameraConfig.fpsRange).thenReturn(Range(MIN_FPS, MAX_FPS)) + underTest._session = mockSession + underTest.perceptionManager.session = mockSession + underTest.resume() + + runTest { + var updateHasReturned: Boolean = false + launch { + underTest.update() + updateHasReturned = true + } + + val avgFps = (MIN_FPS + MAX_FPS) / 2 + advanceTimeBy(1000L / avgFps / 2) + assertThat(updateHasReturned).isFalse() + advanceTimeBy(1000L / avgFps) + assertThat(updateHasReturned).isTrue() + } + } + + @Test + fun pause_doesNotThrowIllegalStateException() { + underTest._session = mockSession + + underTest.resume() + underTest.pause() + + verify(mockSession).pause() + } + + @Test + fun destroy_doesNotThrowIllegalStateException() { + underTest._session = mockSession + + underTest.destroy() + + verify(mockSession).close() + } + + @Test + fun destroyCalledTwice_doesThrowIllegalStateException() { + underTest._session = mockSession + doNothing().doThrow(IllegalStateException()).whenever(mockSession).close() + + underTest.destroy() + + assertFailsWith { underTest.destroy() } + verify(mockSession, times(2)).close() + } + + @Test + fun initialize_throwsArCoreNotInstalledException() { + activityRule.scenario.onActivity { + whenever(mockArCoreApk.checkAvailability(it)) + .thenReturn(Availability.SUPPORTED_NOT_INSTALLED) + + assertFailsWith { underTest.initialize() } + verify(mockArCoreApk).checkAvailability(it) + } + } + + @Test + fun initialize_throwsArCoreUnsupportedDeviceException() { + activityRule.scenario.onActivity { + whenever(mockArCoreApk.checkAvailability(it)) + .thenReturn(Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE) + + assertFailsWith { underTest.initialize() } + verify(mockArCoreApk).checkAvailability(it) + } + } + + @Test + fun initialize_throwsArCoreCheckAvailabilityInProgressException() { + activityRule.scenario.onActivity { + whenever(mockArCoreApk.checkAvailability(it)).thenReturn(Availability.UNKNOWN_CHECKING) + + assertFailsWith { underTest.initialize() } + verify(mockArCoreApk).checkAvailability(it) + } + } + + @Test + fun initialize_throwsArCoreCheckAvailabilityErrorException() { + activityRule.scenario.onActivity { + whenever(mockArCoreApk.checkAvailability(it)).thenReturn(Availability.UNKNOWN_ERROR) + + assertFailsWith { underTest.initialize() } + verify(mockArCoreApk).checkAvailability(it) + } + } + @Test fun isSupported_depthSmoothOnly_whenTrueIn1x_returnsTrue() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.AUTOMATIC)).thenReturn(true) assertThat(underTest.isSupported(DepthEstimationMode.SMOOTH_ONLY)).isTrue() @@ -52,6 +475,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_depthSmoothOnly_whenFalseIn1x_returnsFalse() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.AUTOMATIC)).thenReturn(false) assertThat(underTest.isSupported(DepthEstimationMode.SMOOTH_ONLY)).isFalse() @@ -59,6 +483,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_depthSmoothAndRaw_whenTrueIn1x_returnsTrue() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.AUTOMATIC)).thenReturn(true) assertThat(underTest.isSupported(DepthEstimationMode.SMOOTH_AND_RAW)).isTrue() @@ -66,6 +491,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_depthSmoothAndRaw_whenFalseIn1x_returnsFalse() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.AUTOMATIC)).thenReturn(false) assertThat(underTest.isSupported(DepthEstimationMode.SMOOTH_AND_RAW)).isFalse() @@ -73,6 +499,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_depthRawOnly_whenTrueIn1x_returnsTrue() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.RAW_DEPTH_ONLY)).thenReturn(true) assertThat(underTest.isSupported(DepthEstimationMode.RAW_ONLY)).isTrue() @@ -80,6 +507,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_depthRawOnly_whenFalseIn1x_returnsFalse() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isDepthModeSupported(DepthMode.RAW_DEPTH_ONLY)).thenReturn(false) assertThat(underTest.isSupported(DepthEstimationMode.RAW_ONLY)).isFalse() @@ -87,6 +515,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_geospatialVpsAndGps_whenFalseIn1x_returnsFalse() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isGeospatialModeSupported(GeospatialMode.ENABLED)).thenReturn(false) assertThat(underTest.isSupported(androidx.xr.runtime.GeospatialMode.VPS_AND_GPS)).isFalse() @@ -94,6 +523,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_geospatialVpsAndGps_whenTrueIn1x_returnsTrue() = initRuntimeAndRunTest { + underTest._session = mockSession whenever(mockSession.isGeospatialModeSupported(GeospatialMode.ENABLED)).thenReturn(true) assertThat(underTest.isSupported(androidx.xr.runtime.GeospatialMode.VPS_AND_GPS)).isTrue() @@ -101,6 +531,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_inSupportedList_returnsTrue() = initRuntimeAndRunTest { + underTest._session = mockSession for (mode in ArCoreRuntime.SUPPORTED_CONFIG_MODES) { assertThat(underTest.isSupported(mode)).isTrue() } @@ -108,6 +539,7 @@ class ArCoreRuntimeTest { @Test fun isSupported_notInSupportedList_returnsFalse() = initRuntimeAndRunTest { + underTest._session = mockSession assertThat(underTest.isSupported(FakeConfigMode.UNSUPPORTED_BY_ARCORE)).isFalse() } @@ -116,17 +548,16 @@ class ArCoreRuntimeTest { val perceptionManager = ArCorePerceptionManager(timeSource) mockArCoreApk = mock() mockSession = mock() - arCoreManager = ArCoreManager(it, perceptionManager, timeSource, mockArCoreApk) - arCoreManager._session = mockSession - underTest = ArCoreRuntime(arCoreManager, perceptionManager) + underTest = + ArCoreRuntime( + it, + ArCoreManager(timeSource), + perceptionManager, + timeSource, + mockArCoreApk, + ) testBody() } } - - private class FakeConfigMode private constructor() : Config.ConfigMode() { - companion object { - @JvmField val UNSUPPORTED_BY_ARCORE: FakeConfigMode = FakeConfigMode() - } - } } diff --git a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/CameraStateExtenderTest.kt b/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/CameraStateExtenderTest.kt index 9bcb682882418..119b18779ef20 100644 --- a/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/CameraStateExtenderTest.kt +++ b/xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/CameraStateExtenderTest.kt @@ -59,12 +59,17 @@ class CameraStateExtenderTest { @Before fun setUp() { + val activity = Activity() timeSource = TestTimeSource() var arCoreTimeSource = ArCoreTimeSource() - var lifecycleManager = - ArCoreManager(Activity(), ArCorePerceptionManager(arCoreTimeSource), arCoreTimeSource) perceptionManager = ArCorePerceptionManager(ArCoreTimeSource()) - runtime = ArCoreRuntime(lifecycleManager, perceptionManager) + runtime = + ArCoreRuntime( + activity, + ArCoreManager(ArCoreTimeSource()), + perceptionManager, + arCoreTimeSource, + ) frame = mock() camera = mock() whenever(frame.camera).thenReturn(camera) diff --git a/xr/arcore/arcore-testing/api/current.txt b/xr/arcore/arcore-testing/api/current.txt index e6f50d0d0fd11..278cbb9928c85 100644 --- a/xr/arcore/arcore-testing/api/current.txt +++ b/xr/arcore/arcore-testing/api/current.txt @@ -1 +1,198 @@ // Signature format: 4.0 +package androidx.xr.arcore.testing { + + public final class ArCoreTestRule extends org.junit.rules.ExternalResource { + ctor public ArCoreTestRule(); + method public void addTrackables(androidx.xr.arcore.testing.TestTrackable... trackables); + method protected void before(); + method public void clearPersistedAnchors(); + method @InaccessibleFromKotlin public int getAnchorResourceLimit(); + method @InaccessibleFromKotlin public java.util.List getAugmentableObjects(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestArDevice getDevice(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestFace getFace(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestGeospatial getGeospatial(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getLeftDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestEye getLeftEye(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestHand getLeftHand(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getLeftRenderViewpoint(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getMonoDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getMonoRenderViewpoint(); + method @InaccessibleFromKotlin public java.util.Map getPersistedAnchorPoses(); + method @InaccessibleFromKotlin public java.util.List getPlanes(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getRightDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestEye getRightEye(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestHand getRightHand(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getRightRenderViewpoint(); + method public java.util.UUID persistAnchor(androidx.xr.runtime.math.Pose pose); + method @InaccessibleFromKotlin public void setAnchorResourceLimit(int); + property public int anchorResourceLimit; + property public java.util.List augmentableObjects; + property public androidx.xr.arcore.testing.TestArDevice device; + property public androidx.xr.arcore.testing.TestFace face; + property public androidx.xr.arcore.testing.TestGeospatial geospatial; + property public androidx.xr.arcore.testing.TestDepth leftDepth; + property public androidx.xr.arcore.testing.TestEye leftEye; + property public androidx.xr.arcore.testing.TestHand leftHand; + property public androidx.xr.arcore.testing.TestRenderViewpoint leftRenderViewpoint; + property public androidx.xr.arcore.testing.TestDepth monoDepth; + property public androidx.xr.arcore.testing.TestRenderViewpoint monoRenderViewpoint; + property public java.util.Map persistedAnchorPoses; + property public java.util.List planes; + property public androidx.xr.arcore.testing.TestDepth rightDepth; + property public androidx.xr.arcore.testing.TestEye rightEye; + property public androidx.xr.arcore.testing.TestHand rightHand; + property public androidx.xr.arcore.testing.TestRenderViewpoint rightRenderViewpoint; + } + + public final class TestArDevice { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public boolean isCameraTracking(); + method @InaccessibleFromKotlin public void setCameraTracking(boolean); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public boolean isCameraTracking; + property public androidx.xr.runtime.math.Pose pose; + } + + public final class TestAugmentedObject extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestAugmentedObject(androidx.xr.runtime.AugmentedObjectCategory category); + method @InaccessibleFromKotlin public androidx.xr.runtime.AugmentedObjectCategory getCategory(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getCenterPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FloatSize3d getExtents(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setCategory(androidx.xr.runtime.AugmentedObjectCategory); + method @InaccessibleFromKotlin public void setCenterPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExtents(androidx.xr.runtime.math.FloatSize3d); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public androidx.xr.runtime.AugmentedObjectCategory category; + property public androidx.xr.runtime.math.Pose centerPose; + property public androidx.xr.runtime.math.FloatSize3d extents; + property public boolean isVisible; + } + + public final class TestDepth { + method @InaccessibleFromKotlin public int getHeight(); + method @InaccessibleFromKotlin public java.nio.ByteBuffer? getRawConfidenceMap(); + method @InaccessibleFromKotlin public java.nio.FloatBuffer? getRawDepthMap(); + method @InaccessibleFromKotlin public java.nio.ByteBuffer? getSmoothConfidenceMap(); + method @InaccessibleFromKotlin public java.nio.FloatBuffer? getSmoothDepthMap(); + method @InaccessibleFromKotlin public int getWidth(); + method @InaccessibleFromKotlin public void setHeight(int); + method @InaccessibleFromKotlin public void setRawConfidenceMap(java.nio.ByteBuffer?); + method @InaccessibleFromKotlin public void setRawDepthMap(java.nio.FloatBuffer?); + method @InaccessibleFromKotlin public void setSmoothConfidenceMap(java.nio.ByteBuffer?); + method @InaccessibleFromKotlin public void setSmoothDepthMap(java.nio.FloatBuffer?); + method @InaccessibleFromKotlin public void setWidth(int); + property public int height; + property public java.nio.ByteBuffer? rawConfidenceMap; + property public java.nio.FloatBuffer? rawDepthMap; + property public java.nio.ByteBuffer? smoothConfidenceMap; + property public java.nio.FloatBuffer? smoothDepthMap; + property public int width; + } + + public final class TestEye { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public boolean isOpen(); + method @InaccessibleFromKotlin public void setOpen(boolean); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public boolean isOpen; + property public androidx.xr.runtime.math.Pose pose; + } + + public final class TestFace extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestFace(); + method @InaccessibleFromKotlin public java.util.List getBlendShapeValues(); + method @InaccessibleFromKotlin public java.util.List getConfidenceValues(); + method @InaccessibleFromKotlin public boolean isValid(); + method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public boolean isVisible(); + method @InaccessibleFromKotlin public void setBlendShapeValues(java.util.List); + method @InaccessibleFromKotlin public void setConfidenceValues(java.util.List); + method @InaccessibleFromKotlin public void setValid(boolean); + method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void setVisible(boolean); + property public java.util.List blendShapeValues; + property public java.util.List confidenceValues; + property public boolean isValid; + } + + public final class TestGeospatial { + method @InaccessibleFromKotlin public android.util.Range getAllowedAnchorLatitudeRange(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose? getExpectedAnchorPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.GeospatialPose getExpectedGeospatialPose(); + method @InaccessibleFromKotlin public double getExpectedHorizontalAccuracy(); + method @InaccessibleFromKotlin public double getExpectedOrientationYawAccuracy(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getExpectedPose(); + method @InaccessibleFromKotlin public double getExpectedVerticalAccuracy(); + method @InaccessibleFromKotlin public androidx.xr.arcore.VpsAvailabilityResult getExpectedVpsResult(); + method @InaccessibleFromKotlin @Deprecated public androidx.xr.arcore.Geospatial.State getState(); + method @InaccessibleFromKotlin public void setAllowedAnchorLatitudeRange(android.util.Range); + method @InaccessibleFromKotlin public void setExpectedAnchorPose(androidx.xr.runtime.math.Pose?); + method @InaccessibleFromKotlin public void setExpectedGeospatialPose(androidx.xr.runtime.math.GeospatialPose); + method @InaccessibleFromKotlin public void setExpectedHorizontalAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedOrientationYawAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExpectedVerticalAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedVpsResult(androidx.xr.arcore.VpsAvailabilityResult); + method @InaccessibleFromKotlin @Deprecated public void setState(androidx.xr.arcore.Geospatial.State); + property public android.util.Range allowedAnchorLatitudeRange; + property public androidx.xr.runtime.math.Pose? expectedAnchorPose; + property public androidx.xr.runtime.math.GeospatialPose expectedGeospatialPose; + property public double expectedHorizontalAccuracy; + property public double expectedOrientationYawAccuracy; + property public androidx.xr.runtime.math.Pose expectedPose; + property public double expectedVerticalAccuracy; + property public androidx.xr.arcore.VpsAvailabilityResult expectedVpsResult; + property @Deprecated public androidx.xr.arcore.Geospatial.State state; + } + + public final class TestHand { + method @InaccessibleFromKotlin public java.util.Map getHandJointMap(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setHandJointMap(java.util.Map); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public java.util.Map handJointMap; + property public boolean isVisible; + } + + public final class TestPlane extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestPlane(androidx.xr.arcore.Plane.Type planeType, androidx.xr.arcore.Plane.Label planeLabel); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getCenterPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FloatSize2d getExtents(); + method @InaccessibleFromKotlin public androidx.xr.arcore.Plane.Label getLabel(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestPlane? getSubsumedBy(); + method @InaccessibleFromKotlin public androidx.xr.arcore.Plane.Type getType(); + method @InaccessibleFromKotlin public java.util.List getVertices(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setCenterPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExtents(androidx.xr.runtime.math.FloatSize2d); + method @InaccessibleFromKotlin public void setLabel(androidx.xr.arcore.Plane.Label); + method @InaccessibleFromKotlin public void setSubsumedBy(androidx.xr.arcore.testing.TestPlane?); + method @InaccessibleFromKotlin public void setType(androidx.xr.arcore.Plane.Type); + method @InaccessibleFromKotlin public void setVertices(java.util.List); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public androidx.xr.runtime.math.Pose centerPose; + property public androidx.xr.runtime.math.FloatSize2d extents; + property public boolean isVisible; + property public androidx.xr.arcore.Plane.Label label; + property public androidx.xr.arcore.testing.TestPlane? subsumedBy; + property public androidx.xr.arcore.Plane.Type type; + property public java.util.List vertices; + } + + public final class TestRenderViewpoint { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FieldOfView getFieldOfView(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public void setFieldOfView(androidx.xr.runtime.math.FieldOfView); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public androidx.xr.runtime.math.FieldOfView fieldOfView; + property public androidx.xr.runtime.math.Pose pose; + } + + public abstract class TestTrackable { + ctor public TestTrackable(); + method @InaccessibleFromKotlin public abstract boolean isVisible(); + method @InaccessibleFromKotlin public abstract void setVisible(boolean); + property public abstract boolean isVisible; + } + +} + diff --git a/xr/arcore/arcore-testing/api/restricted_current.txt b/xr/arcore/arcore-testing/api/restricted_current.txt index e6f50d0d0fd11..278cbb9928c85 100644 --- a/xr/arcore/arcore-testing/api/restricted_current.txt +++ b/xr/arcore/arcore-testing/api/restricted_current.txt @@ -1 +1,198 @@ // Signature format: 4.0 +package androidx.xr.arcore.testing { + + public final class ArCoreTestRule extends org.junit.rules.ExternalResource { + ctor public ArCoreTestRule(); + method public void addTrackables(androidx.xr.arcore.testing.TestTrackable... trackables); + method protected void before(); + method public void clearPersistedAnchors(); + method @InaccessibleFromKotlin public int getAnchorResourceLimit(); + method @InaccessibleFromKotlin public java.util.List getAugmentableObjects(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestArDevice getDevice(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestFace getFace(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestGeospatial getGeospatial(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getLeftDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestEye getLeftEye(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestHand getLeftHand(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getLeftRenderViewpoint(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getMonoDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getMonoRenderViewpoint(); + method @InaccessibleFromKotlin public java.util.Map getPersistedAnchorPoses(); + method @InaccessibleFromKotlin public java.util.List getPlanes(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestDepth getRightDepth(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestEye getRightEye(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestHand getRightHand(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestRenderViewpoint getRightRenderViewpoint(); + method public java.util.UUID persistAnchor(androidx.xr.runtime.math.Pose pose); + method @InaccessibleFromKotlin public void setAnchorResourceLimit(int); + property public int anchorResourceLimit; + property public java.util.List augmentableObjects; + property public androidx.xr.arcore.testing.TestArDevice device; + property public androidx.xr.arcore.testing.TestFace face; + property public androidx.xr.arcore.testing.TestGeospatial geospatial; + property public androidx.xr.arcore.testing.TestDepth leftDepth; + property public androidx.xr.arcore.testing.TestEye leftEye; + property public androidx.xr.arcore.testing.TestHand leftHand; + property public androidx.xr.arcore.testing.TestRenderViewpoint leftRenderViewpoint; + property public androidx.xr.arcore.testing.TestDepth monoDepth; + property public androidx.xr.arcore.testing.TestRenderViewpoint monoRenderViewpoint; + property public java.util.Map persistedAnchorPoses; + property public java.util.List planes; + property public androidx.xr.arcore.testing.TestDepth rightDepth; + property public androidx.xr.arcore.testing.TestEye rightEye; + property public androidx.xr.arcore.testing.TestHand rightHand; + property public androidx.xr.arcore.testing.TestRenderViewpoint rightRenderViewpoint; + } + + public final class TestArDevice { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public boolean isCameraTracking(); + method @InaccessibleFromKotlin public void setCameraTracking(boolean); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public boolean isCameraTracking; + property public androidx.xr.runtime.math.Pose pose; + } + + public final class TestAugmentedObject extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestAugmentedObject(androidx.xr.runtime.AugmentedObjectCategory category); + method @InaccessibleFromKotlin public androidx.xr.runtime.AugmentedObjectCategory getCategory(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getCenterPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FloatSize3d getExtents(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setCategory(androidx.xr.runtime.AugmentedObjectCategory); + method @InaccessibleFromKotlin public void setCenterPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExtents(androidx.xr.runtime.math.FloatSize3d); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public androidx.xr.runtime.AugmentedObjectCategory category; + property public androidx.xr.runtime.math.Pose centerPose; + property public androidx.xr.runtime.math.FloatSize3d extents; + property public boolean isVisible; + } + + public final class TestDepth { + method @InaccessibleFromKotlin public int getHeight(); + method @InaccessibleFromKotlin public java.nio.ByteBuffer? getRawConfidenceMap(); + method @InaccessibleFromKotlin public java.nio.FloatBuffer? getRawDepthMap(); + method @InaccessibleFromKotlin public java.nio.ByteBuffer? getSmoothConfidenceMap(); + method @InaccessibleFromKotlin public java.nio.FloatBuffer? getSmoothDepthMap(); + method @InaccessibleFromKotlin public int getWidth(); + method @InaccessibleFromKotlin public void setHeight(int); + method @InaccessibleFromKotlin public void setRawConfidenceMap(java.nio.ByteBuffer?); + method @InaccessibleFromKotlin public void setRawDepthMap(java.nio.FloatBuffer?); + method @InaccessibleFromKotlin public void setSmoothConfidenceMap(java.nio.ByteBuffer?); + method @InaccessibleFromKotlin public void setSmoothDepthMap(java.nio.FloatBuffer?); + method @InaccessibleFromKotlin public void setWidth(int); + property public int height; + property public java.nio.ByteBuffer? rawConfidenceMap; + property public java.nio.FloatBuffer? rawDepthMap; + property public java.nio.ByteBuffer? smoothConfidenceMap; + property public java.nio.FloatBuffer? smoothDepthMap; + property public int width; + } + + public final class TestEye { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public boolean isOpen(); + method @InaccessibleFromKotlin public void setOpen(boolean); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public boolean isOpen; + property public androidx.xr.runtime.math.Pose pose; + } + + public final class TestFace extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestFace(); + method @InaccessibleFromKotlin public java.util.List getBlendShapeValues(); + method @InaccessibleFromKotlin public java.util.List getConfidenceValues(); + method @InaccessibleFromKotlin public boolean isValid(); + method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public boolean isVisible(); + method @InaccessibleFromKotlin public void setBlendShapeValues(java.util.List); + method @InaccessibleFromKotlin public void setConfidenceValues(java.util.List); + method @InaccessibleFromKotlin public void setValid(boolean); + method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void setVisible(boolean); + property public java.util.List blendShapeValues; + property public java.util.List confidenceValues; + property public boolean isValid; + } + + public final class TestGeospatial { + method @InaccessibleFromKotlin public android.util.Range getAllowedAnchorLatitudeRange(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose? getExpectedAnchorPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.GeospatialPose getExpectedGeospatialPose(); + method @InaccessibleFromKotlin public double getExpectedHorizontalAccuracy(); + method @InaccessibleFromKotlin public double getExpectedOrientationYawAccuracy(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getExpectedPose(); + method @InaccessibleFromKotlin public double getExpectedVerticalAccuracy(); + method @InaccessibleFromKotlin public androidx.xr.arcore.VpsAvailabilityResult getExpectedVpsResult(); + method @InaccessibleFromKotlin @Deprecated public androidx.xr.arcore.Geospatial.State getState(); + method @InaccessibleFromKotlin public void setAllowedAnchorLatitudeRange(android.util.Range); + method @InaccessibleFromKotlin public void setExpectedAnchorPose(androidx.xr.runtime.math.Pose?); + method @InaccessibleFromKotlin public void setExpectedGeospatialPose(androidx.xr.runtime.math.GeospatialPose); + method @InaccessibleFromKotlin public void setExpectedHorizontalAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedOrientationYawAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExpectedVerticalAccuracy(double); + method @InaccessibleFromKotlin public void setExpectedVpsResult(androidx.xr.arcore.VpsAvailabilityResult); + method @InaccessibleFromKotlin @Deprecated public void setState(androidx.xr.arcore.Geospatial.State); + property public android.util.Range allowedAnchorLatitudeRange; + property public androidx.xr.runtime.math.Pose? expectedAnchorPose; + property public androidx.xr.runtime.math.GeospatialPose expectedGeospatialPose; + property public double expectedHorizontalAccuracy; + property public double expectedOrientationYawAccuracy; + property public androidx.xr.runtime.math.Pose expectedPose; + property public double expectedVerticalAccuracy; + property public androidx.xr.arcore.VpsAvailabilityResult expectedVpsResult; + property @Deprecated public androidx.xr.arcore.Geospatial.State state; + } + + public final class TestHand { + method @InaccessibleFromKotlin public java.util.Map getHandJointMap(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setHandJointMap(java.util.Map); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public java.util.Map handJointMap; + property public boolean isVisible; + } + + public final class TestPlane extends androidx.xr.arcore.testing.TestTrackable { + ctor public TestPlane(androidx.xr.arcore.Plane.Type planeType, androidx.xr.arcore.Plane.Label planeLabel); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getCenterPose(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FloatSize2d getExtents(); + method @InaccessibleFromKotlin public androidx.xr.arcore.Plane.Label getLabel(); + method @InaccessibleFromKotlin public androidx.xr.arcore.testing.TestPlane? getSubsumedBy(); + method @InaccessibleFromKotlin public androidx.xr.arcore.Plane.Type getType(); + method @InaccessibleFromKotlin public java.util.List getVertices(); + method @InaccessibleFromKotlin public boolean isVisible(); + method @InaccessibleFromKotlin public void setCenterPose(androidx.xr.runtime.math.Pose); + method @InaccessibleFromKotlin public void setExtents(androidx.xr.runtime.math.FloatSize2d); + method @InaccessibleFromKotlin public void setLabel(androidx.xr.arcore.Plane.Label); + method @InaccessibleFromKotlin public void setSubsumedBy(androidx.xr.arcore.testing.TestPlane?); + method @InaccessibleFromKotlin public void setType(androidx.xr.arcore.Plane.Type); + method @InaccessibleFromKotlin public void setVertices(java.util.List); + method @InaccessibleFromKotlin public void setVisible(boolean); + property public androidx.xr.runtime.math.Pose centerPose; + property public androidx.xr.runtime.math.FloatSize2d extents; + property public boolean isVisible; + property public androidx.xr.arcore.Plane.Label label; + property public androidx.xr.arcore.testing.TestPlane? subsumedBy; + property public androidx.xr.arcore.Plane.Type type; + property public java.util.List vertices; + } + + public final class TestRenderViewpoint { + method @InaccessibleFromKotlin public androidx.xr.runtime.math.FieldOfView getFieldOfView(); + method @InaccessibleFromKotlin public androidx.xr.runtime.math.Pose getPose(); + method @InaccessibleFromKotlin public void setFieldOfView(androidx.xr.runtime.math.FieldOfView); + method @InaccessibleFromKotlin public void setPose(androidx.xr.runtime.math.Pose); + property public androidx.xr.runtime.math.FieldOfView fieldOfView; + property public androidx.xr.runtime.math.Pose pose; + } + + public abstract class TestTrackable { + ctor public TestTrackable(); + method @InaccessibleFromKotlin public abstract boolean isVisible(); + method @InaccessibleFromKotlin public abstract void setVisible(boolean); + property public abstract boolean isVisible; + } + +} + diff --git a/xr/arcore/arcore-testing/build.gradle b/xr/arcore/arcore-testing/build.gradle index 89b82353924de..202534b8296f2 100644 --- a/xr/arcore/arcore-testing/build.gradle +++ b/xr/arcore/arcore-testing/build.gradle @@ -29,10 +29,12 @@ plugins { dependencies { api(project(":xr:runtime:runtime")) + api(project(":xr:arcore:arcore")) api(project(":xr:arcore:arcore-runtime")) + implementation(libs.junit) + testImplementation(libs.kotlinCoroutinesTest) - testImplementation(libs.junit) testImplementation(libs.testExtJunit) testImplementation(libs.testRunner) testImplementation(libs.truth) diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/ArCoreTestRule.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/ArCoreTestRule.kt new file mode 100644 index 0000000000000..77406e7f9a2a5 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/ArCoreTestRule.kt @@ -0,0 +1,330 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.annotation.RestrictTo +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakePerceptionRuntime +import androidx.xr.arcore.testing.internal.FakePerceptionRuntimeFactory +import androidx.xr.arcore.testing.internal.FakeRuntimeAnchor +import androidx.xr.arcore.testing.internal.FakeRuntimeDepthMap +import androidx.xr.arcore.testing.internal.FakeRuntimeEye +import androidx.xr.arcore.testing.internal.FakeRuntimeHand +import androidx.xr.arcore.testing.internal.FakeRuntimeRenderViewpoint +import androidx.xr.runtime.AnchorPersistenceMode +import androidx.xr.runtime.Config +import androidx.xr.runtime.math.Pose +import java.util.UUID +import org.junit.rules.ExternalResource + +/** + * A JUnit Rule for creating a test environment for ARCore for Jetpack XR applications. This rule + * allows you to write unit tests where you alter the state of the perception system. + */ +public class ArCoreTestRule : ExternalResource() { + + private val _persistedAnchorPoses: MutableMap = mutableMapOf() + private val _planes: MutableList = mutableListOf() + private val _objects: MutableList = mutableListOf() + private val _faceMeshes: MutableList = mutableListOf() + + internal lateinit var runtime: FakePerceptionRuntime + private set + + /** + * The maximum number of [androidx.xr.arcore.Anchor] objects that can be loaded at once in the + * runtime. Defaults to 6. + */ + public var anchorResourceLimit: Int = 6 + set(value) { + field = value + FakeRuntimeAnchor.anchorResourceLimit = value + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + /** + * A list of all [TestPlane] objects in the environment. Tracking must be configured via + * [androidx.xr.runtime.Session.configure] in order for an added plane to be ingested by the + * runtime. + */ + public val planes: List + get() = _planes.toList() + + /** + * A list of all [TestAugmentedObject] objects in the environment. Tracking must be configured + * via [androidx.xr.runtime.Session.configure] in order for an added object to be ingested by + * the runtime. + */ + public val augmentableObjects: List + get() = _objects.toList() + + /** + * A list of all [TestFace] objects in the environment, excluding the user's. Tracking must be + * configured via [androidx.xr.runtime.Session.configure] in order for an added face to be + * ingested by the runtime. + */ + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + public val faces: List + get() = _faceMeshes.toList() + + /** A Map of [UUID] to `Anchor` [Poses][Pose] stored outside the session. */ + public val persistedAnchorPoses: Map + get() = _persistedAnchorPoses.toMap() + + /** + * The object representing the user's device in the environment. + * [androidx.xr.runtime.DeviceTrackingMode.LAST_KNOWN] must be configured for it to be ingested + * by the runtime. + */ + public val device: TestArDevice = TestArDevice(this) + + /** + * The object representing the user's face in the environment. [Config.faceTracking] must be set + * to [androidx.xr.runtime.FaceTrackingMode.MESHES] or + * [androidx.xr.runtime.FaceTrackingMode.BLEND_SHAPES] for it to be integrated by the runtime. + * [TestTrackable.isVisible] must be set to true for the face's pose to update in the API. + */ + public val face: TestFace = TestFace(this) + + /** + * The object representing the user's left hand in the environment. + * [androidx.xr.runtime.HandTrackingMode.BOTH] must be configured for it to be ingested by the + * runtime. [TestHand.isVisible] must be set to true for the hand's pose to update in the API. + */ + public val leftHand: TestHand by lazy { + TestHand(this, runtime.perceptionManager.leftHand as FakeRuntimeHand) + } + + /** + * The object representing the user's right hand in the environment. + * [androidx.xr.runtime.HandTrackingMode.BOTH] must be configured for it to be ingested by the + * runtime. [TestHand.isVisible] must be set to true for the hand's pose to update in the API. + */ + public val rightHand: TestHand by lazy { + TestHand(this, runtime.perceptionManager.rightHand as FakeRuntimeHand) + } + + /** + * The object representing the user's left eye in the environment. + * [androidx.xr.runtime.EyeTrackingMode.COARSE_TRACKING] or + * [androidx.xr.runtime.EyeTrackingMode.FINE_TRACKING] must be configured for it to be ingested + * by the runtime. [TestEye.isOpen] must be set to true for the eye's pose to update in the API. + */ + public val leftEye: TestEye by lazy { + TestEye(this, runtime.perceptionManager.leftEye as FakeRuntimeEye) + } + + /** + * The object representing the user's right eye in the environment. + * [androidx.xr.runtime.EyeTrackingMode.COARSE_TRACKING] or + * [androidx.xr.runtime.EyeTrackingMode.FINE_TRACKING] must be configured for it to be ingested + * by the runtime. [TestEye.isOpen] must be set to true for the eye's pose to update in the API. + */ + public val rightEye: TestEye by lazy { + TestEye(this, runtime.perceptionManager.rightEye as FakeRuntimeEye) + } + + /** A test representation of the device's [androidx.xr.arcore.Geospatial] status. */ + public val geospatial: TestGeospatial = TestGeospatial(this) + + /** A test representation of the device's left [androidx.xr.arcore.RenderViewpoint]. */ + public val leftRenderViewpoint: TestRenderViewpoint by lazy { + TestRenderViewpoint( + this, + runtime.perceptionManager.leftRenderViewpoint as FakeRuntimeRenderViewpoint, + ) + } + + /** A test representation of the device's right [androidx.xr.arcore.RenderViewpoint]. */ + public val rightRenderViewpoint: TestRenderViewpoint by lazy { + TestRenderViewpoint( + this, + runtime.perceptionManager.rightRenderViewpoint as FakeRuntimeRenderViewpoint, + ) + } + + /** A test representation of the device's mono [androidx.xr.arcore.RenderViewpoint]. */ + public val monoRenderViewpoint: TestRenderViewpoint by lazy { + TestRenderViewpoint( + this, + runtime.perceptionManager.monoRenderViewpoint as FakeRuntimeRenderViewpoint, + ) + } + + /** A test representation of the device's left [androidx.xr.arcore.DepthMap] data. */ + public val leftDepth: TestDepth by lazy { + TestDepth(this, runtime.perceptionManager.leftDepthMap as FakeRuntimeDepthMap) + } + + /** A test representation of the device's right [androidx.xr.arcore.DepthMap] data. */ + public val rightDepth: TestDepth by lazy { + TestDepth(this, runtime.perceptionManager.rightDepthMap as FakeRuntimeDepthMap) + } + + /** A test representation of the device's mono [androidx.xr.arcore.DepthMap] data. */ + public val monoDepth: TestDepth by lazy { + TestDepth(this, runtime.perceptionManager.monoDepthMap as FakeRuntimeDepthMap) + } + + /** + * Adds the given [TestTrackable] objects and registers them with this ArCoreTestRule. + * + * Objects that are added are not removed during the lifetime of the test. Instead, their + * [TrackingState] will be updated based on their [TestTrackable.isVisible] property and the + * [androidx.xr.runtime.Session] configuration. + * + * @param trackables [TestTrackable] objects to add + */ + public fun addTrackables(vararg trackables: TestTrackable) { + trackables.forEach { + it.arCoreTestRule = this + when (it) { + is TestPlane -> { + _planes.add(it) + if (it.isConfigured()) { + runtime.perceptionManager.trackables.add(it.fakeRuntimeTrackable) + } + } + is TestAugmentedObject -> { + _objects.add(it) + if (it.isConfigured()) { + runtime.perceptionManager.trackables.add(it.fakeRuntimeTrackable) + } + } + is TestFace -> { + _faceMeshes.add(it) + if (it.isConfiguredForMeshing()) { + runtime.perceptionManager.trackables.add(it.fakeRuntimeTrackable) + } + } + } + // TODO: b/497925970 ensure trackables added before they get configured are + // retroactively added to the PerceptionManager + updateFakeRuntimeTrackable(it) + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + /** + * Supply the [Pose] of an [androidx.xr.arcore.Anchor] to be persisted outside the + * [androidx.xr.runtime.Session]. Persisted Anchors can be loaded by their [UUID]. + * + * @param pose the [Pose] at which the test will persist an Anchor + * @return the [UUID] of the newly persisted Anchor + */ + public fun persistAnchor(pose: Pose): UUID { + val uuid = UUID.randomUUID() + _persistedAnchorPoses[uuid] = pose + if (runtime.config.anchorPersistence == AnchorPersistenceMode.LOCAL) { + runtime.perceptionManager.persistedAnchorUUIDs[uuid] = pose + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + return uuid + } + + /** Clears the map of [UUID] instances to [Pose] instances. */ + public fun clearPersistedAnchors() { + _persistedAnchorPoses.clear() + runtime.perceptionManager.persistedAnchorUUIDs.clear() + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + @Suppress("DEPRECATION") + private fun updateFakeRuntimeTrackable(testTrackable: TestTrackable) { + when (testTrackable) { + is TestPlane -> { + if (!testTrackable.isConfigured()) { + return + } + testTrackable.fakeRuntimeTrackable.apply { + centerPose = testTrackable.centerPose + type = testTrackable.type.toRuntimeType() + label = testTrackable.label.toRuntimeType() + extents = testTrackable.extents + vertices = testTrackable.vertices + subsumedBy = testTrackable.subsumedBy?.fakeRuntimeTrackable + trackingState = + if (testTrackable.isVisible) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + } + is TestAugmentedObject -> { + if (!testTrackable.isConfigured()) { + return + } + testTrackable.fakeRuntimeTrackable.apply { + centerPose = testTrackable.centerPose + extents = testTrackable.extents + category = testTrackable.category + trackingState = + if (testTrackable.isVisible) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + } + is TestFace -> { + if (!testTrackable.isConfiguredForMeshing()) { + return + } + testTrackable.fakeRuntimeTrackable.apply { + centerPose = testTrackable.centerPose + mesh = testTrackable.mesh + noseTipPose = testTrackable.noseTipPose + foreheadLeftPose = testTrackable.foreheadLeftPose + foreheadRightPose = testTrackable.foreheadRightPose + trackingState = + if (testTrackable.isVisible) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + } + } + } + + internal fun registerWithRuntime(fakePerceptionRuntime: FakePerceptionRuntime) { + runtime = fakePerceptionRuntime + for ((uuid, pose) in persistedAnchorPoses) { + if (runtime.config.anchorPersistence == AnchorPersistenceMode.LOCAL) { + runtime.perceptionManager.persistedAnchorUUIDs[uuid] = pose + } + } + } + + @Suppress("DEPRECATION") + override fun before() { + FakePerceptionRuntimeFactory.arCoreTestRule = this + // TODO b/448689133: Remove this when no longer necessary + androidx.xr.arcore.testing.FakePerceptionRuntimeFactory.createNewFakeRuntime = true + FakeRuntimeAnchor.anchorsCreatedCount = 0 + } + + @Suppress("DEPRECATION") + override fun after() { + FakePerceptionRuntimeFactory.arCoreTestRule = null + // TODO b/448689133: Remove this when no longer necessary + androidx.xr.arcore.testing.FakePerceptionRuntimeFactory.createNewFakeRuntime = false + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/FakeRuntimePlane.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/FakeRuntimePlane.kt index 23509dee5ee2c..87ddf0e7fe24c 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/FakeRuntimePlane.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/FakeRuntimePlane.kt @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:Suppress("DEPRECATION") package androidx.xr.arcore.testing @@ -33,7 +34,7 @@ import androidx.xr.runtime.math.Vector2 * in the environment. * * For example, for a FakeRuntimePlane with [Label.WALL], [Type.VERTICAL] and - * [androidx.xr.runtime.TrackingState.PAUSED]: + * [androidx.xr.arcore.runtime.TrackingState.PAUSED]: * ``` * val plane = FakeRuntimePlane(type = RuntimePlane.Type.VERTICAL, * label = RuntimePlane.Label.WALL, diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestArDevice.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestArDevice.kt new file mode 100644 index 0000000000000..d194fce94c2bd --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestArDevice.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeArDevice +import androidx.xr.runtime.DeviceTrackingMode +import androidx.xr.runtime.PreviewSpatialApi +import androidx.xr.runtime.math.Pose + +/** + * An object which represents the user's device in the simulated environment of an ARCore unit test. + * + * @property pose the current pose of the device + * @property isCameraTracking whether the AR Device is currently tracking the environment + */ +public class TestArDevice internal constructor(private val arCoreTestRule: ArCoreTestRule) { + + private val fakeRuntimeArDevice: FakeRuntimeArDevice by lazy { + arCoreTestRule.runtime.perceptionManager.arDevice as FakeRuntimeArDevice + } + + private val isConfigured6Dof: Boolean + get() = + arCoreTestRule.runtime.config.deviceTracking == DeviceTrackingMode.SPATIAL_LAST_KNOWN + + @OptIn(PreviewSpatialApi::class) + private val isConfigured3Dof: Boolean + get() = + arCoreTestRule.runtime.config.deviceTracking == DeviceTrackingMode.INERTIAL_LAST_KNOWN + + public var pose: Pose = Pose() + set(value) { + field = value + fakeRuntimeArDevice.devicePose = + if (isConfigured6Dof) { + value + } else if (isConfigured3Dof) { + Pose(fakeRuntimeArDevice.devicePose.translation, value.rotation) + } else { + fakeRuntimeArDevice.devicePose + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var isCameraTracking: Boolean = true + set(value) { + field = value + arCoreTestRule.runtime.perceptionManager.isCameraTracking = value + FakeLifecycleManager.allowOneMoreCallToUpdate() + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestAugmentedObject.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestAugmentedObject.kt new file mode 100644 index 0000000000000..6d52845736610 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestAugmentedObject.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeAugmentedObject +import androidx.xr.runtime.AugmentedObjectCategory +import androidx.xr.runtime.math.FloatSize3d +import androidx.xr.runtime.math.Pose + +/** + * A representation of a real-world object of an [AugmentedObjectCategory] in the test environment. + * + * @property category the [AugmentedObjectCategory] that describes the object + * @property centerPose [Pose] at the center of the augmented object + * @property extents the [FloatSize3d] extents used to determine the size of the object + */ +public class TestAugmentedObject(category: AugmentedObjectCategory) : TestTrackable() { + + internal val fakeRuntimeTrackable = FakeRuntimeAugmentedObject(category = category) + + override var isVisible: Boolean = true + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var category: AugmentedObjectCategory = category + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.category = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var centerPose: Pose = Pose() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.centerPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var extents: FloatSize3d = FloatSize3d() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.extents = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + internal fun isConfigured(): Boolean = + if (isAddedToTestRule) + arCoreTestRule.runtime.config.augmentedObjectCategories.contains(category) + else false +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestDepth.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestDepth.kt new file mode 100644 index 0000000000000..a749074776e5f --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestDepth.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeDepthMap +import androidx.xr.runtime.DepthEstimationMode +import java.nio.ByteBuffer +import java.nio.FloatBuffer + +/** + * Represents a camera view perspective on the device. + * + * @property width the width of the [androidx.xr.arcore.DepthMap] + * @property height the height of the [androidx.xr.arcore.DepthMap] + * @property rawDepthMap the [FloatBuffer] containing raw depth data + * @property rawConfidenceMap the [ByteBuffer] containing raw depth confidence + * @property smoothDepthMap the [FloatBuffer] containing smooth depth data + * @property smoothConfidenceMap the [ByteBuffer] containing smooth depth confidence + */ +public class TestDepth +internal constructor( + private val arCoreTestRule: ArCoreTestRule, + private val fakeRuntimeDepthMap: FakeRuntimeDepthMap, +) { + public var width: Int = 0 + set(value) { + field = value + if (arCoreTestRule.runtime.config.depthEstimation != DepthEstimationMode.DISABLED) { + fakeRuntimeDepthMap.width = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var height: Int = 0 + set(value) { + field = value + if (arCoreTestRule.runtime.config?.depthEstimation != DepthEstimationMode.DISABLED) { + fakeRuntimeDepthMap.height = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var rawDepthMap: FloatBuffer? = null + set(value) { + field = value + if (isRawDepthConfigured()) { + fakeRuntimeDepthMap.rawDepthMap = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var rawConfidenceMap: ByteBuffer? = null + set(value) { + field = value + if (isRawDepthConfigured()) { + fakeRuntimeDepthMap.rawConfidenceMap = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var smoothDepthMap: FloatBuffer? = null + set(value) { + field = value + if (isSmoothDepthConfigured()) { + fakeRuntimeDepthMap.smoothDepthMap = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var smoothConfidenceMap: ByteBuffer? = null + set(value) { + field = value + if (isSmoothDepthConfigured()) { + fakeRuntimeDepthMap.smoothConfidenceMap = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + private fun isRawDepthConfigured(): Boolean = + arCoreTestRule.runtime.config.depthEstimation == DepthEstimationMode.RAW_ONLY || + arCoreTestRule.runtime.config.depthEstimation == DepthEstimationMode.SMOOTH_AND_RAW + + private fun isSmoothDepthConfigured(): Boolean = + arCoreTestRule.runtime.config.depthEstimation == DepthEstimationMode.SMOOTH_ONLY || + arCoreTestRule.runtime.config.depthEstimation == DepthEstimationMode.SMOOTH_AND_RAW +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestEye.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestEye.kt new file mode 100644 index 0000000000000..3c6953b8bfa72 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestEye.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeEye +import androidx.xr.runtime.EyeTrackingMode +import androidx.xr.runtime.math.Pose + +/** + * Represents one of the user's eyes in a testing environment. + * + * @property isOpen whether the eye is open + * @property pose the [Pose] of the eye + */ +public class TestEye +internal constructor( + private val arCoreTestRule: ArCoreTestRule, + private val fakeRuntimeEye: FakeRuntimeEye, +) { + private val isConfigured: Boolean + get() = arCoreTestRule.runtime.config.eyeTracking != EyeTrackingMode.DISABLED + + /** Flag indicating the eye is open and thus visible to the runtime. */ + public var isOpen: Boolean = true + set(value) { + field = value + if (isConfigured) { + fakeRuntimeEye.isOpen = value + fakeRuntimeEye.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + /** Pose of the eye within the testing environment. */ + public var pose: Pose = Pose() + set(value) { + field = value + if (isConfigured && isOpen) { + if (isOpen) { + fakeRuntimeEye.pose = value + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestFace.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestFace.kt new file mode 100644 index 0000000000000..7917822a0f8d0 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestFace.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.annotation.RestrictTo +import androidx.xr.arcore.runtime.Mesh +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeFace +import androidx.xr.runtime.FaceTrackingMode +import androidx.xr.runtime.math.Pose + +/** + * Represents a human face as observed by the runtime within a test environment. If [isValid] is + * `false`, the [blendShapeValues] will be ignored and tracking will be [TrackingState.PAUSED]. + * + * @property isValid whether the [blendShapeValues] are valid + * @property blendShapeValues a list of normalized blend shape values of facial features + * @property confidenceValues a list of normalized values describing the confidence of blend shape + * values in a specific region of the face + */ +public class TestFace public constructor() : TestTrackable() { + + internal constructor(testRule: ArCoreTestRule) : this() { + isUserFace = true + arCoreTestRule = testRule + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + override var isVisible: Boolean = true + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + private var isUserFace: Boolean = false + + public var isValid: Boolean = true + set(value) { + field = value + if (isConfiguredForBlendShapes()) { + fakeRuntimeTrackable.isValid = value + fakeRuntimeTrackable.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + internal val fakeRuntimeTrackable: FakeRuntimeFace by lazy { + if (isUserFace) { + arCoreTestRule.runtime.perceptionManager.userFace as FakeRuntimeFace + } else { + FakeRuntimeFace( + trackingState = + if (isVisible || isValid) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + ) + } + } + + public var blendShapeValues: List = listOf() + set(value) { + field = value + if (isConfiguredForBlendShapes() && value.isNotEmpty() && value.all { it in 0f..1f }) { + fakeRuntimeTrackable.blendShapeValues = value.toFloatArray() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var confidenceValues: List = listOf() + set(value) { + field = value + if (isConfiguredForBlendShapes() && value.isNotEmpty() && value.all { it in 0f..1f }) { + fakeRuntimeTrackable.confidenceValues = value.toFloatArray() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + public var centerPose: Pose = Pose() + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.centerPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + public var mesh: Mesh = Mesh(null, null, null, null) + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.mesh = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + public var noseTipPose: Pose = Pose() + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.noseTipPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + public var foreheadLeftPose: Pose = Pose() + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.foreheadLeftPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/452680433: Unrestrict when the ArCore Face meshing APIs are unrestricted + @get:RestrictTo(RestrictTo.Scope.LIBRARY) + @set:RestrictTo(RestrictTo.Scope.LIBRARY) + public var foreheadRightPose: Pose = Pose() + set(value) { + field = value + if (isConfiguredForMeshing()) { + fakeRuntimeTrackable.foreheadRightPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + internal fun isConfiguredForMeshing() = + if (isAddedToTestRule) arCoreTestRule.runtime.config.faceTracking == FaceTrackingMode.MESHES + else false + + internal fun isConfiguredForBlendShapes() = + if (isAddedToTestRule) + arCoreTestRule.runtime.config.faceTracking == FaceTrackingMode.BLEND_SHAPES + else false +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestGeospatial.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestGeospatial.kt new file mode 100644 index 0000000000000..ef77d44afeb3a --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestGeospatial.kt @@ -0,0 +1,172 @@ +/* + * Copyright 2026 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. + */ +@file:Suppress("DEPRECATION", "TYPEALIAS_EXPANSION_DEPRECATION") + +package androidx.xr.arcore.testing + +import android.util.Range +import androidx.xr.arcore.Geospatial +import androidx.xr.arcore.GeospatialState +import androidx.xr.arcore.VpsAvailabilityAvailable +import androidx.xr.arcore.VpsAvailabilityErrorInternal +import androidx.xr.arcore.VpsAvailabilityNetworkError +import androidx.xr.arcore.VpsAvailabilityNotAuthorized +import androidx.xr.arcore.VpsAvailabilityResourceExhausted +import androidx.xr.arcore.VpsAvailabilityResult +import androidx.xr.arcore.VpsAvailabilityUnavailable +import androidx.xr.arcore.runtime.Geospatial.State as RuntimeGeospatialState +import androidx.xr.arcore.runtime.VpsAvailabilityResult as RuntimeVpsAvailabilityResult +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeGeospatial +import androidx.xr.runtime.GeospatialMode +import androidx.xr.runtime.math.GeospatialPose +import androidx.xr.runtime.math.Pose +import androidx.xr.runtime.math.Quaternion + +/** + * An object which describes the overall condition of [Geospatial] operations in the test + * environment. + * + * @property expectedPose the [Pose] that would be created by + * [Geospatial.createPoseFromGeospatialPose] + * @property expectedGeospatialPose the [GeospatialPose] that would be created by + * [Geospatial.createGeospatialPoseFromPose] + * @property expectedHorizontalAccuracy the horizontal accuracy of the value returned by + * [Geospatial.createGeospatialPoseFromPose] + * @property expectedVerticalAccuracy the vertical accuracy of the value returned by + * [Geospatial.createGeospatialPoseFromPose] + * @property expectedOrientationYawAccuracy the yaw accuracy of the value returned by + * [Geospatial.createGeospatialPoseFromPose] + * @property expectedAnchorPose the [Pose] of the [androidx.xr.arcore.Anchor] that will be returned + * by [Geospatial.createAnchor] or [Geospatial.createAnchorOnSurface] + * @property state the [GeospatialState] device's Geospatial communication + * @property expectedVpsResult [VpsAvailabilityResult] that will be returned when checking for VPS + * availability if not null + * @property allowedAnchorLatitudeRange the acceptable range of latitude values that [Geospatial] + * can use when creating Anchors, with a default of `-90..90` (inclusive) + */ +public class TestGeospatial internal constructor(private val arCoreTestRule: ArCoreTestRule) { + private val fakeRuntimeGeospatial: FakeRuntimeGeospatial by lazy { + arCoreTestRule.runtime.perceptionManager.geospatial as FakeRuntimeGeospatial + } + + public var expectedPose: Pose = Pose() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedGeospatialPose: GeospatialPose = + GeospatialPose(0.0, 0.0, 0.0, Quaternion.Identity) + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedGeospatialPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedHorizontalAccuracy: Double = 0.0 + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedHorizontalAccuracy = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedVerticalAccuracy: Double = 0.0 + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedVerticalAccuracy = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedOrientationYawAccuracy: Double = 0.0 + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedOrientationYawAccuracy = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedAnchorPose: Pose? = Pose() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedAnchorPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + @Deprecated("Convert to androidx.xr.arcore.GeospatialState") + public var state: Geospatial.State = GeospatialState.NOT_RUNNING + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.state = value.toRuntimeType() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var expectedVpsResult: VpsAvailabilityResult = VpsAvailabilityAvailable() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.expectedVpsAvailabilityResult = value.toRuntimeType() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var allowedAnchorLatitudeRange: Range = Range(-90.0, 90.0) + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeGeospatial.allowedAnchorLatitudeRange = value.lower..value.upper + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + private fun isConfigured() = + arCoreTestRule.runtime.config.geospatial == GeospatialMode.VPS_AND_GPS +} + +internal fun GeospatialState.toRuntimeType(): RuntimeGeospatialState = + when (this) { + GeospatialState.PAUSED -> RuntimeGeospatialState.PAUSED + GeospatialState.RUNNING -> RuntimeGeospatialState.RUNNING + GeospatialState.ERROR_INTERNAL -> RuntimeGeospatialState.ERROR_INTERNAL + GeospatialState.ERROR_NOT_AUTHORIZED -> RuntimeGeospatialState.ERROR_NOT_AUTHORIZED + GeospatialState.ERROR_RESOURCE_EXHAUSTED -> RuntimeGeospatialState.ERROR_RESOURCE_EXHAUSTED + else -> RuntimeGeospatialState.NOT_RUNNING + } + +internal fun VpsAvailabilityResult.toRuntimeType(): RuntimeVpsAvailabilityResult = + when (this) { + is VpsAvailabilityAvailable -> androidx.xr.arcore.runtime.VpsAvailabilityAvailable() + is VpsAvailabilityResourceExhausted -> + androidx.xr.arcore.runtime.VpsAvailabilityResourceExhausted() + is VpsAvailabilityErrorInternal -> androidx.xr.arcore.runtime.VpsAvailabilityErrorInternal() + is VpsAvailabilityNetworkError -> androidx.xr.arcore.runtime.VpsAvailabilityNetworkError() + is VpsAvailabilityNotAuthorized -> androidx.xr.arcore.runtime.VpsAvailabilityNotAuthorized() + is VpsAvailabilityUnavailable -> androidx.xr.arcore.runtime.VpsAvailabilityUnavailable() + } diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestHand.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestHand.kt new file mode 100644 index 0000000000000..a2c3e27a281a0 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestHand.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.HandJointType +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeHand +import androidx.xr.arcore.testing.internal.FakeRuntimeHand.Companion.bufferSize +import androidx.xr.runtime.HandTrackingMode +import androidx.xr.runtime.math.Pose +import java.nio.ByteBuffer +import java.nio.ByteOrder +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.iterator + +/** + * Represents one of the user's hands. + * + * @property isVisible whether the hand is currently in view of the runtime + * @property handJointMap a [Map] of [HandJointType] to that joint's [Pose] + */ +public class TestHand +internal constructor( + private val arCoreTestRule: ArCoreTestRule, + private val fakeRuntimeHand: FakeRuntimeHand, +) { + + private val _handJointMap: MutableMap = + HandJointType.entries.associateWith { Pose() }.toMutableMap() + + public var isVisible: Boolean = false + set(value) { + field = value + if (arCoreTestRule.runtime.config.handTracking != HandTrackingMode.DISABLED) { + fakeRuntimeHand.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var handJointMap: Map + get() = _handJointMap.toMap() + set(value) { + for ((joint, pose) in value) { + _handJointMap[joint] = pose + } + if (arCoreTestRule.runtime.config.handTracking != HandTrackingMode.DISABLED) { + val buffer = ByteBuffer.allocate(bufferSize).order(ByteOrder.nativeOrder()) + + HandJointType.entries.forEach { handJointType -> + val handJointPose = handJointMap[handJointType]!! + buffer.putFloat(handJointPose.rotation.x) + buffer.putFloat(handJointPose.rotation.y) + buffer.putFloat(handJointPose.rotation.z) + buffer.putFloat(handJointPose.rotation.w) + buffer.putFloat(handJointPose.translation.x) + buffer.putFloat(handJointPose.translation.y) + buffer.putFloat(handJointPose.translation.z) + } + + buffer.flip() + fakeRuntimeHand.handJointsBuffer = buffer.asFloatBuffer() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestPlane.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestPlane.kt new file mode 100644 index 0000000000000..1842be51b4191 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestPlane.kt @@ -0,0 +1,145 @@ +/* + * Copyright 2026 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. + */ +// TODO b/482675376 remove Suppress when no longer needed +@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION") + +package androidx.xr.arcore.testing + +import androidx.xr.arcore.PlaneLabel +import androidx.xr.arcore.PlaneType +import androidx.xr.arcore.runtime.Plane as RuntimePlane +import androidx.xr.arcore.runtime.TrackingState +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimePlane +import androidx.xr.runtime.PlaneTrackingMode +import androidx.xr.runtime.math.FloatSize2d +import androidx.xr.runtime.math.Pose +import androidx.xr.runtime.math.Vector2 + +/** + * Represents a flat surface in the test environment, which can be described by a [PlaneType]. + * + * @property type the [PlaneType] of the surface + * @property label the [PlaneLabel] that describes the surface + * @property centerPose the [Pose] at the center of the plane + * @property extents a pair of extents describing the size of the plane + * @property vertices the [Vector2] vertices of a convex polygon approximating the detected plane + * @property subsumedBy a possible other plane that this plane has been merged into + */ +public class TestPlane(planeType: PlaneType, planeLabel: PlaneLabel) : TestTrackable() { + + internal val fakeRuntimeTrackable = + FakeRuntimePlane(planeType.toRuntimeType(), planeLabel.toRuntimeType()) + + override var isVisible: Boolean = true + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.trackingState = + if (value) { + TrackingState.TRACKING + } else { + TrackingState.PAUSED + } + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/482675376 remove Suppress when no longer needed + @get:SuppressWarnings("ReferencesDeprecated") + @set:SuppressWarnings("ReferencesDeprecated") + public var type: PlaneType = planeType + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.type = value.toRuntimeType() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + // TODO b/482675376 remove Suppress when no longer needed + @get:SuppressWarnings("ReferencesDeprecated") + @set:SuppressWarnings("ReferencesDeprecated") + public var label: PlaneLabel = planeLabel + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.label = value.toRuntimeType() + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var centerPose: Pose = Pose() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.centerPose = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var extents: FloatSize2d = FloatSize2d() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.extents = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var vertices: List = emptyList() + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.vertices = value + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + public var subsumedBy: TestPlane? = null + set(value) { + field = value + if (isConfigured()) { + fakeRuntimeTrackable.subsumedBy = value?.fakeRuntimeTrackable + } + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + internal fun isConfigured(): Boolean = + if (isAddedToTestRule) + arCoreTestRule.runtime.config.planeTracking != PlaneTrackingMode.DISABLED + else false +} + +// TODO b/482675376 remove Suppress when no longer needed +@Suppress("DEPRECATION") +internal fun PlaneType.toRuntimeType() = + when (this) { + PlaneType.HORIZONTAL_UPWARD_FACING -> RuntimePlane.Type.HORIZONTAL_UPWARD_FACING + PlaneType.HORIZONTAL_DOWNWARD_FACING -> RuntimePlane.Type.HORIZONTAL_DOWNWARD_FACING + else -> RuntimePlane.Type.VERTICAL + } + +// TODO b/482675376 remove Suppress when no longer needed +@Suppress("DEPRECATION") +internal fun PlaneLabel.toRuntimeType() = + when (this) { + PlaneLabel.WALL -> RuntimePlane.Label.WALL + PlaneLabel.TABLE -> RuntimePlane.Label.TABLE + PlaneLabel.FLOOR -> RuntimePlane.Label.FLOOR + PlaneLabel.CEILING -> RuntimePlane.Label.CEILING + else -> RuntimePlane.Label.UNKNOWN + } diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestRenderViewpoint.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestRenderViewpoint.kt new file mode 100644 index 0000000000000..263004940576d --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestRenderViewpoint.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.xr.arcore.RenderViewpoint +import androidx.xr.arcore.testing.internal.FakeLifecycleManager +import androidx.xr.arcore.testing.internal.FakeRuntimeRenderViewpoint +import androidx.xr.runtime.math.FieldOfView +import androidx.xr.runtime.math.Pose + +/** + * Represents a [RenderViewpoint] on the device. + * + * @property pose the [Pose] + * @property fieldOfView the [FieldOfView] + */ +public class TestRenderViewpoint +internal constructor( + private val arCoreTestRule: ArCoreTestRule, + private val fakeRuntimeRenderViewpoint: FakeRuntimeRenderViewpoint, +) { + public var pose: Pose = Pose() + set(value) { + field = value + fakeRuntimeRenderViewpoint.pose = value + FakeLifecycleManager.allowOneMoreCallToUpdate() + } + + @Suppress("DEPRECATION") + public var fieldOfView: FieldOfView = FieldOfView(0f, 0f, 0f, 0f) + set(value) { + field = value + fakeRuntimeRenderViewpoint.fieldOfView = + androidx.xr.runtime.FieldOfView( + value.angleLeft, + value.angleRight, + value.angleUp, + value.angleDown, + ) + FakeLifecycleManager.allowOneMoreCallToUpdate() + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestTrackable.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestTrackable.kt new file mode 100644 index 0000000000000..5cdb85e324b32 --- /dev/null +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestTrackable.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +/** + * Represents a real-world object in the user's environment that is not part of the user and which + * can be collected by ARCore, such as a `Plane` or `AugmentedObject`. + * + * @property isVisible indicates whether the trackable object is currently in view of the runtime + */ +public abstract class TestTrackable { + public abstract var isVisible: Boolean + + internal val isAddedToTestRule: Boolean + get() = ::arCoreTestRule.isInitialized + + internal lateinit var arCoreTestRule: ArCoreTestRule +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManager.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManager.kt index f7b2d3fa49c9c..fc001c4c141f7 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManager.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManager.kt @@ -31,8 +31,14 @@ import kotlinx.coroutines.sync.Semaphore internal class FakeLifecycleManager : LifecycleManager { companion object { - @JvmField - val TestPermissions: List = listOf("android.permission.SCENE_UNDERSTANDING_COARSE") + private val semaphore = Semaphore(1) + + @JvmStatic + internal fun allowOneMoreCallToUpdate() { + if (semaphore.availablePermits == 0) { + semaphore.release() + } + } } /** Set of possible states of the runtime. */ @@ -49,11 +55,10 @@ internal class FakeLifecycleManager : LifecycleManager { val timeSource: TestTimeSource = TestTimeSource() - private val semaphore = Semaphore(1) - override fun create() { check(state == State.NOT_INITIALIZED) state = State.INITIALIZED + allowOneMoreCallToUpdate() } override var config: Config = @@ -75,6 +80,7 @@ internal class FakeLifecycleManager : LifecycleManager { ) this.config = config + allowOneMoreCallToUpdate() } override fun resume() { @@ -88,10 +94,6 @@ internal class FakeLifecycleManager : LifecycleManager { return timeSource.markNow() } - fun allowOneMoreCallToUpdate() { - semaphore.release() - } - override fun pause() { check(state == State.RESUMED) state = State.PAUSED diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionManager.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionManager.kt index ef082c1d8444d..73e39efdf4da7 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionManager.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionManager.kt @@ -18,17 +18,18 @@ package androidx.xr.arcore.testing.internal import androidx.xr.arcore.runtime.Anchor import androidx.xr.arcore.runtime.AnchorInvalidUuidException -import androidx.xr.arcore.runtime.AnchorNotTrackingException import androidx.xr.arcore.runtime.HitResult import androidx.xr.arcore.runtime.PerceptionManager import androidx.xr.arcore.runtime.Trackable import androidx.xr.arcore.runtime.TrackingState import androidx.xr.runtime.Config +import androidx.xr.runtime.DeviceTrackingMode import androidx.xr.runtime.EyeTrackingMode import androidx.xr.runtime.FaceTrackingMode import androidx.xr.runtime.GeospatialMode import androidx.xr.runtime.HandTrackingMode import androidx.xr.runtime.PlaneTrackingMode +import androidx.xr.runtime.PreviewSpatialApi import androidx.xr.runtime.math.Pose import androidx.xr.runtime.math.Ray import androidx.xr.runtime.math.Vector3 @@ -95,19 +96,14 @@ internal class FakePerceptionManager() : PerceptionManager, AnchorHolder { internal val anchors: MutableList = mutableListOf() internal var isCameraTracking: Boolean = true - private fun createAnchor(pose: Pose, anchorHolder: AnchorHolder): FakeRuntimeAnchor { - if (!isCameraTracking) { - throw AnchorNotTrackingException() - } + override fun createAnchor(pose: Pose): Anchor { // TODO: b/349862231 - Modify it once detach is implemented. - val anchor = FakeRuntimeAnchor(pose) - anchor.anchorHolder = anchorHolder + val anchor = + FakeRuntimeAnchor(pose, anchorHolder = this, isTrackingAvailable = isCameraTracking) anchors.add(anchor) return anchor } - override fun createAnchor(pose: Pose): Anchor = createAnchor(pose, this) - override fun hitTest(ray: Ray): List { val results: MutableList = mutableListOf() trackables.forEach { @@ -166,7 +162,14 @@ internal class FakePerceptionManager() : PerceptionManager, AnchorHolder { anchor.uuid?.let { persistedAnchorUUIDs.remove(it) } } + @OptIn(PreviewSpatialApi::class) internal fun updateTrackingStates(config: Config) { + fakeArDevice.trackingState = + when (config.deviceTracking) { + DeviceTrackingMode.SPATIAL_LAST_KNOWN -> TrackingState.TRACKING + DeviceTrackingMode.INERTIAL_LAST_KNOWN -> TrackingState.TRACKING_DEGRADED + else -> TrackingState.PAUSED + } if (config.planeTracking == PlaneTrackingMode.DISABLED) { trackables.filterIsInstance().forEach { it.trackingState = TrackingState.STOPPED diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionRuntimeFactory.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionRuntimeFactory.kt index 2c14a18411905..33cb353d548e7 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionRuntimeFactory.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakePerceptionRuntimeFactory.kt @@ -18,11 +18,15 @@ package androidx.xr.arcore.testing.internal import android.app.Activity import android.content.Context +import androidx.xr.arcore.testing.ArCoreTestRule import androidx.xr.runtime.interfaces.Feature import androidx.xr.runtime.internal.PerceptionRuntimeFactory import kotlin.coroutines.CoroutineContext internal class FakePerceptionRuntimeFactory() : PerceptionRuntimeFactory { + companion object { + @JvmStatic var arCoreTestRule: ArCoreTestRule? = null + } override val requirements: Set = emptySet() @@ -36,6 +40,7 @@ internal class FakePerceptionRuntimeFactory() : PerceptionRuntimeFactory { FakePerceptionManager(), context as? Activity, ) + arCoreTestRule?.registerWithRuntime(runtime) return runtime } } diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeAnchor.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeAnchor.kt index ef125c7d5c23d..5ad59ee188b72 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeAnchor.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeAnchor.kt @@ -36,6 +36,7 @@ internal class FakeRuntimeAnchor( if (anchorsCreatedCount > anchorResourceLimit) { throw AnchorResourcesExhaustedException() } + FakeLifecycleManager.allowOneMoreCallToUpdate() } override var trackingState: TrackingState = TrackingState.TRACKING diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeFace.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeFace.kt index a45e6975d7b42..a1d193ebf211e 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeFace.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeFace.kt @@ -16,7 +16,7 @@ package androidx.xr.arcore.testing.internal -import androidx.xr.arcore.runtime.Face as RuntimeFace +import androidx.xr.arcore.runtime.Face import androidx.xr.arcore.runtime.Mesh import androidx.xr.arcore.runtime.TrackingState import androidx.xr.runtime.math.Pose @@ -30,28 +30,28 @@ internal class FakeRuntimeFace( override var isValid: Boolean = true, override var blendShapeValues: FloatArray = FloatArray(0), override var confidenceValues: FloatArray = FloatArray(0), -) : RuntimeFace { +) : Face { override var centerPose: Pose = Pose() override var mesh: Mesh = Mesh( - ShortBuffer.allocate(1), - FloatBuffer.allocate(1), - FloatBuffer.allocate(1), - FloatBuffer.allocate(1), + triangleIndices = ShortBuffer.allocate(1), + vertices = FloatBuffer.allocate(1), + normals = FloatBuffer.allocate(1), + textureCoordinates = FloatBuffer.allocate(1), ) - override var noseTipPose: Pose = Pose(Vector3(1f, 1f, 0f), Quaternion.Identity) + override var noseTipPose: Pose = Pose(Vector3(0f, 0f, 1f), Quaternion.Identity) - override var foreheadLeftPose: Pose = Pose(Vector3(0f, 0f, 0f), Quaternion.Identity) + override var foreheadLeftPose: Pose = Pose(Vector3(-1f, 1f, 0f), Quaternion.Identity) - override var foreheadRightPose: Pose = Pose(Vector3(2f, 0f, 0f), Quaternion.Identity) + override var foreheadRightPose: Pose = Pose(Vector3(1f, 1f, 0f), Quaternion.Identity) init { - mesh.triangleIndices!!.put(1) - mesh.normals!!.put(1f) - mesh.textureCoordinates!!.put(1f) - mesh.vertices!!.put(1f) + mesh.triangleIndices!!.put(0) + mesh.normals!!.put(0f) + mesh.textureCoordinates!!.put(0f) + mesh.vertices!!.put(0f) } } diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatial.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatial.kt index d83d98fcdfeec..fb0d98f29aba8 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatial.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatial.kt @@ -26,7 +26,6 @@ import androidx.xr.arcore.runtime.Geospatial.GeospatialPoseResult import androidx.xr.arcore.runtime.GeospatialPoseNotTrackingException import androidx.xr.arcore.runtime.VpsAvailabilityAvailable import androidx.xr.arcore.runtime.VpsAvailabilityResult -import androidx.xr.arcore.runtime.VpsAvailabilityUnavailable import androidx.xr.runtime.math.GeospatialPose import androidx.xr.runtime.math.Pose import androidx.xr.runtime.math.Quaternion @@ -35,16 +34,15 @@ internal class FakeRuntimeGeospatial( override var state: Geospatial.State = Geospatial.State.NOT_RUNNING ) : Geospatial { - val vpsAvailabilityMap: MutableMap, Boolean> = mutableMapOf() var expectedPose: Pose = Pose() var expectedGeospatialPose: GeospatialPose = GeospatialPose(0.0, 0.0, 0.0, Quaternion.Identity) var expectedHorizontalAccuracy: Double = 0.0 var expectedVerticalAccuracy: Double = 0.0 var expectedOrientationYawAccuracy: Double = 0.0 var expectedAnchorPose: Pose? = Pose() - var expectedVpsAvailabilityResult: VpsAvailabilityResult? = null + var expectedVpsAvailabilityResult: VpsAvailabilityResult = VpsAvailabilityAvailable() - internal var allowedAnchorLatitudeRange: ClosedFloatingPointRange = -90.0..90.0 + internal var allowedAnchorLatitudeRange = -90.0..90.0 override fun createPoseFromGeospatialPose(geospatialPose: GeospatialPose): Pose { if (state == Geospatial.State.RUNNING) { @@ -115,15 +113,6 @@ internal class FakeRuntimeGeospatial( longitude: Double, ): VpsAvailabilityResult { check(state == Geospatial.State.RUNNING) - if (expectedVpsAvailabilityResult != null) { - return expectedVpsAvailabilityResult!! - } - val location = Pair(latitude, longitude) - if (vpsAvailabilityMap.contains(location)) { - if (vpsAvailabilityMap[location]!!) { - return VpsAvailabilityAvailable() - } - } - return VpsAvailabilityUnavailable() + return expectedVpsAvailabilityResult } } diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeHand.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeHand.kt index de2a58d59a2aa..e94fd3342fcf6 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeHand.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeHand.kt @@ -17,11 +17,17 @@ package androidx.xr.arcore.testing.internal import androidx.xr.arcore.runtime.Hand as RuntimeHand +import androidx.xr.arcore.runtime.HandJointType import androidx.xr.arcore.runtime.TrackingState import java.nio.ByteBuffer import java.nio.FloatBuffer internal class FakeRuntimeHand( override var trackingState: TrackingState = TrackingState.PAUSED, - override var handJointsBuffer: FloatBuffer = ByteBuffer.allocate(0).asFloatBuffer(), -) : RuntimeHand + override var handJointsBuffer: FloatBuffer = ByteBuffer.allocate(bufferSize).asFloatBuffer(), +) : RuntimeHand { + + companion object { + internal val bufferSize: Int = HandJointType.entries.size * 7 * Float.SIZE_BYTES + } +} diff --git a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlane.kt b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlane.kt index 1593baed01bbc..7dad76ba996d7 100644 --- a/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlane.kt +++ b/xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlane.kt @@ -16,8 +16,9 @@ package androidx.xr.arcore.testing.internal -import androidx.xr.arcore.runtime.Anchor as RuntimeAnchor -import androidx.xr.arcore.runtime.Plane as RuntimePlane +import androidx.xr.arcore.runtime.Anchor +import androidx.xr.arcore.runtime.AnchorNotTrackingException +import androidx.xr.arcore.runtime.Plane import androidx.xr.arcore.runtime.Plane.Label import androidx.xr.arcore.runtime.Plane.Type import androidx.xr.arcore.runtime.TrackingState @@ -29,24 +30,33 @@ internal class FakeRuntimePlane( override var type: Type = Type.HORIZONTAL_UPWARD_FACING, override var label: Label = Label.FLOOR, override var trackingState: TrackingState = TrackingState.TRACKING, - override var centerPose: Pose = Pose(), + centerPose: Pose = Pose(), override var extents: FloatSize2d = FloatSize2d(), override var vertices: List = emptyList(), - override var subsumedBy: RuntimePlane? = null, -) : RuntimePlane, AnchorHolder { + override var subsumedBy: Plane? = null, +) : Plane, AnchorHolder { - val anchors: MutableCollection = mutableListOf() + val anchors: MutableCollection = mutableListOf() - override fun createAnchor(pose: Pose): RuntimeAnchor { - val anchor = FakeRuntimeAnchor(centerPose.compose(pose)) - anchor.anchorHolder = this + override var centerPose: Pose = centerPose + // when this Trackable moves, its Anchors move with it. + set(value) { + field = value + anchors.forEach { it.pose = value.compose(it.pose) } + } + + override fun createAnchor(pose: Pose): Anchor { + if (trackingState != TrackingState.TRACKING) { + throw AnchorNotTrackingException() + } + val anchor = FakeRuntimeAnchor(centerPose.compose(pose), anchorHolder = this) anchors.add(anchor) return anchor } - override fun detachAnchor(anchor: RuntimeAnchor) { + override fun detachAnchor(anchor: Anchor) { anchors.remove(anchor) } - override fun onAnchorPersisted(anchor: RuntimeAnchor) {} + override fun onAnchorPersisted(anchor: Anchor) {} } diff --git a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/ArCoreTestRuleTest.kt b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/ArCoreTestRuleTest.kt new file mode 100644 index 0000000000000..b96439471ffdf --- /dev/null +++ b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/ArCoreTestRuleTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2026 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.xr.arcore.testing + +import androidx.activity.ComponentActivity +import androidx.kruth.assertThat +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.xr.runtime.Session +import androidx.xr.runtime.math.Pose +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Robolectric +import org.robolectric.android.controller.ActivityController + +@RunWith(AndroidJUnit4::class) +class ArCoreTestRuleTest { + @Rule @JvmField val underTest = ArCoreTestRule() + + private lateinit var activityController: ActivityController + private lateinit var activity: ComponentActivity + private lateinit var testDispatcher: TestDispatcher + + @Before + fun setUp() { + testDispatcher = StandardTestDispatcher() + activityController = Robolectric.buildActivity(ComponentActivity::class.java) + activity = activityController.get() + + activityController.create().start().resume() + + Session.create(activity, testDispatcher) + } + + @Test + fun init_persistedAnchorPoses_isEmpty() { + assertThat(underTest.persistedAnchorPoses).isEmpty() + } + + @Test + fun init_planes_isEmpty() { + assertThat(underTest.planes).isEmpty() + } + + @Test + fun init_augmentableObjects_isEmpty() { + assertThat(underTest.augmentableObjects.isEmpty()) + } + + @Test + fun init_otherFaces_isEmpty() { + assertThat(underTest.faces).isEmpty() + } + + @Test + fun persistAnchorPose_addsToMapWithUUID() { + val pose = Pose() + + val uuid = underTest.persistAnchor(pose) + + assertThat(underTest.persistedAnchorPoses.size).isEqualTo(1) + assertThat(underTest.persistedAnchorPoses).containsKey(uuid) + assertThat(underTest.persistedAnchorPoses[uuid]).isEqualTo(pose) + } +} diff --git a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManagerTest.kt b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManagerTest.kt index 4437a80cda66b..bb1f955dd3eea 100644 --- a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManagerTest.kt +++ b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeLifecycleManagerTest.kt @@ -20,6 +20,7 @@ import androidx.kruth.assertThat import androidx.xr.runtime.Config import kotlin.test.assertFailsWith import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -27,7 +28,6 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(JUnit4::class) -@Suppress("DEPRECATION") class FakeLifecycleManagerTest { private lateinit var underTest: FakeLifecycleManager @@ -161,6 +161,7 @@ class FakeLifecycleManagerTest { assertThat(timeMark.elapsedNow()).isEqualTo(testDuration) } + @OptIn(ExperimentalCoroutinesApi::class) @Test fun update_calledTwiceAfterAllowOneMoreCallToUpdate_resumesExecution() = runTest { val testDuration = 5.seconds @@ -169,7 +170,7 @@ class FakeLifecycleManagerTest { val firstTimeMark = underTest.update() underTest.timeSource += testDuration - underTest.allowOneMoreCallToUpdate() + FakeLifecycleManager.allowOneMoreCallToUpdate() val secondTimeMark = underTest.update() assertThat(secondTimeMark - firstTimeMark).isEqualTo(testDuration) diff --git a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatialTest.kt b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatialTest.kt index 04b6a353d6471..eb6d46bfb6c03 100644 --- a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatialTest.kt +++ b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimeGeospatialTest.kt @@ -204,7 +204,7 @@ class FakeRuntimeGeospatialTest { } @Test - fun checkVpsAvailability_expectedResultSet_returnsExpectedResult() = + fun checkVpsAvailability_returnsExpectedResult() = runTest(testDispatcher) { val coordinates = Pair(10.0, 20.0) underTest.state = Geospatial.State.RUNNING @@ -233,29 +233,4 @@ class FakeRuntimeGeospatialTest { result = underTest.checkVpsAvailability(coordinates.first, coordinates.second) assertThat(result).isInstanceOf() } - - @Test - fun checkVpsAvailability_notAvailable_returnsVpsAvailabilityUnavailable() = - runTest(testDispatcher) { - val coordinates = Pair(10.0, 20.0) - underTest.state = Geospatial.State.RUNNING - - var result = underTest.checkVpsAvailability(coordinates.first, coordinates.second) - assertThat(result).isInstanceOf() - - underTest.vpsAvailabilityMap[coordinates] = false - result = underTest.checkVpsAvailability(coordinates.first, coordinates.second) - assertThat(result).isInstanceOf() - } - - @Test - fun checkVpsAvailability_available_returnsVpsAvailabilityAvailable() = - runTest(testDispatcher) { - val coordinates = Pair(10.0, 20.0) - underTest.state = Geospatial.State.RUNNING - underTest.vpsAvailabilityMap[coordinates] = true - - val result = underTest.checkVpsAvailability(coordinates.first, coordinates.second) - assertThat(result).isInstanceOf() - } } diff --git a/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlaneTest.kt b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlaneTest.kt new file mode 100644 index 0000000000000..d5fa2512f2a9a --- /dev/null +++ b/xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlaneTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2026 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.xr.arcore.testing.internal + +import androidx.kruth.assertThat +import androidx.xr.runtime.math.Pose +import androidx.xr.runtime.math.Quaternion +import androidx.xr.runtime.math.Vector3 +import kotlin.test.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class FakeRuntimePlaneTest { + + private lateinit var underTest: FakeRuntimePlane + + @Test + fun createAnchor_addsAndReturnsAnchor() { + underTest = FakeRuntimePlane() + + val anchor = underTest.createAnchor(Pose()) + + assertThat(underTest.anchors).containsExactly(anchor) + } + + @Test + fun createAnchor_composesAnchorPose() { + underTest = FakeRuntimePlane() + val planePose = Pose(Vector3.Forward, Quaternion(1.0f, 2.0f, 3.0f, 4.0f)) + val anchorPose = Pose(Vector3.Right, Quaternion(4.0f, 3.0f, 2.0f, 1.0f)) + underTest.centerPose = planePose + + val anchor = underTest.createAnchor(anchorPose) + + assertThat(anchor.pose).isEqualTo(planePose.compose(anchorPose)) + } + + @Test + fun detachAnchor_removesAnchor() { + underTest = FakeRuntimePlane() + val anchor = underTest.createAnchor(Pose()) + check(underTest.anchors.contains(anchor)) + + underTest.detachAnchor(anchor) + + assertThat(underTest.anchors).doesNotContain(anchor) + } +} diff --git a/xr/arcore/arcore/src/test/kotlin/androidx/xr/arcore/PlaneTest.kt b/xr/arcore/arcore/src/test/kotlin/androidx/xr/arcore/PlaneTest.kt index 639c408a2ade3..f392686c07c07 100644 --- a/xr/arcore/arcore/src/test/kotlin/androidx/xr/arcore/PlaneTest.kt +++ b/xr/arcore/arcore/src/test/kotlin/androidx/xr/arcore/PlaneTest.kt @@ -13,22 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:Suppress("DEPRECATION") package androidx.xr.arcore import androidx.activity.ComponentActivity import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.xr.arcore.runtime.Plane as RuntimePlane -import androidx.xr.arcore.testing.FakeLifecycleManager -import androidx.xr.arcore.testing.FakePerceptionManager -import androidx.xr.arcore.testing.FakePerceptionRuntimeFactory -import androidx.xr.arcore.testing.FakeRuntimeAnchor -import androidx.xr.arcore.testing.FakeRuntimePlane +import androidx.xr.arcore.testing.ArCoreTestRule +import androidx.xr.arcore.testing.TestPlane import androidx.xr.runtime.Config import androidx.xr.runtime.PlaneTrackingMode import androidx.xr.runtime.Session import androidx.xr.runtime.SessionCreateSuccess +import androidx.xr.runtime.manifest.SCENE_UNDERSTANDING_COARSE import androidx.xr.runtime.math.FloatSize2d import androidx.xr.runtime.math.Pose import androidx.xr.runtime.math.Quaternion @@ -38,15 +34,14 @@ import com.google.common.truth.Truth.assertThat import kotlin.test.assertFailsWith import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.robolectric.Robolectric @@ -54,13 +49,16 @@ import org.robolectric.Shadows.shadowOf import org.robolectric.android.controller.ActivityController @RunWith(AndroidJUnit4::class) +@OptIn(ExperimentalCoroutinesApi::class) +@Suppress("DEPRECATION") class PlaneTest { + @Rule @JvmField val arCoreTestRule = ArCoreTestRule() + private lateinit var activityController: ActivityController private lateinit var activity: ComponentActivity private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope private lateinit var session: Session - private lateinit var xrResourcesManager: XrResourcesManager @Before fun setUp() { @@ -68,223 +66,287 @@ class PlaneTest { testScope = TestScope(testDispatcher) activityController = Robolectric.buildActivity(ComponentActivity::class.java) activity = activityController.get() - xrResourcesManager = XrResourcesManager() - val shadowApplication = shadowOf(activity.application) - FakeLifecycleManager.TestPermissions.forEach { permission -> - shadowApplication.grantPermissions(permission) - } - FakePerceptionRuntimeFactory.hasCreatePermission = true - activityController.create() + shadowOf(activity.application).grantPermissions(SCENE_UNDERSTANDING_COARSE) + + activityController.create().start().resume() session = (Session.create(activity, testDispatcher) as SessionCreateSuccess).session session.configure(Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL)) - xrResourcesManager.lifecycleManager = session.perceptionRuntime.lifecycleManager - - FakeRuntimeAnchor.anchorsCreatedCount = 0 } @Test - @Suppress("DEPRECATION") - fun constructor_convertsRuntimePlaneType() { - val plane1 = - Plane( - FakeRuntimePlane(type = RuntimePlane.Type.HORIZONTAL_UPWARD_FACING), - xrResourcesManager, - ) - val plane2 = - Plane( - FakeRuntimePlane(type = RuntimePlane.Type.HORIZONTAL_DOWNWARD_FACING), - xrResourcesManager, - ) - val plane3 = Plane(FakeRuntimePlane(type = RuntimePlane.Type.VERTICAL), xrResourcesManager) - - assertThat(plane1.type).isEqualTo(PlaneType.HORIZONTAL_UPWARD_FACING) - assertThat(plane2.type).isEqualTo(PlaneType.HORIZONTAL_DOWNWARD_FACING) - assertThat(plane3.type).isEqualTo(PlaneType.VERTICAL) - } + fun constructor_convertsRuntimePlaneType() = + runTest(testDispatcher) { + val plane1 = TestPlane(PlaneType.HORIZONTAL_UPWARD_FACING, PlaneLabel.FLOOR) + val plane2 = TestPlane(PlaneType.HORIZONTAL_DOWNWARD_FACING, PlaneLabel.CEILING) + val plane3 = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(plane1, plane2, plane3) + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + check(underTest.size == 3) + advanceUntilIdle() + + assertThat(underTest.count { it.type == PlaneType.HORIZONTAL_UPWARD_FACING }) + .isEqualTo(1) + assertThat(underTest.count { it.type == PlaneType.HORIZONTAL_DOWNWARD_FACING }) + .isEqualTo(1) + assertThat(underTest.count { it.type == PlaneType.VERTICAL }).isEqualTo(1) + } @Test - @Suppress("DEPRECATION") - fun constructor_convertsRuntimePlaneLabel() { - val plane1 = Plane(FakeRuntimePlane(label = RuntimePlane.Label.UNKNOWN), xrResourcesManager) - val plane2 = Plane(FakeRuntimePlane(label = RuntimePlane.Label.WALL), xrResourcesManager) - val plane3 = Plane(FakeRuntimePlane(label = RuntimePlane.Label.FLOOR), xrResourcesManager) - val plane4 = Plane(FakeRuntimePlane(label = RuntimePlane.Label.CEILING), xrResourcesManager) - val plane5 = Plane(FakeRuntimePlane(label = RuntimePlane.Label.TABLE), xrResourcesManager) - - assertThat(plane1.state.value.label).isEqualTo(PlaneLabel.UNKNOWN) - assertThat(plane2.state.value.label).isEqualTo(PlaneLabel.WALL) - assertThat(plane3.state.value.label).isEqualTo(PlaneLabel.FLOOR) - assertThat(plane4.state.value.label).isEqualTo(PlaneLabel.CEILING) - assertThat(plane5.state.value.label).isEqualTo(PlaneLabel.TABLE) - } + fun constructor_convertsRuntimePlaneLabel() = + runTest(testDispatcher) { + val plane1 = TestPlane(PlaneType.VERTICAL, PlaneLabel.UNKNOWN) + val plane2 = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + val plane3 = TestPlane(PlaneType.VERTICAL, PlaneLabel.FLOOR) + val plane4 = TestPlane(PlaneType.VERTICAL, PlaneLabel.CEILING) + val plane5 = TestPlane(PlaneType.VERTICAL, PlaneLabel.TABLE) + arCoreTestRule.addTrackables(plane1, plane2, plane3, plane4, plane5) + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + check(underTest.size == 5) + advanceUntilIdle() + + assertThat(underTest.count { it.state.value.label == PlaneLabel.UNKNOWN }).isEqualTo(1) + assertThat(underTest.count { it.state.value.label == PlaneLabel.WALL }).isEqualTo(1) + assertThat(underTest.count { it.state.value.label == PlaneLabel.FLOOR }).isEqualTo(1) + assertThat(underTest.count { it.state.value.label == PlaneLabel.CEILING }).isEqualTo(1) + assertThat(underTest.count { it.state.value.label == PlaneLabel.TABLE }).isEqualTo(1) + } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun subscribe_collectReturnsPlane() = runTest(testDispatcher) { - val perceptionManager = getFakePerceptionManager() - val runtimePlane = FakeRuntimePlane() - perceptionManager.addTrackable(runtimePlane) - activityController.resume() + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) advanceUntilIdle() - activityController.pause() - var underTest = emptyList() - val job = - backgroundScope.launch(start = CoroutineStart.UNDISPATCHED) { - underTest = Plane.subscribe(session).first().toList() - } + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } advanceUntilIdle() assertThat(underTest.size).isEqualTo(1) - assertThat(underTest.first().runtimePlane).isEqualTo(runtimePlane) - job.cancel() + assertThat(underTest.single().type).isEqualTo(PlaneType.VERTICAL) } @Test fun subscribe_planeTrackingDisabled_throwsIllegalStateException() { - val configureResult = session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) + session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) assertFailsWith { Plane.subscribe(session) } } @Test - fun createAnchor_usesGivenPose() { - val runtimePlane = FakeRuntimePlane() - getFakePerceptionManager().addTrackable(runtimePlane) - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap.values.first() as Plane - val pose = Pose(Vector3(1.0f, 2.0f, 3.0f), Quaternion(1.0f, 2.0f, 3.0f, 4.0f)) - - val anchorResult = underTest.createAnchor(pose) - - assertThat(anchorResult).isInstanceOf(AnchorCreateSuccess::class.java) - val anchor = (anchorResult as AnchorCreateSuccess).anchor - assertThat(anchor.state.value.pose.translation.x).isWithin(0.001f).of(pose.translation.x) - assertThat(anchor.state.value.pose.translation.y).isWithin(0.001f).of(pose.translation.y) - assertThat(anchor.state.value.pose.translation.z).isWithin(0.001f).of(pose.translation.z) - assertThat(anchor.state.value.pose.rotation.x).isWithin(0.001f).of(pose.rotation.x) - assertThat(anchor.state.value.pose.rotation.y).isWithin(0.001f).of(pose.rotation.y) - assertThat(anchor.state.value.pose.rotation.z).isWithin(0.001f).of(pose.rotation.z) - assertThat(anchor.state.value.pose.rotation.w).isWithin(0.001f).of(pose.rotation.w) - } + fun createAnchor_usesGivenPose() = + runTest(testDispatcher) { + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + + advanceUntilIdle() + + var underTest: Plane? = null + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.first() } + } + check(underTest != null) + + val anchorPose = Pose(Vector3(1.0f, 2.0f, 3.0f), Quaternion(1.0f, 2.0f, 3.0f, 4.0f)) + val expectedPose = underTest.state.value.centerPose.compose(anchorPose) + val anchorResult = underTest.createAnchor(anchorPose) + check(anchorResult is AnchorCreateSuccess) + val anchorState = anchorResult.anchor.state.value + + assertThat(anchorState.pose.translation).isEqualTo(expectedPose.translation) + assertThat(anchorState.pose.rotation).isEqualTo(expectedPose.rotation) + } @Test - fun createAnchor_anchorLimitReached_returnsAnchorResourcesExhaustedResult() { - val runtimePlane = FakeRuntimePlane() - getFakePerceptionManager().addTrackable(runtimePlane) - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap.values.first() as Plane - - repeat(FakeRuntimeAnchor.anchorResourceLimit) { - val result = underTest.createAnchor(Pose()) + fun createAnchor_anchorLimitReached_returnsAnchorResourcesExhaustedResult() = + runTest(testDispatcher) { + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + + repeat(arCoreTestRule.anchorResourceLimit) { underTest.single().createAnchor(Pose()) } + + assertThat(underTest.single().createAnchor(Pose())) + .isInstanceOf(AnchorCreateResourcesExhausted::class.java) } - assertThat(underTest.createAnchor(Pose())) - .isInstanceOf(AnchorCreateResourcesExhausted::class.java) - } + @Test + fun createAnchor_planeTrackingDisabled_throwsIllegalStateException() = + runTest(testDispatcher) { + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + + activityController.pause() + advanceUntilIdle() + session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) + activityController.resume() + + assertFailsWith { underTest.single().createAnchor(Pose()) } + } @Test - fun createAnchor_planeTrackingDisabled_throwsIllegalStateException() { - val runtimePlane = FakeRuntimePlane() - getFakePerceptionManager().addTrackable(runtimePlane) - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap.values.first() as Plane - session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) + fun update_trackingStateMatchesTestPlaneVisibility() = + runTest(testDispatcher) { + activityController.resume() + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + advanceUntilIdle() - assertFailsWith { underTest.createAnchor(Pose()) } - } + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + advanceUntilIdle() + + assertThat(underTest.single().state.value.trackingState) + .isEqualTo(TrackingState.TRACKING) + + testPlane.isVisible = false + advanceUntilIdle() + + assertThat(underTest.single().state.value.trackingState).isEqualTo(TrackingState.PAUSED) + } @Test - fun update_trackingStateMatchesRuntime() = runBlocking { - val runtimePlane = FakeRuntimePlane() - runtimePlane.trackingState = TrackingState.STOPPED.toRuntimeTrackingState() - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap[runtimePlane] as Plane - check(underTest.state.value.trackingState == TrackingState.STOPPED) + fun update_planeTrackingDisabled_trackingStops() = + runTest(testDispatcher) { + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) - runtimePlane.trackingState = TrackingState.TRACKING.toRuntimeTrackingState() - underTest.update() + advanceUntilIdle() - assertThat(underTest.state.value.trackingState).isEqualTo(TrackingState.TRACKING) - } + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + + activityController.pause() + advanceUntilIdle() + session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) + activityController.resume() + advanceUntilIdle() + + assertThat(underTest.single().state.value.trackingState) + .isEqualTo(TrackingState.STOPPED) + } @Test - fun update_centerPoseMatchesRuntime() = runBlocking { - val runtimePlane = FakeRuntimePlane() - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap[runtimePlane] as Plane - check( - (underTest.state.value.centerPose == - Pose(Vector3(0f, 0f, 0f), Quaternion(0f, 0f, 0f, 1.0f))) - ) - - val newPose = Pose(Vector3(1.0f, 2.0f, 3.0f), Quaternion(1.0f, 2.0f, 3.0f, 4.0f)) - runtimePlane.centerPose = newPose - underTest.update() - - assertThat(underTest.state.value.centerPose).isEqualTo(newPose) - } + fun update_centerPoseMatchesTestPlaneCenterPose() = + runTest(testDispatcher) { + activityController.resume() + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + advanceUntilIdle() + + assertThat(underTest.single().state.value.centerPose).isEqualTo(Pose()) + + val newPose = Pose(Vector3(1.0f, 2.0f, 3.0f), Quaternion(1.0f, 2.0f, 3.0f, 4.0f)) + testPlane.centerPose = newPose + advanceUntilIdle() + + assertThat(underTest.single().state.value.centerPose).isEqualTo(newPose) + } @Test - fun update_extentsMatchesRuntime() = runBlocking { - val runtimePlane = FakeRuntimePlane() - val extents = FloatSize2d(1.0f, 2.0f) - runtimePlane.extents = extents - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap[runtimePlane] as Plane - underTest.update() - check(underTest.state.value.extents == extents) - - val newExtents = FloatSize2d(3.0f, 4.0f) - runtimePlane.extents = newExtents - underTest.update() - - assertThat(underTest.state.value.extents).isEqualTo(newExtents) - } + fun update_extentsMatchesTestPlaneExtents() = + runTest(testDispatcher) { + activityController.resume() + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + advanceUntilIdle() + + assertThat(underTest.single().state.value.extents).isEqualTo(FloatSize2d()) + + val newExtents = FloatSize2d(3.0f, 4.0f) + testPlane.extents = newExtents + advanceUntilIdle() + + assertThat(underTest.single().state.value.extents).isEqualTo(newExtents) + } @Test - fun update_verticesMatchesRuntime() = runBlocking { - val runtimePlane = FakeRuntimePlane() - val vertices = listOf(Vector2(1.0f, 2.0f), Vector2(3.0f, 4.0f)) - runtimePlane.vertices = vertices - xrResourcesManager.syncTrackables(listOf(runtimePlane)) - val underTest = xrResourcesManager.trackablesMap[runtimePlane] as Plane - underTest.update() - assertThat(underTest.state.value.vertices).isEqualTo(vertices) - - val newVertices = listOf(Vector2(3.0f, 4.0f), Vector2(5.0f, 6.0f)) - runtimePlane.vertices = newVertices - underTest.update() - - assertThat(underTest.state.value.vertices).isEqualTo(newVertices) - } + fun update_verticesMatchesTestPlaneVertices() = + runTest(testDispatcher) { + activityController.resume() + val testPlane = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + arCoreTestRule.addTrackables(testPlane) + advanceUntilIdle() + + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + advanceUntilIdle() + + assertThat(underTest.single().state.value.vertices).isEqualTo(listOf()) + + val newVertices = listOf(Vector2(3.0f, 4.0f), Vector2(5.0f, 6.0f)) + testPlane.vertices = newVertices + advanceUntilIdle() + + assertThat(underTest.single().state.value.vertices).isEqualTo(newVertices) + } @Test - fun update_subsumedByMatchesRuntime() = runBlocking { - val runtimePlane = FakeRuntimePlane() - val subsumedByRuntimePlane = FakeRuntimePlane() - getFakePerceptionManager().addTrackable(runtimePlane) - getFakePerceptionManager().addTrackable(subsumedByRuntimePlane) - xrResourcesManager.syncTrackables(listOf(runtimePlane, subsumedByRuntimePlane)) - xrResourcesManager.update() - val underTest = xrResourcesManager.trackablesMap[runtimePlane] as Plane - val subsumingPlaneWrapper = - xrResourcesManager.trackablesMap[subsumedByRuntimePlane] as Plane - check(underTest.state.value.subsumedBy == null) - - runtimePlane.subsumedBy = subsumedByRuntimePlane - xrResourcesManager.update() - - assertThat(underTest.state.value.subsumedBy).isNotNull() - assertThat(underTest.state.value.subsumedBy).isEqualTo(subsumingPlaneWrapper) - assertThat(underTest.state.value.subsumedBy!!.runtimePlane) - .isEqualTo(subsumedByRuntimePlane) - } + fun update_subsumedByMatchesTestPlaneSubsumedBy() = + runTest(testDispatcher) { + activityController.resume() + val testPlane1 = TestPlane(PlaneType.VERTICAL, PlaneLabel.WALL) + val testPlane2 = TestPlane(PlaneType.HORIZONTAL_UPWARD_FACING, PlaneLabel.TABLE) + arCoreTestRule.addTrackables(testPlane1, testPlane2) + advanceUntilIdle() - private fun getFakePerceptionManager(): FakePerceptionManager { - return session.perceptionRuntime.perceptionManager as FakePerceptionManager - } + var underTest = emptyList() + testScope.launch(start = CoroutineStart.UNDISPATCHED) { + Plane.subscribe(session).collect { underTest = it.toList() } + } + advanceUntilIdle() + + testPlane1.subsumedBy = testPlane2 + advanceUntilIdle() + + // XrResourcesManager stores Trackables in a ConcurrentHashMap so entries are unordered + val subsumed = underTest.first { it.state.value.subsumedBy != null } + val subsumer = underTest.first { it.state.value.subsumedBy == null } + assertThat(subsumed.state.value.subsumedBy).isEqualTo(subsumer) + } } diff --git a/xr/compose/compose/api/current.txt b/xr/compose/compose/api/current.txt index 1c5ba9c6019ba..feff136153a0d 100644 --- a/xr/compose/compose/api/current.txt +++ b/xr/compose/compose/api/current.txt @@ -820,32 +820,32 @@ package androidx.xr.compose.subspace.layout { } @kotlin.jvm.JvmInline public final value class PlaneOrientation { - method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneOrientation! box-impl(int); - method @BytecodeOnly public int unbox-impl(); + method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneOrientation! box-impl(java.util.Set!); + method @BytecodeOnly public java.util.Set! unbox-impl(); field public static final androidx.xr.compose.subspace.layout.PlaneOrientation.Companion Companion; } public static final class PlaneOrientation.Companion { - method @BytecodeOnly public int getAny-rnqRDCc(); - method @BytecodeOnly public int getHorizontal-rnqRDCc(); - method @BytecodeOnly public int getVertical-rnqRDCc(); + method @BytecodeOnly public java.util.Set getAny-rnqRDCc(); + method @BytecodeOnly public java.util.Set getHorizontal-rnqRDCc(); + method @BytecodeOnly public java.util.Set getVertical-rnqRDCc(); property public androidx.xr.compose.subspace.layout.PlaneOrientation Any; property public androidx.xr.compose.subspace.layout.PlaneOrientation Horizontal; property public androidx.xr.compose.subspace.layout.PlaneOrientation Vertical; } @kotlin.jvm.JvmInline public final value class PlaneSemantic { - method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneSemantic! box-impl(int); - method @BytecodeOnly public int unbox-impl(); + method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneSemantic! box-impl(java.util.Set!); + method @BytecodeOnly public java.util.Set! unbox-impl(); field public static final androidx.xr.compose.subspace.layout.PlaneSemantic.Companion Companion; } public static final class PlaneSemantic.Companion { - method @BytecodeOnly public int getAny-FWya8ks(); - method @BytecodeOnly public int getCeiling-FWya8ks(); - method @BytecodeOnly public int getFloor-FWya8ks(); - method @BytecodeOnly public int getTable-FWya8ks(); - method @BytecodeOnly public int getWall-FWya8ks(); + method @BytecodeOnly public java.util.Set getAny-FWya8ks(); + method @BytecodeOnly public java.util.Set getCeiling-FWya8ks(); + method @BytecodeOnly public java.util.Set getFloor-FWya8ks(); + method @BytecodeOnly public java.util.Set getTable-FWya8ks(); + method @BytecodeOnly public java.util.Set getWall-FWya8ks(); property public androidx.xr.compose.subspace.layout.PlaneSemantic Any; property public androidx.xr.compose.subspace.layout.PlaneSemantic Ceiling; property public androidx.xr.compose.subspace.layout.PlaneSemantic Floor; diff --git a/xr/compose/compose/api/restricted_current.txt b/xr/compose/compose/api/restricted_current.txt index ab8d5e5c0d86a..e2165ea9d7f72 100644 --- a/xr/compose/compose/api/restricted_current.txt +++ b/xr/compose/compose/api/restricted_current.txt @@ -851,32 +851,32 @@ package androidx.xr.compose.subspace.layout { } @kotlin.jvm.JvmInline public final value class PlaneOrientation { - method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneOrientation! box-impl(int); - method @BytecodeOnly public int unbox-impl(); + method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneOrientation! box-impl(java.util.Set!); + method @BytecodeOnly public java.util.Set! unbox-impl(); field public static final androidx.xr.compose.subspace.layout.PlaneOrientation.Companion Companion; } public static final class PlaneOrientation.Companion { - method @BytecodeOnly public int getAny-rnqRDCc(); - method @BytecodeOnly public int getHorizontal-rnqRDCc(); - method @BytecodeOnly public int getVertical-rnqRDCc(); + method @BytecodeOnly public java.util.Set getAny-rnqRDCc(); + method @BytecodeOnly public java.util.Set getHorizontal-rnqRDCc(); + method @BytecodeOnly public java.util.Set getVertical-rnqRDCc(); property public androidx.xr.compose.subspace.layout.PlaneOrientation Any; property public androidx.xr.compose.subspace.layout.PlaneOrientation Horizontal; property public androidx.xr.compose.subspace.layout.PlaneOrientation Vertical; } @kotlin.jvm.JvmInline public final value class PlaneSemantic { - method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneSemantic! box-impl(int); - method @BytecodeOnly public int unbox-impl(); + method @BytecodeOnly public static androidx.xr.compose.subspace.layout.PlaneSemantic! box-impl(java.util.Set!); + method @BytecodeOnly public java.util.Set! unbox-impl(); field public static final androidx.xr.compose.subspace.layout.PlaneSemantic.Companion Companion; } public static final class PlaneSemantic.Companion { - method @BytecodeOnly public int getAny-FWya8ks(); - method @BytecodeOnly public int getCeiling-FWya8ks(); - method @BytecodeOnly public int getFloor-FWya8ks(); - method @BytecodeOnly public int getTable-FWya8ks(); - method @BytecodeOnly public int getWall-FWya8ks(); + method @BytecodeOnly public java.util.Set getAny-FWya8ks(); + method @BytecodeOnly public java.util.Set getCeiling-FWya8ks(); + method @BytecodeOnly public java.util.Set getFloor-FWya8ks(); + method @BytecodeOnly public java.util.Set getTable-FWya8ks(); + method @BytecodeOnly public java.util.Set getWall-FWya8ks(); property public androidx.xr.compose.subspace.layout.PlaneSemantic Any; property public androidx.xr.compose.subspace.layout.PlaneSemantic Ceiling; property public androidx.xr.compose.subspace.layout.PlaneSemantic Floor; diff --git a/xr/compose/compose/lint-baseline.xml b/xr/compose/compose/lint-baseline.xml index 2bb1084b71269..4ad9ca9d2bcdc 100644 --- a/xr/compose/compose/lint-baseline.xml +++ b/xr/compose/compose/lint-baseline.xml @@ -1,14 +1,5 @@ - - - - - + @@ -76,7 +67,7 @@ @@ -85,7 +76,7 @@ @@ -103,7 +94,7 @@ @@ -112,26 +103,8 @@ - - - - - - - - + errorLine1=" coreEntity?.applyCoreEntityNodes(entityNodes.asSequence())" + errorLine2=" ~~~~~~~~~~"> @@ -154,22 +127,4 @@ file="src/main/kotlin/androidx/xr/compose/subspace/node/SubspaceLayoutNode.kt"/> - - - - - - - - diff --git a/xr/compose/compose/src/main/kotlin/androidx/xr/compose/subspace/layout/Anchorable.kt b/xr/compose/compose/src/main/kotlin/androidx/xr/compose/subspace/layout/Anchorable.kt index 0c0ecfde08ed0..10037162f75ec 100644 --- a/xr/compose/compose/src/main/kotlin/androidx/xr/compose/subspace/layout/Anchorable.kt +++ b/xr/compose/compose/src/main/kotlin/androidx/xr/compose/subspace/layout/Anchorable.kt @@ -242,13 +242,13 @@ internal class AnchorableNode( if (anchorPlaneOrientations.isEmpty() && anchorPlaneSemantics.isEmpty()) return mutableSetOf() - val planeTypeFilter: MutableSet = mutableSetOf() - anchorPlaneOrientations.forEach { planeTypeFilter.add(it.value) } - if (planeTypeFilter.isEmpty()) planeTypeFilter.add(SceneCorePlaneOrientation.ANY) + val planeTypeFilter: MutableSet = mutableSetOf() + anchorPlaneOrientations.forEach { planeTypeFilter.addAll(it.value) } + if (planeTypeFilter.isEmpty()) planeTypeFilter.addAll(SceneCorePlaneOrientation.ALL) - val planeSemanticFilter: MutableSet = mutableSetOf() - anchorPlaneSemantics.forEach { planeSemanticFilter.add(it.value) } - if (planeSemanticFilter.isEmpty()) planeSemanticFilter.add(SceneCorePlaneSemantic.ANY) + val planeSemanticFilter: MutableSet = mutableSetOf() + anchorPlaneSemantics.forEach { planeSemanticFilter.addAll(it.value) } + if (planeSemanticFilter.isEmpty()) planeSemanticFilter.addAll(SceneCorePlaneSemantic.ALL) return mutableSetOf(AnchorPlacement.createForPlanes(planeTypeFilter, planeSemanticFilter)) } @@ -256,12 +256,14 @@ internal class AnchorableNode( /** Type of plane based on orientation i.e. Horizontal or Vertical. */ @JvmInline -public value class PlaneOrientation private constructor(internal val value: Int) { +public value class PlaneOrientation +private constructor(internal val value: Set) { public companion object { public val Horizontal: PlaneOrientation = - PlaneOrientation(SceneCorePlaneOrientation.HORIZONTAL) - public val Vertical: PlaneOrientation = PlaneOrientation(SceneCorePlaneOrientation.VERTICAL) - public val Any: PlaneOrientation = PlaneOrientation(SceneCorePlaneOrientation.ANY) + PlaneOrientation(setOf(SceneCorePlaneOrientation.HORIZONTAL)) + public val Vertical: PlaneOrientation = + PlaneOrientation(setOf(SceneCorePlaneOrientation.VERTICAL)) + public val Any: PlaneOrientation = PlaneOrientation(SceneCorePlaneOrientation.ALL) } override fun toString(): String { @@ -276,13 +278,14 @@ public value class PlaneOrientation private constructor(internal val value: Int) /** Semantic plane types. */ @JvmInline -public value class PlaneSemantic private constructor(internal val value: Int) { +public value class PlaneSemantic +private constructor(internal val value: Set) { public companion object { - public val Wall: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.WALL) - public val Floor: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.FLOOR) - public val Ceiling: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.CEILING) - public val Table: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.TABLE) - public val Any: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.ANY) + public val Wall: PlaneSemantic = PlaneSemantic(setOf(SceneCorePlaneSemantic.WALL)) + public val Floor: PlaneSemantic = PlaneSemantic(setOf(SceneCorePlaneSemantic.FLOOR)) + public val Ceiling: PlaneSemantic = PlaneSemantic(setOf(SceneCorePlaneSemantic.CEILING)) + public val Table: PlaneSemantic = PlaneSemantic(setOf(SceneCorePlaneSemantic.TABLE)) + public val Any: PlaneSemantic = PlaneSemantic(SceneCorePlaneSemantic.ALL) } override fun toString(): String { diff --git a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/spatial/SubspaceTest.kt b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/spatial/SubspaceTest.kt index 877ff05f0626f..bd152f7c34cb4 100644 --- a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/spatial/SubspaceTest.kt +++ b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/spatial/SubspaceTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.compose.spatial import androidx.compose.foundation.layout.Box @@ -1838,7 +1840,7 @@ class SubspaceTest { val session = assertNotNull(composeTestRule.session) session.configure(Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL)) val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) composeTestRule.setContent { FollowingSubspace( @@ -1859,7 +1861,7 @@ class SubspaceTest { val session = assertNotNull(composeTestRule.session) session.configure(Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL)) val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) composeTestRule.setContent { FollowingSubspace( @@ -1883,7 +1885,7 @@ class SubspaceTest { val session = assertNotNull(composeTestRule.session) session.configure(Config(planeTracking = PlaneTrackingMode.HORIZONTAL_AND_VERTICAL)) val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) composeTestRule.setContent { Subspace(modifier = SubspaceModifier.offset(x = 40.dp, y = 50.dp, z = 60.dp)) { diff --git a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/SpatialGltfModelTest.kt b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/SpatialGltfModelTest.kt index 745c333ce86b0..a32cb062220e5 100644 --- a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/SpatialGltfModelTest.kt +++ b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/SpatialGltfModelTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.compose.subspace import android.annotation.TargetApi diff --git a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/AnchorableModifierTest.kt b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/AnchorableModifierTest.kt index a9ebd2f594cd6..645f9998cdcfa 100644 --- a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/AnchorableModifierTest.kt +++ b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/AnchorableModifierTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.compose.subspace.layout import androidx.compose.material3.Button diff --git a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/MovableModifierTest.kt b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/MovableModifierTest.kt index 8a8a958f148ae..b56d2b329ccbc 100644 --- a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/MovableModifierTest.kt +++ b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/subspace/layout/MovableModifierTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.compose.subspace.layout import androidx.compose.material3.Button diff --git a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/testing/ConfigureFakeSession.kt b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/testing/ConfigureFakeSession.kt index 0a12375edec15..1ce5150160073 100644 --- a/xr/compose/compose/src/test/kotlin/androidx/xr/compose/testing/ConfigureFakeSession.kt +++ b/xr/compose/compose/src/test/kotlin/androidx/xr/compose/testing/ConfigureFakeSession.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.compose.testing import android.app.Activity diff --git a/xr/glimmer/glimmer/samples/lint-baseline.xml b/xr/glimmer/glimmer/samples/lint-baseline.xml index d810967df1d9e..5bed2a488a60f 100644 --- a/xr/glimmer/glimmer/samples/lint-baseline.xml +++ b/xr/glimmer/glimmer/samples/lint-baseline.xml @@ -1,11 +1,11 @@ - + + errorLine1=" onSwipeForward = { log = "${Instant.now()} - onSwipeForward\n" + log }," + errorLine2=" ~~~"> @@ -13,8 +13,8 @@ + errorLine1=" onSwipeBackward = { log = "${Instant.now()} - onSwipeBackward\n" + log }," + errorLine2=" ~~~"> @@ -22,8 +22,8 @@ + errorLine1=" onClick = { log = "${Instant.now()} - onClick\n" + log }," + errorLine2=" ~~~"> diff --git a/xr/glimmer/glimmer/src/androidTest/kotlin/androidx/xr/glimmer/IconTest.kt b/xr/glimmer/glimmer/src/androidTest/kotlin/androidx/xr/glimmer/IconTest.kt index 6fbba8ab91f76..b93edc11fa099 100644 --- a/xr/glimmer/glimmer/src/androidTest/kotlin/androidx/xr/glimmer/IconTest.kt +++ b/xr/glimmer/glimmer/src/androidTest/kotlin/androidx/xr/glimmer/IconTest.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.testutils.assertPixels import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Canvas import androidx.compose.ui.graphics.Color @@ -31,8 +32,10 @@ import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.drawscope.CanvasDrawScope +import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.ColorPainter +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.path import androidx.compose.ui.platform.LocalDensity @@ -45,6 +48,7 @@ import androidx.compose.ui.test.assertContentDescriptionEquals import androidx.compose.ui.test.assertHeightIsEqualTo import androidx.compose.ui.test.assertWidthIsEqualTo import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp @@ -997,6 +1001,55 @@ class IconTest { .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Image)) } + @Test + fun painter_updatesWhenPainterChanges() { + // Under the hood, `Icon()` can change both sizes and colors. Therefore, the only fair way + // to isolate and test this case is by verifying the icon's shape. To do this, draw a + // horizontal line, then draw a vertical line with the same size and tint, and then check + // that the icon updates correctly. Use `drawRect()` instead of `drawLine()` to avoid + // anti-aliasing. + val horizontalLinePainter = + object : Painter() { + override val intrinsicSize: Size = Size(500f, 500f) + + override fun DrawScope.onDraw() { + // Draw a 1px horizontal line along the top edge. + drawRect(Color.White, Offset.Zero, Size(size.width, 1f)) + } + } + val verticalLinePainter = + object : Painter() { + override val intrinsicSize: Size = Size(500f, 500f) + + override fun DrawScope.onDraw() { + // Draw a 1px vertical line along the left edge. + drawRect(Color.White, Offset.Zero, Size(1f, size.height)) + } + } + + val painterState = mutableStateOf(horizontalLinePainter) + rule.setGlimmerThemeContent(density = Density(1f)) { + Icon( + painter = painterState.value, + contentDescription = iconTag, + modifier = Modifier.contentColorProvider(Color.White), + ) + } + + // Initially, verify the horizontal line is present at the top. + rule.onNodeWithContentDescription(iconTag).captureToImage().assertPixels { position -> + if (position.y == 0) Color.White else Color.Black + } + + // Switch the painter to the vertical line. + painterState.value = verticalLinePainter + + // Verify the cache was invalidated and we now see the vertical line on the left. + rule.onNodeWithContentDescription(iconTag).captureToImage().assertPixels { position -> + if (position.x == 0) Color.White else Color.Black + } + } + private fun createVectorWithColor(width: Dp, height: Dp, color: Color): ImageVector { return ImageVector.Builder( defaultWidth = width, diff --git a/xr/glimmer/glimmer/src/main/java/androidx/xr/glimmer/Icon.kt b/xr/glimmer/glimmer/src/main/java/androidx/xr/glimmer/Icon.kt index 79b009e1c10e7..8e0f7a16d0d6b 100644 --- a/xr/glimmer/glimmer/src/main/java/androidx/xr/glimmer/Icon.kt +++ b/xr/glimmer/glimmer/src/main/java/androidx/xr/glimmer/Icon.kt @@ -277,7 +277,11 @@ private fun Icon( ) { val colorFilter = if (useContentColor || tint != null) { - IconColorFilterElement(useContentColor = useContentColor, tint = tint) + IconColorFilterElement( + useContentColor = useContentColor, + tint = tint, + painter = painter, + ) } else { Modifier } @@ -304,11 +308,12 @@ private fun Icon( private class IconColorFilterElement( private val useContentColor: Boolean, private val tint: ColorProducer?, + private val painter: Painter, ) : ModifierNodeElement() { - override fun create() = IconColorFilterNode(useContentColor, tint) + override fun create() = IconColorFilterNode(useContentColor, tint, painter) override fun update(node: IconColorFilterNode) { - node.update(useContentColor, tint) + node.update(useContentColor, tint, painter) } override fun equals(other: Any?): Boolean { @@ -317,6 +322,7 @@ private class IconColorFilterElement( if (useContentColor != other.useContentColor) return false if (tint != other.tint) return false + if (painter != other.painter) return false return true } @@ -324,6 +330,7 @@ private class IconColorFilterElement( override fun hashCode(): Int { var result = useContentColor.hashCode() result = 31 * result + (tint?.hashCode() ?: 0) + result = 31 * result + painter.hashCode() return result } } @@ -331,6 +338,7 @@ private class IconColorFilterElement( private class IconColorFilterNode( private var useContentColor: Boolean, private var tint: ColorProducer?, + private var painter: Painter, ) : DelegatingNode() { val cacheDrawNode = delegate( @@ -357,11 +365,17 @@ private class IconColorFilterNode( } ) - fun update(useContentColor: Boolean, tint: ColorProducer?) { - if (this.useContentColor != useContentColor || this.tint != tint) { + fun update(useContentColor: Boolean, tint: ColorProducer?, painter: Painter) { + val painterChanged = this.painter != painter + if (this.useContentColor != useContentColor || this.tint != tint || painterChanged) { this.useContentColor = useContentColor this.tint = tint - cacheDrawNode.invalidateDraw() + this.painter = painter + if (painterChanged) { + cacheDrawNode.invalidateDrawCache() + } else { + cacheDrawNode.invalidateDraw() + } } } } diff --git a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/anchorentity/AnchorEntityActivity.kt b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/anchorentity/AnchorEntityActivity.kt index 195698eb05b9e..c1d725ee2e2ed 100644 --- a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/anchorentity/AnchorEntityActivity.kt +++ b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/anchorentity/AnchorEntityActivity.kt @@ -124,8 +124,8 @@ class AnchorEntityActivity : AppCompatActivity() { AnchorEntity.create( session!!, FloatSize2d(0.1f, 0.1f), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, ) val xyzModelEntity = GltfModelEntity.create( diff --git a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/model/GltfModelAnimationActivity.kt b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/model/GltfModelAnimationActivity.kt index 7f751afd96863..a31da9788962f 100644 --- a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/model/GltfModelAnimationActivity.kt +++ b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/model/GltfModelAnimationActivity.kt @@ -93,6 +93,12 @@ class GltfModelAnimationActivity : AppCompatActivity() { private val session by lazy { (Session.create(this) as SessionCreateSuccess).session } + private companion object { + const val STATE_PLAYING = "PLAYING" + const val STATE_STOPPED = "STOPPED" + const val STATE_PAUSED = "PAUSED" + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -284,7 +290,13 @@ class GltfModelAnimationActivity : AppCompatActivity() { animationList.setOnItemClickListener { parent, view, position, id -> selectedIndexAtAnimationList = position - animationStateText.text = animationStateMap[position].toString() + animationStateText.text = + when (animationStateMap[position]) { + GltfAnimation.AnimationState.PLAYING -> STATE_PLAYING + GltfAnimation.AnimationState.STOPPED -> STATE_STOPPED + GltfAnimation.AnimationState.PAUSED -> STATE_PAUSED + else -> STATE_STOPPED + } loopToggleButton.isChecked = false @@ -298,7 +310,7 @@ class GltfModelAnimationActivity : AppCompatActivity() { speedSlider.value = 1f } - animationStateText.text = "STOPPED" + animationStateText.text = STATE_STOPPED } } @@ -313,22 +325,27 @@ class GltfModelAnimationActivity : AppCompatActivity() { when (state) { GltfAnimation.AnimationState.PLAYING -> { Log.d(TAG, "${animation.name} animation is now playing!!") + if (animation.index == selectedIndexAtAnimationList) { + animationStateText.text = STATE_PLAYING + } } GltfAnimation.AnimationState.STOPPED -> { Log.d(TAG, "${animation.name} animation is now stopped!!") + if (animation.index == selectedIndexAtAnimationList) { + animationStateText.text = STATE_STOPPED + } } GltfAnimation.AnimationState.PAUSED -> { Log.d(TAG, "${animation.name} animation is now paused!!") + if (animation.index == selectedIndexAtAnimationList) { + animationStateText.text = STATE_PAUSED + } } } animationStateMap[animation.index] = state - - if (animation.index == selectedIndexAtAnimationList) { - animationStateText.text = state.toString() - } } } @@ -340,7 +357,7 @@ class GltfModelAnimationActivity : AppCompatActivity() { animations = emptyList() animationStateMap.clear() animationList.setText("Choose glTF Animations") - animationStateText.text = "STOPPED" + animationStateText.text = STATE_STOPPED selectedIndexAtAnimationList = -1 } diff --git a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/movable/MovableActivity.kt b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/movable/MovableActivity.kt index 35ea89b087f8b..bc5bea3a93d09 100644 --- a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/movable/MovableActivity.kt +++ b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/movable/MovableActivity.kt @@ -84,8 +84,8 @@ class MovableActivity : AppCompatActivity() { private var movableComponent: MovableComponent? = null private val executor = Executors.newSingleThreadExecutor() - private var planeOrientationFilter: MutableSet = mutableSetOf() - private var planeSemanticFilter: MutableSet = mutableSetOf() + private var planeOrientationFilter: MutableSet = mutableSetOf() + private var planeSemanticFilter: MutableSet = mutableSetOf() companion object { private const val TAG = "MovableActivity" @@ -231,6 +231,7 @@ class MovableActivity : AppCompatActivity() { movablePanelContentView.findViewById(R.id.custom_behavior_group) } + @Suppress("RestrictedApiAndroidX", "DEPRECATION") private fun setupAnchorPlacementCheckboxes(view: View, movablePanelEntity: Entity) { val planeOrientationCheckboxMap = mapOf( @@ -335,7 +336,7 @@ class MovableActivity : AppCompatActivity() { movablePanelEntity.addComponent(movableComponent!!) } - @SuppressLint("ExceptionMessage") + @Suppress("ExceptionMessage", "RestrictedApiAndroidX", "DEPRECATION") private fun createAnchorableGltfEntity() { lifecycleScope.launch { val gltfModel = diff --git a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/transformation/TransformationActivity.kt b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/transformation/TransformationActivity.kt index cff0831afa46d..a5a3cb8176092 100644 --- a/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/transformation/TransformationActivity.kt +++ b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/transformation/TransformationActivity.kt @@ -165,8 +165,8 @@ class TransformationActivity : AppCompatActivity() { AnchorEntity.create( session!!, FloatSize2d(0.1f, 0.1f), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, ) GltfModelEntity.create( session!!, diff --git a/xr/scenecore/scenecore-runtime/api/restricted_current.txt b/xr/scenecore/scenecore-runtime/api/restricted_current.txt index da558f83109bb..76fa9bd5b5ea5 100644 --- a/xr/scenecore/scenecore-runtime/api/restricted_current.txt +++ b/xr/scenecore/scenecore-runtime/api/restricted_current.txt @@ -1,33 +1,4 @@ // Signature format: 4.0 -package androidx.xr.scenecore.runtime { - - @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class SoundEffect { - ctor public SoundEffect(int id); - method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getId(); - property @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public int id; - } - - @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SoundEffectPool { - method public void clearOnLoadCompleteListener(); - method public androidx.xr.scenecore.runtime.SoundEffect load(android.content.Context context, int resId); - method public androidx.xr.scenecore.runtime.SoundEffect load(android.content.res.AssetFileDescriptor assetFileDescriptor); - method public void release(); - method public void setOnLoadCompleteListener(java.util.concurrent.Executor executor, androidx.xr.scenecore.runtime.SoundEffectPool.LoadCompleteListener listener); - method public boolean unload(androidx.xr.scenecore.runtime.SoundEffect soundEffect); - } - - public static fun interface SoundEffectPool.LoadCompleteListener { - method public void onLoadComplete(androidx.xr.scenecore.runtime.SoundEffect soundEffect, boolean success); - } - - @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Stream { - ctor public Stream(int streamId); - method @InaccessibleFromKotlin @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getStreamId(); - property @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public int streamId; - } - -} - package androidx.xr.scenecore.runtime.extensions { @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class XrExtensionsProvider { diff --git a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/GltfAnimationFeature.kt b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/GltfAnimationFeature.kt index 70feccd7cc704..14adcbaf7a5d2 100644 --- a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/GltfAnimationFeature.kt +++ b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/GltfAnimationFeature.kt @@ -22,8 +22,6 @@ import java.util.concurrent.Executor import java.util.function.Consumer /** Provide the rendering implementation for [GltfAnimationFeature] */ -// TODO(b/481429599): Audit usage of LIBRARY_GROUP_PREFIX in SceneCore and migrate it over to -// LIBRARY_GROUP. @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public interface GltfAnimationFeature { diff --git a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneSemantic.kt b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneSemantic.kt index 020766f03e44f..9ba586c629db7 100644 --- a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneSemantic.kt +++ b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneSemantic.kt @@ -25,5 +25,4 @@ public enum class PlaneSemantic { FLOOR, CEILING, TABLE, - ANY, } diff --git a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneType.kt b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneType.kt index 98dce76b28a37..5eb2fbfa9d65f 100644 --- a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneType.kt +++ b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/PlaneType.kt @@ -23,5 +23,4 @@ import androidx.annotation.RestrictTo public enum class PlaneType { HORIZONTAL, VERTICAL, - ANY, } diff --git a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/SoundEffectPool.kt b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/SoundEffectPool.kt index b6c1bd6226d63..6c2221646a2b5 100644 --- a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/SoundEffectPool.kt +++ b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/SoundEffectPool.kt @@ -22,13 +22,13 @@ import androidx.annotation.RestrictTo import androidx.annotation.RestrictTo.Scope import java.util.concurrent.Executor -@RestrictTo(Scope.LIBRARY_GROUP_PREFIX) -public class SoundEffect(@get:RestrictTo(Scope.LIBRARY_GROUP_PREFIX) public val id: Int) +@RestrictTo(Scope.LIBRARY_GROUP) +public class SoundEffect(@get:RestrictTo(Scope.LIBRARY_GROUP) public val id: Int) -@RestrictTo(Scope.LIBRARY_GROUP_PREFIX) -public class Stream(@get:RestrictTo(Scope.LIBRARY_GROUP_PREFIX) public val streamId: Int) +@RestrictTo(Scope.LIBRARY_GROUP) +public class Stream(@get:RestrictTo(Scope.LIBRARY_GROUP) public val streamId: Int) -@RestrictTo(Scope.LIBRARY_GROUP_PREFIX) +@RestrictTo(Scope.LIBRARY_GROUP) public interface SoundEffectPool { /** Callback interface for receiving notification when a sound effect has finished loading. */ public fun interface LoadCompleteListener { diff --git a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/extensions/XrExtensionsProvider.kt b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/extensions/XrExtensionsProvider.kt index a4cd11ef117e3..8f19dd10bddf4 100644 --- a/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/extensions/XrExtensionsProvider.kt +++ b/xr/scenecore/scenecore-runtime/src/main/kotlin/androidx/xr/scenecore/runtime/extensions/XrExtensionsProvider.kt @@ -24,7 +24,7 @@ import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method /** Provides the OEM implementation of [XrExtensions]. */ -@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used by XR Compose public object XrExtensionsProvider { private const val TAG = "XrExtensionsProvider" diff --git a/xr/scenecore/scenecore-runtime/src/test/kotlin/androidx/xr/scenecore/runtime/impl/OpenXrScenePoseTest.kt b/xr/scenecore/scenecore-runtime/src/test/kotlin/androidx/xr/scenecore/runtime/impl/OpenXrScenePoseTest.kt index b103e1982e421..4714995e6c795 100644 --- a/xr/scenecore/scenecore-runtime/src/test/kotlin/androidx/xr/scenecore/runtime/impl/OpenXrScenePoseTest.kt +++ b/xr/scenecore/scenecore-runtime/src/test/kotlin/androidx/xr/scenecore/runtime/impl/OpenXrScenePoseTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.runtime.impl import androidx.xr.runtime.math.Matrix4 diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ActivitySpaceImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ActivitySpaceImplTest.kt index 74f2d32b95c3b..e89a2ca014213 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ActivitySpaceImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ActivitySpaceImplTest.kt @@ -32,9 +32,9 @@ import androidx.xr.scenecore.runtime.HitTestResult import androidx.xr.scenecore.runtime.ScenePose import androidx.xr.scenecore.runtime.SceneRuntime import androidx.xr.scenecore.runtime.Space +import androidx.xr.scenecore.runtime.SpatialModeChangeListener import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider import androidx.xr.scenecore.testing.FakeScheduledExecutorService -import androidx.xr.scenecore.testing.FakeSpatialModeChangeListener import com.android.extensions.xr.ShadowXrExtensions import com.android.extensions.xr.XrExtensions import com.android.extensions.xr.environment.EnvironmentVisibilityState @@ -272,9 +272,21 @@ class ActivitySpaceImplTest : SystemSpaceEntityImplTest() { } } + private class TestSpatialModeChangeListener : SpatialModeChangeListener { + var lastRecommendedPose: Pose? = null + var lastRecommendedScale: Vector3? = null + var updateCount = 0 + + override fun onSpatialModeChanged(recommendedPose: Pose, recommendedScale: Vector3) { + lastRecommendedPose = recommendedPose + lastRecommendedScale = recommendedScale + updateCount++ + } + } + @Test fun handleOriginUpdate_unscaledGravityAlignedFalse_handlerCalled() { - val handler = FakeSpatialModeChangeListener() + val handler = TestSpatialModeChangeListener() activitySpace.setSpatialModeChangeListener(handler) val initialRotation = Quaternion.fromEulerAngles(30f, 0f, 0f) @@ -290,7 +302,7 @@ class ActivitySpaceImplTest : SystemSpaceEntityImplTest() { @Test fun handleOriginUpdate_unscaledGravityAlignedTrue_scaleAndRotationApplied_handlerCalled() { - val handler = FakeSpatialModeChangeListener() + val handler = TestSpatialModeChangeListener() testRuntime = createTestSceneRuntime() activitySpace = testRuntime.activitySpace as ActivitySpaceImpl activitySpace.setSpatialModeChangeListener(handler) @@ -323,7 +335,7 @@ class ActivitySpaceImplTest : SystemSpaceEntityImplTest() { @Test fun handleOriginUpdate_unscaledGravityAlignedTrue_preservesYaw() { - val handler = FakeSpatialModeChangeListener() + val handler = TestSpatialModeChangeListener() testRuntime = createTestSceneRuntime() activitySpace = testRuntime.activitySpace as ActivitySpaceImpl activitySpace.setSpatialModeChangeListener(handler) @@ -366,7 +378,7 @@ class ActivitySpaceImplTest : SystemSpaceEntityImplTest() { @Test fun handleOriginUpdate_noHandler_doesNotCallHandler() { - val handler = FakeSpatialModeChangeListener() + val handler = TestSpatialModeChangeListener() testRuntime = createTestSceneRuntime() activitySpace = testRuntime.activitySpace as ActivitySpaceImpl activitySpace.setSpatialModeChangeListener(null) @@ -520,7 +532,6 @@ class ActivitySpaceImplTest : SystemSpaceEntityImplTest() { override fun setPoseInOpenXrReferenceSpace_updatesScale() { val systemSpaceEntity = this.systemSpaceEntityImpl val matrix = Matrix4.fromScale(3.3f) - val scale = Vector3(3.3f, 3.3f, 3.3f) systemSpaceEntity.setOpenXrReferenceSpaceTransform(matrix) assertVector3(systemSpaceEntity.activitySpaceScale, Vector3.One) // ActivitySpace always returns Vector3.One diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/AnchorEntityImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/AnchorEntityImplTest.kt index 6f4c78c8fbe4a..da6f76e101820 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/AnchorEntityImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/AnchorEntityImplTest.kt @@ -32,10 +32,11 @@ import androidx.xr.runtime.math.Vector3 import androidx.xr.runtime.testing.math.assertPose import androidx.xr.runtime.testing.math.assertVector3 import androidx.xr.scenecore.runtime.AnchorEntity +import androidx.xr.scenecore.runtime.GltfFeature import androidx.xr.scenecore.runtime.Space import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider.getXrExtensions import androidx.xr.scenecore.runtime.impl.PerceptionSpaceScenePoseImpl -import androidx.xr.scenecore.testing.FakeGltfFeature +import androidx.xr.scenecore.testing.FakeGltfFeature.Companion.createWithMockFeature import androidx.xr.scenecore.testing.FakeScheduledExecutorService import com.android.extensions.xr.node.Node import com.android.extensions.xr.node.NodeRepository @@ -119,6 +120,24 @@ class AnchorEntityImplTest : SystemSpaceEntityImplTest() { ) } + private val mockGltfFeature: GltfFeature = mock() + + private fun createGltfEntity(): GltfEntityImpl { + val nodeHolder = NodeHolder(xrExtensions.createNode(), Node::class.java) + val activityController = Robolectric.buildActivity(Activity::class.java) + val activity = activityController.create().start().get() + val fakeGltfFeature = createWithMockFeature(mockGltfFeature, nodeHolder) + + return GltfEntityImpl( + activity, + fakeGltfFeature, + activitySpace, + xrExtensions, + sceneNodeRegistry, + executor, + ) + } + private fun createAnchorEntityWithRuntimeAnchor(): AnchorEntityImpl { val node = xrExtensions.createNode() val activityController = Robolectric.buildActivity(Activity::class.java) @@ -159,22 +178,6 @@ class AnchorEntityImplTest : SystemSpaceEntityImplTest() { ) } - /** Creates a generic glTF entity. */ - private fun createGltfEntity(): GltfEntityImpl { - val activityController = Robolectric.buildActivity(Activity::class.java) - val activity = activityController.create().start().get() - val nodeHolder: NodeHolder<*> = - NodeHolder((xrExtensions).createNode(), Node::class.java) - return GltfEntityImpl( - activity, - FakeGltfFeature(nodeHolder), - activitySpace, - xrExtensions, - sceneNodeRegistry, - executor, - ) - } - @Test fun anchorEntityAddChildren_addsChildren() { val childEntity1 = createGltfEntity() @@ -190,13 +193,6 @@ class AnchorEntityImplTest : SystemSpaceEntityImplTest() { Truth.assertThat(childEntity1.parent).isEqualTo(parentEntity) Truth.assertThat(childEntity2.parent).isEqualTo(parentEntity) Truth.assertThat(parentEntity.children).containsExactly(childEntity1, childEntity2) - - val parentNode = parentEntity.getNode() - val childNode1 = childEntity1.getNode() - val childNode2 = childEntity2.getNode() - - Truth.assertThat(NodeRepository.getInstance().getParent(childNode1)).isEqualTo(parentNode) - Truth.assertThat(NodeRepository.getInstance().getParent(childNode2)).isEqualTo(parentNode) } @Test diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MeshEntityImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MeshEntityImplTest.kt index cf8199eb2aad4..d721e33355944 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MeshEntityImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MeshEntityImplTest.kt @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.app.Activity diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MovableComponentImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MovableComponentImplTest.kt index 66d65f5927fe9..b8133fda18322 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MovableComponentImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/MovableComponentImplTest.kt @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.app.Activity diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/OpenXrScenePoseTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/OpenXrScenePoseTest.kt index c6c62d5816570..0106fd74b4bb1 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/OpenXrScenePoseTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/OpenXrScenePoseTest.kt @@ -27,10 +27,10 @@ import androidx.xr.runtime.testing.math.assertVector3 import androidx.xr.scenecore.runtime.GltfFeature import androidx.xr.scenecore.runtime.HitTestResult import androidx.xr.scenecore.runtime.ScenePose -import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider +import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider.getXrExtensions import androidx.xr.scenecore.runtime.impl.BaseScenePose import androidx.xr.scenecore.runtime.impl.OpenXrScenePose -import androidx.xr.scenecore.testing.FakeGltfFeature +import androidx.xr.scenecore.testing.FakeGltfFeature.Companion.createWithMockFeature import androidx.xr.scenecore.testing.FakeScheduledExecutorService import com.android.extensions.xr.XrExtensions import com.android.extensions.xr.node.Node @@ -53,8 +53,8 @@ import org.robolectric.annotation.Config */ @RunWith(RobolectricTestRunner::class) @Config(sdk = [Config.TARGET_SDK]) -class OpenXrScenePoseTest() { - private val xrExtensions: XrExtensions? = XrExtensionsProvider.getXrExtensions() +class OpenXrScenePoseTest { + private val xrExtensions: XrExtensions? = getXrExtensions() private val executor = FakeScheduledExecutorService() private val sceneNodeRegistry = SceneNodeRegistry() private val activity: Activity = @@ -75,8 +75,11 @@ class OpenXrScenePoseTest() { /** Creates a generic glTF entity. */ private fun createGltfEntity(): GltfEntityImpl { - val nodeHolder = NodeHolder(xrExtensions!!.createNode(), Node::class.java) - val fakeGltfFeature = FakeGltfFeature.createWithMockFeature(mockGltfFeature, nodeHolder) + val activityController = Robolectric.buildActivity(Activity::class.java) + val activity = activityController.create().start().get() + val nodeHolder = NodeHolder(xrExtensions!!.createNode(), Node::class.java) + val fakeGltfFeature = createWithMockFeature(mockGltfFeature, nodeHolder) + val xrExtensions = getXrExtensions()!! return GltfEntityImpl( activity, diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PanelEntityImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PanelEntityImplTest.kt index ae6bceb9a800d..d164af8479c96 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PanelEntityImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PanelEntityImplTest.kt @@ -27,9 +27,9 @@ import androidx.xr.runtime.math.Vector3 import androidx.xr.scenecore.runtime.Dimensions import androidx.xr.scenecore.runtime.PerceivedResolutionResult import androidx.xr.scenecore.runtime.PixelDimensions +import androidx.xr.scenecore.runtime.ScenePose import androidx.xr.scenecore.runtime.Space import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider.getXrExtensions -import androidx.xr.scenecore.testing.FakeScenePose import androidx.xr.scenecore.testing.FakeScheduledExecutorService import com.android.extensions.xr.node.NodeRepository import com.google.common.truth.Truth @@ -40,6 +40,8 @@ import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment @@ -58,7 +60,7 @@ class PanelEntityImplTest { private val nodeRepository: NodeRepository = NodeRepository.getInstance() private val pixelDimensions = PixelDimensions(2000, 1000) private lateinit var sceneRuntime: SpatialSceneRuntime - private var renderViewScenePose: FakeScenePose = FakeScenePose() + private val renderViewScenePose: ScenePose = mock(ScenePose::class.java) private lateinit var renderViewFov: FieldOfView @Before @@ -68,7 +70,8 @@ class PanelEntityImplTest { RuntimeEnvironment.setQualifiers(widthAndHeightConfig) sceneRuntime = SpatialSceneRuntime.create(activity, fakeExecutor, xrExtensions!!, sceneNodeRegistry) - renderViewScenePose.activitySpacePose = Pose(Vector3(0f, 0f, 0f), Quaternion.Identity) + `when`(renderViewScenePose.activitySpacePose) + .thenReturn(Pose(Vector3(0f, 0f, 0f), Quaternion.Identity)) renderViewFov = FieldOfView( atan(1.0).toFloat(), diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PerceivedResolutionUtilsTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PerceivedResolutionUtilsTest.kt index 6414e46be9ccb..30c5d37491fc3 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PerceivedResolutionUtilsTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PerceivedResolutionUtilsTest.kt @@ -25,14 +25,18 @@ import androidx.xr.runtime.math.Vector3 import androidx.xr.scenecore.runtime.Dimensions import androidx.xr.scenecore.runtime.PerceivedResolutionResult import androidx.xr.scenecore.runtime.PixelDimensions -import androidx.xr.scenecore.testing.FakeScenePose -import androidx.xr.scenecore.testing.FakeSceneRuntime +import androidx.xr.scenecore.runtime.ScenePose +import androidx.xr.scenecore.runtime.SceneRuntime +import androidx.xr.scenecore.testing.FakeScheduledExecutorService +import com.android.extensions.xr.XrExtensions import com.google.common.truth.Truth.assertThat import kotlin.math.atan import kotlin.math.roundToInt import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment @@ -46,14 +50,14 @@ class PerceivedResolutionUtilsTest { private lateinit var activityController: ActivityController private lateinit var activity: ComponentActivity - private lateinit var fakeCameraView: FakeScenePose + private val fakeCameraView: ScenePose = mock(ScenePose::class.java) // Default camera properties private lateinit var cameraPose: Pose private lateinit var cameraFov: FieldOfView private lateinit var cameraDisplayResolution: PixelDimensions private lateinit var session: Session - private lateinit var fakeSceneRuntime: FakeSceneRuntime + private lateinit var fakeSceneRuntime: SceneRuntime @Suppress("DEPRECATION") // TODO: b/494308962 Remove references to arcore-testing Fakes @@ -67,14 +71,20 @@ class PerceivedResolutionUtilsTest { activity = activityController.get() // Default camera setup: at origin, looking along -Z, 90deg HFOV, 90deg VFOV - fakeCameraView = FakeScenePose() - fakeCameraView.activitySpacePose = Pose(Vector3(0f, 0f, 0f), Quaternion.Identity) + `when`(fakeCameraView.activitySpacePose) + .thenReturn(Pose(Vector3(0f, 0f, 0f), Quaternion.Identity)) cameraPose = Pose(Vector3(0f, 0f, 0f), Quaternion.Identity) cameraFov = FieldOfView(atan(1.0f), atan(1.0f), atan(1.0f), atan(1.0f)) // tan(angle) = 1 => 45 deg cameraDisplayResolution = PixelDimensions(1000, 1000) // 1000x1000 display - fakeSceneRuntime = FakeSceneRuntime() + fakeSceneRuntime = + SpatialSceneRuntime.create( + activity, + FakeScheduledExecutorService(), + XrExtensions(), + SceneNodeRegistry(), + ) session = Session( activity, @@ -132,7 +142,8 @@ class PerceivedResolutionUtilsTest { @Test fun getDimensionsAndDistanceOfLargest3dBoxSurface_cameraNotAtOrigin() { - fakeCameraView.activitySpacePose = Pose(Vector3(1f, 1f, 1f), Quaternion.Identity) + `when`(fakeCameraView.activitySpacePose) + .thenReturn(Pose(Vector3(1f, 1f, 1f), Quaternion.Identity)) val boxDimensions = Dimensions(width = 1f, height = 2f, depth = 3f) // Smallest is width val boxPosition = Vector3(1f, 1f, -2f) // Box is 3 units away from camera along -Z relative to camera diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PositionalAudioComponentImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PositionalAudioComponentImplTest.kt index 0b92e9d3b1fa7..e06b909cd6ec1 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PositionalAudioComponentImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/PositionalAudioComponentImplTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.app.Activity diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ResizableComponentImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ResizableComponentImplTest.kt index 49d228098560e..c3d8239d1e458 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ResizableComponentImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/ResizableComponentImplTest.kt @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.app.Activity diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SceneNodeRegistryTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SceneNodeRegistryTest.kt index c6624e663d664..35a395b0489fc 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SceneNodeRegistryTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SceneNodeRegistryTest.kt @@ -28,12 +28,13 @@ import androidx.xr.scenecore.runtime.ActivitySpace import androidx.xr.scenecore.runtime.AnchorEntity import androidx.xr.scenecore.runtime.Entity import androidx.xr.scenecore.runtime.GltfEntity +import androidx.xr.scenecore.runtime.GltfFeature import androidx.xr.scenecore.runtime.PanelEntity import androidx.xr.scenecore.runtime.PerceptionSpaceScenePose import androidx.xr.scenecore.runtime.PixelDimensions import androidx.xr.scenecore.runtime.extensions.XrExtensionsProvider.getXrExtensions import androidx.xr.scenecore.runtime.impl.PerceptionSpaceScenePoseImpl -import androidx.xr.scenecore.testing.FakeGltfFeature +import androidx.xr.scenecore.testing.FakeGltfFeature.Companion.createWithMockFeature import androidx.xr.scenecore.testing.FakeScheduledExecutorService import com.android.extensions.xr.node.Node import com.google.common.truth.Truth.assertThat @@ -41,6 +42,7 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.mock import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -53,6 +55,7 @@ class SceneNodeRegistryTest { private val panelEntityNode: Node = xrExtensions.createNode() private val anchorEntityNode: Node = xrExtensions.createNode() private val sceneNodeRegistry = SceneNodeRegistry() + private val mockGltfFeature: GltfFeature = mock(GltfFeature::class.java) private lateinit var entityNode: Node private lateinit var gltfEntityNode: Node private val activity = Robolectric.buildActivity(Activity::class.java).create().start().get() @@ -135,14 +138,10 @@ class SceneNodeRegistryTest { assertThat(sceneNodeRegistry.getEntitiesOfType(PanelEntity::class.java)) .contains(panelEntity) // Base class of all entities. - assertThat(sceneNodeRegistry.getEntitiesOfType(Entity::class.java)).contains(entity) - assertThat(sceneNodeRegistry.getEntitiesOfType(AnchorEntity::class.java)) + assertThat(sceneNodeRegistry.getEntitiesOfType(Entity::class.java)).contains(entity) + assertThat(sceneNodeRegistry.getEntitiesOfType(AnchorEntity::class.java)) .containsExactly(anchorEntity) - assertThat( - sceneNodeRegistry.getEntitiesOfType( - ActivityPanelEntity::class.java - ) - ) + assertThat(sceneNodeRegistry.getEntitiesOfType(ActivityPanelEntity::class.java)) .containsExactly(activityPanelEntity) } @@ -194,14 +193,11 @@ class SceneNodeRegistryTest { @Test fun getSystemSpaceScenePoseOfType_returnsSystemSpaceScenePoseOfType() { - assertThat( - sceneNodeRegistry.getSystemSpaceScenePoseOfType(ActivitySpace::class.java).get(0) - ) + assertThat(sceneNodeRegistry.getSystemSpaceScenePoseOfType(ActivitySpace::class.java)[0]) .isInstanceOf(ActivitySpaceImpl::class.java) assertThat( sceneNodeRegistry - .getSystemSpaceScenePoseOfType(PerceptionSpaceScenePose::class.java) - .get(0) + .getSystemSpaceScenePoseOfType(PerceptionSpaceScenePose::class.java)[0] ) .isInstanceOf(PerceptionSpaceScenePoseImpl::class.java) } @@ -251,10 +247,11 @@ class SceneNodeRegistryTest { /** Creates a generic glTF entity. */ private fun createGltfEntity(): GltfEntity { val nodeHolder = NodeHolder(xrExtensions.createNode(), Node::class.java) + val fakeGltfFeature = createWithMockFeature(mockGltfFeature, nodeHolder) val gltfEntity = GltfEntityImpl( activity, - FakeGltfFeature(nodeHolder), + fakeGltfFeature, activitySpace, xrExtensions, sceneNodeRegistry, @@ -269,7 +266,7 @@ class SceneNodeRegistryTest { val display = activity!!.getSystemService(DisplayManager::class.java).displays[0] val displayContext = activity.createDisplayContext(display!!) val view = View(displayContext) - view.setLayoutParams(ViewGroup.LayoutParams(VGA_WIDTH, VGA_HEIGHT)) + view.layoutParams = ViewGroup.LayoutParams(VGA_WIDTH, VGA_HEIGHT) val panelEntity = PanelEntityImpl( displayContext, diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SoundEffectPoolImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SoundEffectPoolImplTest.kt index 3611c3252519d..1b25da84396a6 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SoundEffectPoolImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SoundEffectPoolImplTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.content.Context diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SpatialSceneRuntimeTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SpatialSceneRuntimeTest.kt index 6b44fd2fa4b6c..1e834777cbc82 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SpatialSceneRuntimeTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SpatialSceneRuntimeTest.kt @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.annotation.SuppressLint @@ -76,7 +79,6 @@ import com.android.extensions.xr.space.ShadowSpatialState import com.android.extensions.xr.space.SpatialCapabilities import com.android.extensions.xr.space.VisibilityState import com.google.common.collect.ImmutableList -import com.google.common.collect.ImmutableSet import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors import java.util.function.Consumer @@ -985,8 +987,8 @@ class SpatialSceneRuntimeTest { fun createAnchorPlacement_returnsAnchorPlacement() { val anchorPlacement = testRuntime.createAnchorPlacementForPlanes( - ImmutableSet.of<@JvmSuppressWildcards PlaneType>(PlaneType.ANY), - ImmutableSet.of<@JvmSuppressWildcards PlaneSemantic>(PlaneSemantic.ANY), + PlaneType.entries.toSet(), + PlaneSemantic.entries.toSet(), ) assertThat(anchorPlacement).isNotNull() diff --git a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SurfaceEntityImplTest.kt b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SurfaceEntityImplTest.kt index 33be7159ff966..5cbb45c191e5e 100644 --- a/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SurfaceEntityImplTest.kt +++ b/xr/scenecore/scenecore-spatial-core/src/test/java/androidx/xr/scenecore/spatial/core/SurfaceEntityImplTest.kt @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.core import android.app.Activity diff --git a/xr/scenecore/scenecore-spatial-rendering/src/test/java/androidx/xr/scenecore/spatial/rendering/SpatialRenderingRuntimeTest.kt b/xr/scenecore/scenecore-spatial-rendering/src/test/java/androidx/xr/scenecore/spatial/rendering/SpatialRenderingRuntimeTest.kt index ac4d884bf0233..fd9d6e4784469 100644 --- a/xr/scenecore/scenecore-spatial-rendering/src/test/java/androidx/xr/scenecore/spatial/rendering/SpatialRenderingRuntimeTest.kt +++ b/xr/scenecore/scenecore-spatial-rendering/src/test/java/androidx/xr/scenecore/spatial/rendering/SpatialRenderingRuntimeTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.spatial.rendering import android.app.Activity @@ -35,7 +37,8 @@ import androidx.xr.scenecore.runtime.RenderingRuntime import androidx.xr.scenecore.runtime.SceneRuntime import androidx.xr.scenecore.runtime.SurfaceEntity import androidx.xr.scenecore.runtime.TextureResource -import androidx.xr.scenecore.testing.FakeSceneRuntime +import androidx.xr.scenecore.spatial.core.SceneNodeRegistry +import androidx.xr.scenecore.spatial.core.SpatialSceneRuntime import androidx.xr.scenecore.testing.FakeScheduledExecutorService import androidx.xr.scenecore.testing.FakeXrExtensionsHolderProvider import com.android.extensions.xr.ShadowXrExtensions @@ -101,10 +104,10 @@ class SpatialRenderingRuntimeTest { activity.setContentView(FrameLayout(activity)) ShadowXrExtensions.extract(xrExtensions) .setOpenXrWorldSpaceType(OPEN_XR_REFERENCE_SPACE_TYPE) - val fakeSceneRuntime = FakeSceneRuntime(fakeExecutor) - sceneRuntime = fakeSceneRuntime + sceneRuntime = + SpatialSceneRuntime.create(activity, fakeExecutor, xrExtensions, SceneNodeRegistry()) - assertThat(fakeSceneRuntime).isNotNull() + assertThat(sceneRuntime).isNotNull() spatialRenderingRuntime = SpatialRenderingRuntime.create( diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntity.kt index 299d1c31d230c..4791e6a43851a 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity @@ -23,6 +25,7 @@ import androidx.annotation.RestrictTo import androidx.xr.scenecore.runtime.ActivityPanelEntity /** Test-only implementation of [androidx.xr.scenecore.runtime.ActivityPanelEntity] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeActivityPanelEntity(name: String = "") : FakePanelEntity(name = name), ActivityPanelEntity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivitySpace.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivitySpace.kt index b343cc77ce836..85ba1f9d6f505 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivitySpace.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeActivitySpace.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -33,6 +35,7 @@ import java.util.concurrent.atomic.AtomicReference * A test double for [androidx.xr.scenecore.runtime.ActivitySpace], designed for use in unit or * integration tests. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeActivitySpace() : FakeSystemSpaceEntity(), ActivitySpace { @RestrictTo(RestrictTo.Scope.LIBRARY) diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntity.kt index 950de8bbd776e..96cf56311917d 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import androidx.xr.scenecore.runtime.AnchorEntity import androidx.xr.scenecore.runtime.AnchorEntity.OnStateChangedListener /** Test-only implementation of [androidx.xr.scenecore.runtime.AnchorEntity] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeAnchorEntity : FakeSystemSpaceEntity(), AnchorEntity { /** diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacement.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacement.kt index 8465e449b06bb..3df6be7343145 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacement.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacement.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -36,10 +38,11 @@ import androidx.xr.scenecore.runtime.PlaneType * When an entity is successfully anchored, its pose is adjusted so that its local Z-axis aligns * with the plane's normal vector (i.e., it sits flat against the surface). */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeAnchorPlacement internal constructor( - internal val planeTypeFilter: Set<@JvmSuppressWildcards PlaneType> = setOf(PlaneType.ANY), + internal val planeTypeFilter: Set<@JvmSuppressWildcards PlaneType> = PlaneType.entries.toSet(), internal val planeSemanticFilter: Set<@JvmSuppressWildcards PlaneSemantic> = - setOf(PlaneSemantic.ANY), + PlaneSemantic.entries.toSet(), ) : AnchorPlacement diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapper.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapper.kt index 7a26664888642..173744926452a 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapper.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapper.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.AudioTrack @@ -25,6 +27,7 @@ import androidx.xr.scenecore.runtime.SoundFieldAttributes import androidx.xr.scenecore.runtime.SpatializerConstants /** Test-only implementation of [androidx.xr.scenecore.runtime.AudioTrackExtensionsWrapper] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeAudioTrackExtensionsWrapper : AudioTrackExtensionsWrapper { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBaseRenderingFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBaseRenderingFeature.kt index 4097d3467696b..0efeca3427fd2 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBaseRenderingFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBaseRenderingFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -21,6 +23,7 @@ import androidx.xr.runtime.NodeHolder import androidx.xr.scenecore.runtime.RenderingFeature /** Test-only implementation of [androidx.xr.scenecore.runtime.RenderingFeature] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeBaseRenderingFeature(private val _nodeHolder: NodeHolder<*>) : RenderingFeature { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponent.kt index 2af2394109eab..8e93a045c591c 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponent.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -@file:Suppress("BanConcurrentHashMap") +@file:Suppress("BanConcurrentHashMap", "DEPRECATION") package androidx.xr.scenecore.testing @@ -28,6 +28,7 @@ import java.util.concurrent.Executor import java.util.function.Consumer /** Test-only implementation of [BoundsComponent] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeBoundsComponent : FakeComponent(), BoundsComponent { public var entity: GltfEntity? = null diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeComponent.kt index 0441a48f5f5c2..1641191f77ede 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -21,6 +23,7 @@ import androidx.xr.scenecore.runtime.Component import androidx.xr.scenecore.runtime.Entity /** Test-only implementation of [androidx.xr.scenecore.runtime.Component] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeComponent : Component { /** diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeEntity.kt index 4bc013773ece9..6707950c29730 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -38,6 +40,7 @@ import java.util.concurrent.Executor * * @see androidx.xr.scenecore.runtime.Entity */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeEntity(public val name: String = "") : FakeScenePose(), Entity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeExrImageResource.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeExrImageResource.kt index e9ee0ab125645..5cbf7d5d30c9c 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeExrImageResource.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeExrImageResource.kt @@ -14,12 +14,15 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo import androidx.xr.scenecore.runtime.ExrImageResource /** Test-only implementation of [androidx.xr.scenecore.runtime.ExrImageResource] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeExrImageResource(public val mToken: Long) : ExrImageResource { /** diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeature.kt index 86aa18ea27f50..2d274491a513b 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import java.util.concurrent.Executor import java.util.function.Consumer /** Test-only implementation of [androidx.xr.scenecore.runtime.GltfAnimationFeature] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeGltfAnimationFeature( override val animationName: String? = "animation_name", diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfEntity.kt index c1187d9fd0124..fbc2173fb3c25 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -27,6 +29,7 @@ import java.util.concurrent.Executor import java.util.function.Consumer /** Test-only implementation of [androidx.xr.scenecore.runtime.GltfEntity] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeGltfEntity( private val feature: GltfFeature? = null, diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfFeature.kt index 2b85cae4e2d92..33e04d4b2b12c 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -29,6 +31,7 @@ import java.util.concurrent.Executor import java.util.function.Consumer /** Test-only implementation of [androidx.xr.scenecore.runtime.GltfFeature] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeGltfFeature(nodeHolder: NodeHolder<*>) : FakeBaseRenderingFeature(nodeHolder), GltfFeature { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeature.kt index 37df96d100d03..5f3b546cafd64 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -25,6 +27,7 @@ import androidx.xr.scenecore.runtime.MaterialResource /** Test-only implementation of [androidx.xr.scenecore.runtime.GltfModelNodeFeature] */ // TODO(b/481429599): Audit usage of LIBRARY_GROUP_PREFIX in SceneCore and migrate it over to // LIBRARY_GROUP. +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeGltfModelNodeFeature(override val name: String? = "test_node") : GltfModelNodeFeature { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelResource.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelResource.kt index 109faf1da2cf6..e87bfcc5c6ad7 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelResource.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeGltfModelResource.kt @@ -14,20 +14,23 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo import androidx.xr.scenecore.runtime.GltfModelResource /** Test-only implementation of [androidx.xr.scenecore.runtime.GltfModelResource] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeGltfModelResource(public val mToken: Long) : GltfModelResource { /** * The asset name that was used to "load" this fake resource. * * This property is intended for testing purposes. It is populated by the - * [FakeRenderingRuntime.loadGltfByAssetNameAsync] method and can be inspected by tests to - * verify that the correct asset path was used during the model loading process. + * [FakeRenderingRuntime.loadGltfByByteArray] method and can be inspected by tests to verify + * that the correct asset path was used during the model loading process. */ public var assetName: String = "" internal set @@ -36,8 +39,8 @@ public class FakeGltfModelResource(public val mToken: Long) : GltfModelResource * The asset data that was used to "load" this fake resource. * * This property is intended for testing purposes. It is populated by the - * [FakeRenderingRuntime.loadGltfByByteArrayAsync] method and can be inspected by tests to - * verify that the correct asset data was used during the model loading process. + * [FakeRenderingRuntime.loadGltfByByteArray] method and can be inspected by tests to verify + * that the correct asset data was used during the model loading process. */ public var assetData: ByteArray = ByteArray(0) internal set @@ -46,8 +49,8 @@ public class FakeGltfModelResource(public val mToken: Long) : GltfModelResource * The asset key that was used to "load" this fake resource. * * This property is intended for testing purposes. It is populated by the - * [FakeRenderingRuntime.loadGltfByByteArrayAsync] method and can be inspected by tests to - * verify that the correct asset key was used during the model loading process. + * [FakeRenderingRuntime.loadGltfByByteArray] method and can be inspected by tests to verify + * that the correct asset key was used during the model loading process. */ public var assetKey: String = "" internal set diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponent.kt index b9ab935b77f5d..10912a71ae9ea 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import androidx.xr.scenecore.runtime.InteractableComponent import java.util.concurrent.Executor /** Test-only implementation of [androidx.xr.scenecore.runtime.InteractableComponent] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeInteractableComponent() : FakeComponent(), InteractableComponent { internal val inputEventListenersMap: MutableMap = mutableMapOf() diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapper.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapper.kt index 07755e9a5c222..1e05becaa8119 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapper.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapper.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.MediaPlayer @@ -24,6 +26,7 @@ import androidx.xr.scenecore.runtime.PointSourceParams import androidx.xr.scenecore.runtime.SoundFieldAttributes /** Test-only implementation of [androidx.xr.scenecore.runtime.MediaPlayerExtensionsWrapper] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeMediaPlayerExtensionsWrapper : MediaPlayerExtensionsWrapper { private var _paramsWithEntity: MutableMap> = diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshEntity.kt index 75f6d190f4934..68942b574f1eb 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import androidx.xr.scenecore.runtime.MeshEntity import androidx.xr.scenecore.runtime.MeshFeature /** Test-only implementation of [androidx.xr.scenecore.runtime.MeshEntity] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeMeshEntity(private val feature: MeshFeature? = null) : FakeEntity(), MeshEntity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshFeature.kt index ccab9b20a9be9..5e0479b321c36 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMeshFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import androidx.xr.scenecore.runtime.MaterialResource import androidx.xr.scenecore.runtime.MeshFeature /** Test-only implementation of [androidx.xr.scenecore.runtime.MeshFeature] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeMeshFeature(nodeHolder: NodeHolder<*>) : FakeBaseRenderingFeature(nodeHolder), MeshFeature { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMovableComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMovableComponent.kt index 79a6463bee289..177f652d6cb9f 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMovableComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeMovableComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -26,6 +28,7 @@ import androidx.xr.scenecore.runtime.MoveEventListener import java.util.concurrent.Executor /** Test-only implementation of [androidx.xr.scenecore.runtime.MovableComponent] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeMovableComponent : FakeComponent(), MovableComponent { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeNode.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeNode.kt index d53c56c322d92..83c9e0fabd5ed 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeNode.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeNode.kt @@ -14,15 +14,20 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo import androidx.xr.runtime.NodeHolder /** Test-only interface for XrExtensions Node. */ -@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public interface FakeNode +@Deprecated("Use SceneCoreTestRule instead.") +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public interface FakeNode /** Test-only interface for Impress SubspaceNode. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public interface FakeSubspaceNode { public val nodeHolder: NodeHolder<*> diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePanelEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePanelEntity.kt index 6c414456cb877..dac589fced817 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePanelEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePanelEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.content.Context @@ -31,6 +33,7 @@ import androidx.xr.scenecore.runtime.ScenePose import kotlin.math.roundToInt /** Test-only implementation of [androidx.xr.scenecore.runtime.PanelEntity] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakePanelEntity(public val view: View? = null, name: String = "") : FakeEntity(name), PanelEntity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePerceptionSpaceScenePose.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePerceptionSpaceScenePose.kt index a295c4af1a41f..4555ea41144b3 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePerceptionSpaceScenePose.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePerceptionSpaceScenePose.kt @@ -14,11 +14,14 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo import androidx.xr.scenecore.runtime.PerceptionSpaceScenePose /** A fake ScenePose representing a perception space. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakePerceptionSpaceScenePose() : FakeScenePose(), PerceptionSpaceScenePose diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponent.kt index cf154a53b7ce3..cc908fe823fe6 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -25,6 +27,7 @@ import androidx.xr.scenecore.runtime.PointerCaptureComponent.StateListener import java.util.concurrent.Executor /** Test-only implementation of [FakePointerCaptureComponent] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakePointerCaptureComponent( /** diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePositionalAudioComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePositionalAudioComponent.kt index c36ead69a66a8..1c5591d5fa593 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePositionalAudioComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakePositionalAudioComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.content.Context @@ -24,6 +26,7 @@ import androidx.xr.scenecore.runtime.PointSourceParams import androidx.xr.scenecore.runtime.PositionalAudioComponent /** Test-only implementation of [PositionalAudioComponent]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakePositionalAudioComponent( internal val context: Context, diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntime.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntime.kt index 19da5abe36a3b..8fec8636dbe37 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntime.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntime.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -48,6 +50,7 @@ import java.nio.ByteBuffer * [androidx.xr.scenecore.runtime.SceneRuntime] instance, which must also implement * [androidx.xr.scenecore.runtime.RenderingEntityFactory]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeRenderingRuntime( private val sceneRuntime: SceneRuntime, @@ -124,7 +127,7 @@ public class FakeRenderingRuntime( * For test purposes only. * * A fake implementation of [androidx.xr.scenecore.runtime.MaterialResource] used to simulate a - * water material within the test senvironment. + * water material within the test environment. * *

Instances of this class are created by [createWaterMaterial] and can be accessed for * verification via the [createdWaterMaterials] list. Tests can inspect the public properties of @@ -134,6 +137,7 @@ public class FakeRenderingRuntime( * @param isAlphaMapVersion The value provided during creation, indicating which version of the * water material was requested. */ + @Deprecated("Use SceneCoreTestRule instead.") public class FakeWaterMaterial(public val isAlphaMapVersion: Boolean) : MaterialResource { public var reflectionMap: TextureResource? = null public var reflectionMapSampler: TextureSampler? = null @@ -172,6 +176,7 @@ public class FakeRenderingRuntime( * @param spec The [androidx.xr.scenecore.runtime.KhronosPbrMaterialSpec] provided during * creation, which defines the initial configuration of the material. */ + @Deprecated("Use SceneCoreTestRule instead.") public class FakeKhronosPbrMaterial(public val spec: KhronosPbrMaterialSpec) : MaterialResource { public var baseColorTexture: TextureResource? = null @@ -602,9 +607,9 @@ public class FakeRenderingRuntime( /** * The current state of the adapter will transition based on the lifecycle of the adapter. It - * starts off as [State.CREATED] and transitions to [State.STARTED] when startRenderer is - * called. When stopRenderer is called, it transitions to [State.PAUSED]. When dispose is - * called, it transitions to [State.DESTROYED]. + * starts off as [State.CREATED] and transitions to [State.STARTED] when [resume] is called. + * When [pause] is called, it transitions to [State.PAUSED]. When [destroy] is called, it + * transitions to [State.DESTROYED]. */ public val state: Enum get() = _state diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactory.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactory.kt index 89b25661e58ba..2f1bd817fdba1 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactory.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactory.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity @@ -25,6 +27,7 @@ import androidx.xr.scenecore.runtime.RenderingRuntime import androidx.xr.scenecore.runtime.SceneRuntime /** Factory for creating test-only instances of [androidx.xr.scenecore.runtime.RenderingRuntime]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeRenderingRuntimeFactory() : RenderingRuntimeFactory { override val requirements: Set = emptySet() diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResizableComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResizableComponent.kt index 61db8260e634a..d5f6b45c60a40 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResizableComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResizableComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,8 +25,10 @@ import androidx.xr.scenecore.runtime.ResizableComponent import androidx.xr.scenecore.runtime.ResizeEvent import androidx.xr.scenecore.runtime.ResizeEventListener import java.util.concurrent.Executor +import kotlin.collections.iterator /** Fake implementation of [androidx.xr.scenecore.runtime.ResizableComponent] for testing. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeResizableComponent( override var size: Dimensions = Dimensions(2.0f, 2.0f, 2.0f), diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResource.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResource.kt index edbc32cc72ece..333df4c4119f3 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResource.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeResource.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -24,6 +26,7 @@ import androidx.xr.scenecore.runtime.Resource import androidx.xr.scenecore.runtime.TextureResource /** Fake implementation of [androidx.xr.scenecore.runtime.Resource] for testing. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public data class FakeResource(internal val token: Long = 0) : Resource, ExrImageResource, GltfModelResource, TextureResource, MaterialResource {} diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeScenePose.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeScenePose.kt index b7ac6e3c889f1..1115462148d86 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeScenePose.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeScenePose.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -34,6 +36,7 @@ import androidx.xr.scenecore.runtime.impl.BaseScenePose * * @see androidx.xr.scenecore.runtime.ScenePose */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeScenePose : BaseScenePose() { /** Returns the pose for this entity, relative to the activity space root. */ diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntime.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntime.kt index 4787decef2d91..ec36e0f27e783 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntime.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntime.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity @@ -67,6 +69,7 @@ import java.util.function.Consumer * * @param executor This used to input [executor] for tests. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSceneRuntime(public val executor: Executor? = null) : SceneRuntime, RenderingEntityFactory { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactory.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactory.kt index 1961d37491ac9..0f040ae0e425f 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactory.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactory.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity @@ -22,6 +24,7 @@ import androidx.xr.runtime.interfaces.Feature import androidx.xr.runtime.internal.SceneRuntimeFactory /** Factory for creating test-only instances of [androidx.xr.scenecore.runtime.SceneRuntime]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSceneRuntimeFactory : SceneRuntimeFactory { override val requirements: Set = emptySet() diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPool.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPool.kt index 3d4afd9275e81..83e0fa1893078 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPool.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPool.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.content.Context @@ -24,6 +26,7 @@ import androidx.xr.scenecore.runtime.SoundEffectPool import java.util.concurrent.Executor /** Test-only implementation of [SoundEffectPool]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSoundEffectPool : SoundEffectPool { public var loadedResId: Int? = null diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPoolComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPoolComponent.kt index deec23011eabd..234af71272b18 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPoolComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundEffectPoolComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -24,6 +26,7 @@ import androidx.xr.scenecore.runtime.SoundEffectPoolComponent import androidx.xr.scenecore.runtime.Stream /** Test-only implementation of [SoundEffectPoolComponent]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSoundEffectPoolComponent : FakeComponent(), SoundEffectPoolComponent { public var lastPlayedSoundEffect: SoundEffect? = null diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundFieldAudioComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundFieldAudioComponent.kt index 7755a39120244..12c442263113e 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundFieldAudioComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundFieldAudioComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.content.Context @@ -23,6 +25,7 @@ import androidx.media3.exoplayer.audio.AudioTrackAudioOutputProvider import androidx.xr.scenecore.runtime.SoundFieldAudioComponent /** Test-only implementation of [SoundFieldAudioComponent]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSoundFieldAudioComponent(private val context: Context) : FakeComponent(), SoundFieldAudioComponent { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapper.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapper.kt index 36ed9c16efa5f..4b489284fa8b2 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapper.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapper.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.SoundPool @@ -25,6 +27,7 @@ import androidx.xr.scenecore.runtime.SoundPoolExtensionsWrapper import androidx.xr.scenecore.runtime.SpatializerConstants /** Test-only implementation of [androidx.xr.scenecore.runtime.SoundPoolExtensionsWrapper] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSoundPoolExtensionsWrapper : SoundPoolExtensionsWrapper { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironment.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironment.kt index f191407278770..eda6625ca7f1a 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironment.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironment.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -31,6 +33,7 @@ import java.util.function.Consumer * visibility by enabling or disabling passthrough. The skybox and geometry will be remembered * across passthrough mode changes. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSpatialEnvironment : SpatialEnvironment, SpatialEnvironmentExt { private var _currentPassthroughOpacity: Float = 0.0f diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentFeature.kt index 0802bbcb05507..4467d9796e683 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -22,6 +24,7 @@ import androidx.xr.scenecore.runtime.SpatialEnvironment.SpatialEnvironmentPrefer import androidx.xr.scenecore.runtime.SpatialEnvironmentFeature /** Test-only implementation of [androidx.xr.scenecore.runtime.SpatialEnvironmentFeature]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSpatialEnvironmentFeature : FakeBaseRenderingFeature(NodeHolder(object : FakeNode {}, FakeNode::class.java)), diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialModeChangeListener.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialModeChangeListener.kt index c2c41b3ade379..cd95807f52649 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialModeChangeListener.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialModeChangeListener.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -22,6 +24,7 @@ import androidx.xr.runtime.math.Vector3 import androidx.xr.scenecore.runtime.SpatialModeChangeListener @Suppress("ListenerInterface") +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSpatialModeChangeListener : SpatialModeChangeListener { public var lastRecommendedPose: Pose? = null diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponent.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponent.kt index e52bb31d985f1..3ee9ca2447911 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponent.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponent.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -23,6 +25,7 @@ import androidx.xr.scenecore.runtime.SpatialPointerIcon import androidx.xr.scenecore.runtime.SpatialPointerIconType /** Test-only implementation of [FakeSpatialPointerComponent] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSpatialPointerComponent : FakeComponent(), SpatialPointerComponent { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntity.kt index 9d74cfa805157..06d8085899921 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -21,6 +23,7 @@ import androidx.xr.scenecore.runtime.Dimensions import androidx.xr.scenecore.runtime.SubspaceNodeEntity /** Test-only implementation of [androidx.xr.scenecore.runtime.SubspaceNodeEntity]. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSubspaceNodeEntity( /** diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntity.kt index 1db445cebcfd5..a8b9096ff7e83 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.graphics.ImageFormat @@ -40,6 +42,7 @@ import androidx.xr.scenecore.runtime.TextureResource * can render stereoscopic content into the Surface and specify how it is routed to the User's eyes * for stereo viewing using the [stereoMode] property. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSurfaceEntity(private val feature: SurfaceFeature? = null) : FakeEntity(), SurfaceEntity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeature.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeature.kt index a80d18bc6d55b..b2d81d5e53d4c 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeature.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeature.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.graphics.ImageFormat @@ -29,6 +31,7 @@ import androidx.xr.scenecore.runtime.SurfaceFeature import androidx.xr.scenecore.runtime.TextureResource /** Test-only implementation of [androidx.xr.scenecore.runtime.SurfaceFeature] */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeSurfaceFeature(nodeHolder: NodeHolder<*>) : FakeBaseRenderingFeature(nodeHolder), SurfaceFeature { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntity.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntity.kt index e4b3075e89464..59589e9e753ed 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntity.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntity.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -26,6 +28,7 @@ import java.util.concurrent.Executor * A test double for [androidx.xr.scenecore.runtime.SystemSpaceEntity], designed for use in unit or * integration tests. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public open class FakeSystemSpaceEntity() : FakeEntity(), SystemSpaceEntity { diff --git a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeXrExtensionsHolderProvider.kt b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeXrExtensionsHolderProvider.kt index 891c6be0a4b76..b96c95ade9508 100644 --- a/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeXrExtensionsHolderProvider.kt +++ b/xr/scenecore/scenecore-testing/src/main/kotlin/androidx/xr/scenecore/testing/FakeXrExtensionsHolderProvider.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.annotation.RestrictTo @@ -28,6 +30,7 @@ import androidx.xr.scenecore.testing.FakeXrExtensionsHolderProvider.Companion.fa * This class allows tests to provide custom [XrExtensionsHolder] instances to simulate different XR * extension availability. */ +@Deprecated("Use SceneCoreTestRule instead.") @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FakeXrExtensionsHolderProvider : XrExtensionsHolderProvider { /** Returns the [fakeHolder] if both [fakeHolder] and [fakeHolderLegacy] is set. */ diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntityTest.kt index 0bc910a79b397..c193d2ea3ede3 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivityPanelEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivitySpaceTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivitySpaceTest.kt index 8a38c5c4bf4e1..75f6b5b954616 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivitySpaceTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeActivitySpaceTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.BoundingBox diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntityTest.kt index 0e7b4f33e62ec..770b342f5b416 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.AnchorEntity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacementTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacementTest.kt index e611f78b94b28..6bbacb872982e 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacementTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAnchorPlacementTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.PlaneSemantic diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapperTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapperTest.kt index 052786cca0357..968e063a8ea4c 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapperTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeAudioTrackExtensionsWrapperTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.AudioTrack diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponentTest.kt index 88100b0c4257c..5291e1a9dcee4 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeBoundsComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.BoundingBox diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeComponentTest.kt index 04de8c4342ef8..2c72f33e9d9e5 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import com.google.common.truth.Truth.assertThat diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeEntityTest.kt index 0e967c89f549f..2efb624b9233b 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.Pose diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeatureTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeatureTest.kt index cb7404fd010ba..405499cb5d5a9 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeatureTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfAnimationFeatureTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.GltfEntity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfEntityTest.kt index 1459f8c9f0149..8391f02666184 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.FloatSize3d diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeatureTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeatureTest.kt index 32367ac1ab327..dd2b303cee015 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeatureTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeGltfModelNodeFeatureTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.Pose diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponentTest.kt index 18852ce555f53..8f13ed24ec720 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeInteractableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.kruth.assertThat diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapperTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapperTest.kt index c7f8d141ef7e1..251714417535a 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapperTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMediaPlayerExtensionsWrapperTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.MediaPlayer diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMovableComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMovableComponentTest.kt index 6080fba1a45ec..7473d99a67ab6 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMovableComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeMovableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.Pose diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePanelEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePanelEntityTest.kt index b3ba4576479c3..ad574b6dfb55c 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePanelEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePanelEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponentTest.kt index 4193e0adc0f97..b5b16c91d454b 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakePointerCaptureComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.kruth.assertThat diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactoryTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactoryTest.kt index 499518e4c1b0b..6c979093065d6 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactoryTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeFactoryTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.test.ext.junit.runners.AndroidJUnit4 diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeTest.kt index 9362d6023d32b..9a33fd7e1e566 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeRenderingRuntimeTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeResizableComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeResizableComponentTest.kt index e422d243d47e9..7176ecd9ab9b6 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeResizableComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeResizableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.Dimensions diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeScenePoseTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeScenePoseTest.kt index 8610ffcbe8cf2..d719c9ed82b1e 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeScenePoseTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeScenePoseTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.runtime.math.Pose diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactoryTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactoryTest.kt index bdb9fabe9aeee..2fd9f4b096064 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactoryTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeFactoryTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.test.ext.junit.runners.AndroidJUnit4 diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeTest.kt index e0b4dd1a081ea..d5a72c999fd0f 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSceneRuntimeTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.app.Activity diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapperTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapperTest.kt index c95f9281c369c..08c10a68432a6 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapperTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSoundPoolExtensionsWrapperTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.media.SoundPool diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentTest.kt index a788ddb6e9d62..b2cffb7202d44 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialEnvironmentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.os.Build diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponentTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponentTest.kt index c72e9641f58e0..226abbc7361c7 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponentTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSpatialPointerComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.SpatialPointerIcon diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntityTest.kt index 43885e7b4c9ed..6f5fdd39e2a31 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSubspaceNodeEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import androidx.xr.scenecore.runtime.Dimensions diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntityTest.kt index 07dab0224ebd7..e13dce0d96f77 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.graphics.ImageFormat diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeatureTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeatureTest.kt index 79fe0cc19b2c1..5312fb9b6a8cf 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeatureTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSurfaceFeatureTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import android.graphics.ImageFormat diff --git a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntityTest.kt b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntityTest.kt index e4cbe86e33902..e91b0cbc13572 100644 --- a/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntityTest.kt +++ b/xr/scenecore/scenecore-testing/src/test/kotlin/androidx/xr/scenecore/testing/FakeSystemSpaceEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore.testing import com.google.common.truth.Truth.assertThat diff --git a/xr/scenecore/scenecore/api/current.txt b/xr/scenecore/scenecore/api/current.txt index 38fb6c230c89f..1fcf586d9f9df 100644 --- a/xr/scenecore/scenecore/api/current.txt +++ b/xr/scenecore/scenecore/api/current.txt @@ -48,8 +48,8 @@ package androidx.xr.scenecore { public final class AnchorEntity extends androidx.xr.scenecore.BaseEntity { method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.arcore.Anchor anchor); - method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType); - method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType, optional java.time.Duration timeout); + method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes); + method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes, optional java.time.Duration timeout); method @InaccessibleFromKotlin public androidx.xr.arcore.Anchor? getAnchor(); method @InaccessibleFromKotlin public androidx.xr.scenecore.AnchorEntity.State getState(); method public void setOnOriginChangedListener(Runnable? listener); @@ -63,9 +63,9 @@ package androidx.xr.scenecore { public static final class AnchorEntity.Companion { method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.arcore.Anchor anchor); - method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType); - method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType, optional java.time.Duration timeout); - method @BytecodeOnly public static androidx.xr.scenecore.AnchorEntity! create$default(androidx.xr.scenecore.AnchorEntity.Companion!, androidx.xr.runtime.Session!, androidx.xr.runtime.math.FloatSize2d!, int, int, java.time.Duration!, int, Object!); + method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes); + method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes, optional java.time.Duration timeout); + method @BytecodeOnly public static androidx.xr.scenecore.AnchorEntity! create$default(androidx.xr.scenecore.AnchorEntity.Companion!, androidx.xr.runtime.Session!, androidx.xr.runtime.math.FloatSize2d!, java.util.Set!, java.util.Set!, java.time.Duration!, int, Object!); } public static final class AnchorEntity.State { @@ -85,19 +85,19 @@ package androidx.xr.scenecore { public final class AnchorPlacement { method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(); - method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); - method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); - method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneOrientations(); - method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneSemanticTypes(); - property public java.util.Set anchorablePlaneOrientations; - property public java.util.Set anchorablePlaneSemanticTypes; + method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); + method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); + method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneOrientations(); + method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneSemanticTypes(); + property public java.util.Set anchorablePlaneOrientations; + property public java.util.Set anchorablePlaneSemanticTypes; field public static final androidx.xr.scenecore.AnchorPlacement.Companion Companion; } public static final class AnchorPlacement.Companion { method public androidx.xr.scenecore.AnchorPlacement createForPlanes(); - method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); - method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); + method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); + method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); method @BytecodeOnly public static androidx.xr.scenecore.AnchorPlacement! createForPlanes$default(androidx.xr.scenecore.AnchorPlacement.Companion!, java.util.Set!, java.util.Set!, int, Object!); } @@ -748,27 +748,33 @@ package androidx.xr.scenecore { } public final class PlaneOrientation { - property public static int ANY; - property public static int HORIZONTAL; - property public static int VERTICAL; - field public static final int ANY = 2; // 0x2 - field public static final int HORIZONTAL = 0; // 0x0 - field public static final androidx.xr.scenecore.PlaneOrientation INSTANCE; - field public static final int VERTICAL = 1; // 0x1 + field public static final java.util.Set ALL; + field public static final androidx.xr.scenecore.PlaneOrientation.Companion Companion; + field public static final androidx.xr.scenecore.PlaneOrientation HORIZONTAL; + field public static final androidx.xr.scenecore.PlaneOrientation VERTICAL; + } + + public static final class PlaneOrientation.Companion { + property public java.util.Set ALL; + property public androidx.xr.scenecore.PlaneOrientation HORIZONTAL; + property public androidx.xr.scenecore.PlaneOrientation VERTICAL; } public final class PlaneSemanticType { - property public static int ANY; - property public static int CEILING; - property public static int FLOOR; - property public static int TABLE; - property public static int WALL; - field public static final int ANY = 4; // 0x4 - field public static final int CEILING = 2; // 0x2 - field public static final int FLOOR = 1; // 0x1 - field public static final androidx.xr.scenecore.PlaneSemanticType INSTANCE; - field public static final int TABLE = 3; // 0x3 - field public static final int WALL = 0; // 0x0 + field public static final java.util.Set ALL; + field public static final androidx.xr.scenecore.PlaneSemanticType CEILING; + field public static final androidx.xr.scenecore.PlaneSemanticType.Companion Companion; + field public static final androidx.xr.scenecore.PlaneSemanticType FLOOR; + field public static final androidx.xr.scenecore.PlaneSemanticType TABLE; + field public static final androidx.xr.scenecore.PlaneSemanticType WALL; + } + + public static final class PlaneSemanticType.Companion { + property public java.util.Set ALL; + property public androidx.xr.scenecore.PlaneSemanticType CEILING; + property public androidx.xr.scenecore.PlaneSemanticType FLOOR; + property public androidx.xr.scenecore.PlaneSemanticType TABLE; + property public androidx.xr.scenecore.PlaneSemanticType WALL; } public final class PointSourceParams { diff --git a/xr/scenecore/scenecore/api/restricted_current.txt b/xr/scenecore/scenecore/api/restricted_current.txt index daff58a8017fb..c1b6b945a86ef 100644 --- a/xr/scenecore/scenecore/api/restricted_current.txt +++ b/xr/scenecore/scenecore/api/restricted_current.txt @@ -48,8 +48,8 @@ package androidx.xr.scenecore { public final class AnchorEntity extends androidx.xr.scenecore.BaseEntity { method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.arcore.Anchor anchor); - method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType); - method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType, optional java.time.Duration timeout); + method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes); + method public static androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes, optional java.time.Duration timeout); method @InaccessibleFromKotlin public androidx.xr.arcore.Anchor? getAnchor(); method @InaccessibleFromKotlin public androidx.xr.scenecore.AnchorEntity.State getState(); method public void setOnOriginChangedListener(Runnable? listener); @@ -63,9 +63,9 @@ package androidx.xr.scenecore { public static final class AnchorEntity.Companion { method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.arcore.Anchor anchor); - method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType); - method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, int planeOrientation, int planeSemanticType, optional java.time.Duration timeout); - method @BytecodeOnly public static androidx.xr.scenecore.AnchorEntity! create$default(androidx.xr.scenecore.AnchorEntity.Companion!, androidx.xr.runtime.Session!, androidx.xr.runtime.math.FloatSize2d!, int, int, java.time.Duration!, int, Object!); + method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes); + method public androidx.xr.scenecore.AnchorEntity create(androidx.xr.runtime.Session session, androidx.xr.runtime.math.FloatSize2d minimumPlaneExtents, java.util.Set planeOrientations, java.util.Set planeSemanticTypes, optional java.time.Duration timeout); + method @BytecodeOnly public static androidx.xr.scenecore.AnchorEntity! create$default(androidx.xr.scenecore.AnchorEntity.Companion!, androidx.xr.runtime.Session!, androidx.xr.runtime.math.FloatSize2d!, java.util.Set!, java.util.Set!, java.time.Duration!, int, Object!); } public static final class AnchorEntity.State { @@ -85,19 +85,19 @@ package androidx.xr.scenecore { public final class AnchorPlacement { method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(); - method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); - method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); - method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneOrientations(); - method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneSemanticTypes(); - property public java.util.Set anchorablePlaneOrientations; - property public java.util.Set anchorablePlaneSemanticTypes; + method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); + method public static androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); + method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneOrientations(); + method @InaccessibleFromKotlin public java.util.Set getAnchorablePlaneSemanticTypes(); + property public java.util.Set anchorablePlaneOrientations; + property public java.util.Set anchorablePlaneSemanticTypes; field public static final androidx.xr.scenecore.AnchorPlacement.Companion Companion; } public static final class AnchorPlacement.Companion { method public androidx.xr.scenecore.AnchorPlacement createForPlanes(); - method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); - method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); + method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations); + method public androidx.xr.scenecore.AnchorPlacement createForPlanes(optional java.util.Set anchorablePlaneOrientations, optional java.util.Set anchorablePlaneSemanticTypes); method @BytecodeOnly public static androidx.xr.scenecore.AnchorPlacement! createForPlanes$default(androidx.xr.scenecore.AnchorPlacement.Companion!, java.util.Set!, java.util.Set!, int, Object!); } @@ -756,27 +756,33 @@ package androidx.xr.scenecore { } public final class PlaneOrientation { - property public static int ANY; - property public static int HORIZONTAL; - property public static int VERTICAL; - field public static final int ANY = 2; // 0x2 - field public static final int HORIZONTAL = 0; // 0x0 - field public static final androidx.xr.scenecore.PlaneOrientation INSTANCE; - field public static final int VERTICAL = 1; // 0x1 + field public static final java.util.Set ALL; + field public static final androidx.xr.scenecore.PlaneOrientation.Companion Companion; + field public static final androidx.xr.scenecore.PlaneOrientation HORIZONTAL; + field public static final androidx.xr.scenecore.PlaneOrientation VERTICAL; + } + + public static final class PlaneOrientation.Companion { + property public java.util.Set ALL; + property public androidx.xr.scenecore.PlaneOrientation HORIZONTAL; + property public androidx.xr.scenecore.PlaneOrientation VERTICAL; } public final class PlaneSemanticType { - property public static int ANY; - property public static int CEILING; - property public static int FLOOR; - property public static int TABLE; - property public static int WALL; - field public static final int ANY = 4; // 0x4 - field public static final int CEILING = 2; // 0x2 - field public static final int FLOOR = 1; // 0x1 - field public static final androidx.xr.scenecore.PlaneSemanticType INSTANCE; - field public static final int TABLE = 3; // 0x3 - field public static final int WALL = 0; // 0x0 + field public static final java.util.Set ALL; + field public static final androidx.xr.scenecore.PlaneSemanticType CEILING; + field public static final androidx.xr.scenecore.PlaneSemanticType.Companion Companion; + field public static final androidx.xr.scenecore.PlaneSemanticType FLOOR; + field public static final androidx.xr.scenecore.PlaneSemanticType TABLE; + field public static final androidx.xr.scenecore.PlaneSemanticType WALL; + } + + public static final class PlaneSemanticType.Companion { + property public java.util.Set ALL; + property public androidx.xr.scenecore.PlaneSemanticType CEILING; + property public androidx.xr.scenecore.PlaneSemanticType FLOOR; + property public androidx.xr.scenecore.PlaneSemanticType TABLE; + property public androidx.xr.scenecore.PlaneSemanticType WALL; } public final class PointSourceParams { diff --git a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorEntity.kt b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorEntity.kt index 1898923e39d9c..33ef0c0081a77 100644 --- a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorEntity.kt +++ b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorEntity.kt @@ -19,6 +19,7 @@ package androidx.xr.scenecore import android.annotation.SuppressLint import android.os.SystemClock import androidx.annotation.RestrictTo +import androidx.annotation.RestrictTo.Scope import androidx.annotation.VisibleForTesting import androidx.xr.arcore.Anchor import androidx.xr.arcore.AnchorCreateSuccess @@ -116,8 +117,8 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : internal data class PlaneFindingInfo( val dimensions: FloatSize2d, - val orientation: @PlaneOrientationValue Int, - val semanticType: @PlaneSemanticTypeValue Int, + val orientations: Set, + val semanticTypes: Set, val searchDeadline: Long?, ) @@ -166,10 +167,8 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : val planeState = it.state.value val planeOrientation = it.type.toSceneCoreOrientation() val planeSemanticType = planeState.label.toSceneCoreSemanticType() - (info.orientation == planeOrientation || - info.orientation == PlaneOrientation.ANY) && - (info.semanticType == planeSemanticType || - info.semanticType == PlaneSemanticType.ANY) && + info.orientations.contains(planeOrientation) && + info.semanticTypes.contains(planeSemanticType) && info.dimensions.width <= planeState.extents.width && info.dimensions.height <= planeState.extents.height } @@ -200,8 +199,8 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : * @param entityRegistry [EntityRegistry] to use. * @param minimumPlaneExtents The minimum extents (in meters) of the plane to which this * AnchorEntity should attach. - * @param planeOrientation Orientation for the plane to which this Anchor should attach. - * @param planeSemanticType Semantics for the plane to which this Anchor should attach. + * @param planeOrientations Orientation for the plane to which this Anchor should attach. + * @param planeSemanticTypes Semantics for the plane to which this Anchor should attach. * @param timeout Maximum time to search for the anchor, if a suitable plane is not found * within the timeout time the AnchorEntity state will be set to TIMED_OUT. */ @@ -209,8 +208,8 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : session: Session, entityRegistry: EntityRegistry, minimumPlaneExtents: FloatSize2d, - planeOrientation: @PlaneOrientationValue Int, - planeSemanticType: @PlaneSemanticTypeValue Int, + planeOrientations: Set, + planeSemanticTypes: Set, timeout: Duration = Duration.ZERO, ): AnchorEntity { check(session.config.planeTracking != PlaneTrackingMode.DISABLED) { @@ -224,8 +223,8 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : val info = PlaneFindingInfo( minimumPlaneExtents, - planeOrientation, - planeSemanticType, + planeOrientations, + planeSemanticTypes, getAnchorDeadline(timeout), ) findAndSetPlaneAnchor(session, info, anchorEntity) @@ -268,19 +267,62 @@ private constructor(rtEntity: RtAnchorEntity, entityRegistry: EntityRegistry) : */ @JvmStatic @JvmOverloads + @Deprecated( + "Use the factory which accepts Set and Set instead." + ) + // TODO: b/500464864 - Remove this factory method. + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public fun create( session: Session, minimumPlaneExtents: FloatSize2d, - planeOrientation: @PlaneOrientationValue Int, - planeSemanticType: @PlaneSemanticTypeValue Int, + planeOrientation: PlaneOrientation, + planeSemanticType: PlaneSemanticType, timeout: Duration = Duration.ZERO, ): AnchorEntity { return create( session, session.scene.entityRegistry, minimumPlaneExtents, - planeOrientation, - planeSemanticType, + setOf(planeOrientation), + setOf(planeSemanticType), + timeout, + ) + } + + /** + * Factory for an AnchorEntity which searches for a real-world surface on which to anchor, + * from the set of tracked planes available to the perception system. + * + * @param session [Session] in which to create the AnchorEntity. + * @param minimumPlaneExtents The minimum extents (in meters) of the plane to which this + * AnchorEntity should attach. + * @param planeOrientations [PlaneOrientation]s of the plane to which this AnchorEntity + * should attach. + * @param planeSemanticTypes [PlaneSemanticType]s of the plane to which this AnchorEntity + * should attach. + * @param timeout The amount of time as a [Duration] to search for the a suitable plane to + * attach to. If a plane is not found within the timeout, the returned AnchorEntity state + * will be set to AnchorEntity.State.TIMEDOUT. It may take longer than the timeout period + * before the anchor state is updated. If the timeout duration is zero it will search for + * the anchor indefinitely. + * @throws [IllegalStateException] if [androidx.xr.runtime.Session.config] is set to + * [PlaneTrackingMode.DISABLED]. + */ + @JvmStatic + @JvmOverloads + public fun create( + session: Session, + minimumPlaneExtents: FloatSize2d, + planeOrientations: Set, + planeSemanticTypes: Set, + timeout: Duration = Duration.ZERO, + ): AnchorEntity { + return create( + session, + session.scene.entityRegistry, + minimumPlaneExtents, + planeOrientations, + planeSemanticTypes, timeout, ) } diff --git a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorPlacement.kt b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorPlacement.kt index 0e27a8de5ae3a..996a2a473a38a 100644 --- a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorPlacement.kt +++ b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/AnchorPlacement.kt @@ -24,8 +24,8 @@ package androidx.xr.scenecore */ public class AnchorPlacement private constructor( - public val anchorablePlaneOrientations: Set<@PlaneOrientationValue Int>, - public val anchorablePlaneSemanticTypes: Set<@PlaneSemanticTypeValue Int>, + public val anchorablePlaneOrientations: Set, + public val anchorablePlaneSemanticTypes: Set, ) { override fun equals(other: Any?): Boolean { @@ -72,14 +72,24 @@ private constructor( @JvmStatic @JvmOverloads public fun createForPlanes( - anchorablePlaneOrientations: Set<@PlaneOrientationValue Int> = - setOf(PlaneOrientation.ANY), - anchorablePlaneSemanticTypes: Set<@PlaneSemanticTypeValue Int> = - setOf(PlaneSemanticType.ANY), + anchorablePlaneOrientations: Set = PlaneOrientation.ALL, + anchorablePlaneSemanticTypes: Set = PlaneSemanticType.ALL, ): AnchorPlacement { + + @Suppress("DEPRECATION") + // TODO: b/500464864 - Cleanup when ANY is removed + val planeOrientations = + if (anchorablePlaneOrientations.contains(PlaneOrientation.ANY)) PlaneOrientation.ALL + else anchorablePlaneOrientations.toSet() // defensive copy + + @Suppress("DEPRECATION") + val planeSemanticTypes = + if (anchorablePlaneSemanticTypes.contains(PlaneSemanticType.ANY)) + PlaneSemanticType.ALL + else anchorablePlaneSemanticTypes.toSet() // defensive copy return AnchorPlacement( - anchorablePlaneOrientations = anchorablePlaneOrientations.toSet(), - anchorablePlaneSemanticTypes = anchorablePlaneSemanticTypes.toSet(), + anchorablePlaneOrientations = planeOrientations, + anchorablePlaneSemanticTypes = planeSemanticTypes, ) } } diff --git a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/MovableComponent.kt b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/MovableComponent.kt index 52c9dc0b3ba1e..1140be5d6270e 100644 --- a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/MovableComponent.kt +++ b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/MovableComponent.kt @@ -135,14 +135,8 @@ private constructor( val planeSemantic = planeData.label.toSceneCoreSemanticType() for (anchorPlacementSpec in anchorPlacement) { if ( - (anchorPlacementSpec.anchorablePlaneOrientations.contains(planeOrientation) || - anchorPlacementSpec.anchorablePlaneOrientations.contains( - PlaneOrientation.ANY - )) && - (anchorPlacementSpec.anchorablePlaneSemanticTypes.contains(planeSemantic) || - anchorPlacementSpec.anchorablePlaneSemanticTypes.contains( - PlaneSemanticType.ANY - )) && + anchorPlacementSpec.anchorablePlaneOrientations.contains(planeOrientation) && + anchorPlacementSpec.anchorablePlaneSemanticTypes.contains(planeSemantic) && planeData.trackingState == TrackingState.TRACKING ) { outPlane = it diff --git a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Types.kt b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Types.kt index cb8798b132d7e..a07a06e9aaa8a 100644 --- a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Types.kt +++ b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Types.kt @@ -15,42 +15,75 @@ */ package androidx.xr.scenecore -import androidx.annotation.IntDef import androidx.annotation.RestrictTo +import androidx.xr.scenecore.PlaneOrientation.Companion.HORIZONTAL +import androidx.xr.scenecore.PlaneOrientation.Companion.VERTICAL -/** Type of plane based on orientation i.e. Horizontal or Vertical. */ -// TODO - b/419544472 Align on a common implementation for this type in SceneCore & ARCore. -public object PlaneOrientation { - public const val HORIZONTAL: Int = 0 - public const val VERTICAL: Int = 1 - public const val ANY: Int = 2 -} +/** + * Orientation of a plane, to specify valid surfaces for anchoring. + * + * For example, see [MovableComponent.createAnchorable]. + */ +public class PlaneOrientation private constructor(private val value: Int) { + // Note: These constants have some overlap with androidx.xr.arcore.Plane.Type, though the + // constants here are specifically for filtering anchors. Due to the difference in semantics, + // the constants are not shared between ARCore and SceneCore. + + public companion object { + + /** Any plane orientation is acceptable. */ + // TODO: b/500464864 - Remove this constant. + @Deprecated("Explicitly enumerate PlaneOrientation constants, or use ALL") + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + @JvmField + public val ANY: PlaneOrientation = PlaneOrientation(0) -@RestrictTo(RestrictTo.Scope.LIBRARY) -@Retention(AnnotationRetention.SOURCE) -@IntDef(PlaneOrientation.HORIZONTAL, PlaneOrientation.VERTICAL, PlaneOrientation.ANY) -@Target(AnnotationTarget.TYPE, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) -public annotation class PlaneOrientationValue - -/** Semantic plane types. */ -// TODO - b/419544472 Align on a common implementation for this type in SceneCore & ARCore. -public object PlaneSemanticType { - - public const val WALL: Int = 0 - public const val FLOOR: Int = 1 - public const val CEILING: Int = 2 - public const val TABLE: Int = 3 - public const val ANY: Int = 4 + /** Specify horizontal planes. */ + @JvmField public val HORIZONTAL: PlaneOrientation = PlaneOrientation(1) + + /** Specify vertical planes. */ + @JvmField public val VERTICAL: PlaneOrientation = PlaneOrientation(2) + + /** Immutable Set containing all PlaneOrientations. */ + @JvmField public val ALL: Set = setOf(HORIZONTAL, VERTICAL) + } + + public override fun toString(): String = value.toString() } -@RestrictTo(RestrictTo.Scope.LIBRARY) -@Retention(AnnotationRetention.SOURCE) -@IntDef( - PlaneSemanticType.WALL, - PlaneSemanticType.FLOOR, - PlaneSemanticType.CEILING, - PlaneSemanticType.TABLE, - PlaneSemanticType.ANY, -) -@Target(AnnotationTarget.TYPE, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) -public annotation class PlaneSemanticTypeValue +/** + * The detected semantic type of a plane, to specify valid surfaces for anchoring. + * + * For example, see [MovableComponent.createAnchorable]. + */ +public class PlaneSemanticType private constructor(private val value: Int) { + // Note: These constants have some overlap with androidx.xr.arcore.Plane.Label, though the + // constants here are specifically for filtering anchors. Due to the difference in semantics, + // the constants are not shared between ARCore and SceneCore. + + public companion object { + /** Any plane type is acceptable. */ + // TODO: b/500464864 - Remove this constant. + @Deprecated("Explicitly enumerate PlaneSemanticType constants, or use ALL") + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + @JvmField + public val ANY: PlaneSemanticType = PlaneSemanticType(0) + + /** Specify planes that are identified as a wall. */ + @JvmField public val WALL: PlaneSemanticType = PlaneSemanticType(1) + + /** Specify planes that are identified as the floor. */ + @JvmField public val FLOOR: PlaneSemanticType = PlaneSemanticType(2) + + /** Specify planes that are identified as the ceiling. */ + @JvmField public val CEILING: PlaneSemanticType = PlaneSemanticType(3) + + /** Specify planes that are identified as a table. */ + @JvmField public val TABLE: PlaneSemanticType = PlaneSemanticType(4) + + /** Immutable Set containing all PlaneSemanticTypes. */ + @JvmField public val ALL: Set = setOf(WALL, FLOOR, CEILING, TABLE) + } + + public override fun toString(): String = value.toString() +} diff --git a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Utils.kt b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Utils.kt index b90887f5e7e7a..621fad3939572 100644 --- a/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Utils.kt +++ b/xr/scenecore/scenecore/src/main/java/androidx/xr/scenecore/Utils.kt @@ -118,11 +118,10 @@ internal fun RtPixelDimensions.toIntSize2d(): IntSize2d { /** * Extension function that converts [PlaneOrientation] to [androidx.xr.scenecore.runtime.PlaneType]. */ -internal fun Int.toRtPlaneType(): RtPlaneType { +internal fun PlaneOrientation.toRtPlaneType(): RtPlaneType { return when (this) { PlaneOrientation.HORIZONTAL -> RtPlaneType.HORIZONTAL PlaneOrientation.VERTICAL -> RtPlaneType.VERTICAL - PlaneOrientation.ANY -> RtPlaneType.ANY else -> error("Unknown Plane Type: $PlaneOrientation") } } @@ -131,13 +130,12 @@ internal fun Int.toRtPlaneType(): RtPlaneType { * Extension function that converts [PlaneSemanticType] to * [androidx.xr.scenecore.runtime.PlaneSemantic]. */ -internal fun Int.toRtPlaneSemantic(): RtPlaneSemantic { +internal fun PlaneSemanticType.toRtPlaneSemantic(): RtPlaneSemantic { return when (this) { PlaneSemanticType.WALL -> RtPlaneSemantic.WALL PlaneSemanticType.FLOOR -> RtPlaneSemantic.FLOOR PlaneSemanticType.CEILING -> RtPlaneSemantic.CEILING PlaneSemanticType.TABLE -> RtPlaneSemantic.TABLE - PlaneSemanticType.ANY -> RtPlaneSemantic.ANY else -> error("Unknown Plane Semantic: $PlaneSemanticType") } } @@ -272,9 +270,9 @@ internal fun Set.toRtAnchorPlacement( return rtAnchorPlacementSet } -/** Extension function that converts an ARCore [PlaneType] to a Scene [PlaneOrientationValue] */ +/** Extension function that converts an ARCore [PlaneType] to a Scene [PlaneOrientation] */ @Suppress("DEPRECATION") -internal fun PlaneType.toSceneCoreOrientation(): @PlaneOrientationValue Int = +internal fun PlaneType.toSceneCoreOrientation(): PlaneOrientation = when (this) { PlaneType.HORIZONTAL_UPWARD_FACING -> PlaneOrientation.HORIZONTAL PlaneType.HORIZONTAL_DOWNWARD_FACING -> PlaneOrientation.HORIZONTAL @@ -284,15 +282,16 @@ internal fun PlaneType.toSceneCoreOrientation(): @PlaneOrientationValue Int = /** * Extension function that converts an ARCore [androidx.xr.arcore.PlaneLabel] to a Scene - * [PlaneSemanticTypeValue] + * [PlaneSemanticType] */ @Suppress("DEPRECATION") -internal fun PlaneLabel.toSceneCoreSemanticType(): @PlaneSemanticTypeValue Int = +internal fun PlaneLabel.toSceneCoreSemanticType(): PlaneSemanticType = when (this) { PlaneLabel.FLOOR -> PlaneSemanticType.FLOOR PlaneLabel.TABLE -> PlaneSemanticType.TABLE PlaneLabel.WALL -> PlaneSemanticType.WALL PlaneLabel.CEILING -> PlaneSemanticType.CEILING + // TODO: b/500464864 - Cleanup when PlaneSemanticType.ANY is removed. PlaneLabel.UNKNOWN -> PlaneSemanticType.ANY else -> error("Unknown semantic type: $this") } diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ActivitySpaceTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ActivitySpaceTest.kt index 5349042f7e2f0..25d74d447874e 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ActivitySpaceTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ActivitySpaceTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.app.Activity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorEntityTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorEntityTest.kt index 27addc03b2793..9b830ca5a4e71 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorEntityTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.os.Build @@ -125,8 +127,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, timeout = 0.toDuration(DurationUnit.SECONDS).toJavaDuration(), ) @@ -147,8 +149,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.HORIZONTAL, - PlaneSemanticType.CEILING, + setOf(PlaneOrientation.HORIZONTAL), + setOf(PlaneSemanticType.CEILING), timeout = 0.toDuration(DurationUnit.SECONDS).toJavaDuration(), ) @@ -173,8 +175,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.HORIZONTAL, - PlaneSemanticType.CEILING, + setOf(PlaneOrientation.HORIZONTAL), + setOf(PlaneSemanticType.CEILING), timeout = 0.toDuration(DurationUnit.SECONDS).toJavaDuration(), ) advanceUntilIdle() @@ -202,8 +204,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.HORIZONTAL, - PlaneSemanticType.CEILING, + setOf(PlaneOrientation.HORIZONTAL), + setOf(PlaneSemanticType.CEILING), timeout = 0.toDuration(DurationUnit.SECONDS).toJavaDuration(), ) advanceUntilIdle() @@ -246,8 +248,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.HORIZONTAL, - PlaneSemanticType.CEILING, + setOf(PlaneOrientation.HORIZONTAL), + setOf(PlaneSemanticType.CEILING), timeout = 5.seconds.toJavaDuration(), ) advanceUntilIdle() @@ -275,8 +277,8 @@ class AnchorEntityTest { AnchorEntity.create( session, FloatSize2d(1.0f, 1.0f), - PlaneOrientation.HORIZONTAL, - PlaneSemanticType.CEILING, + setOf(PlaneOrientation.HORIZONTAL), + setOf(PlaneSemanticType.CEILING), timeout = 0.toDuration(DurationUnit.SECONDS).toJavaDuration(), ) advanceUntilIdle() diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorPlacementTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorPlacementTest.kt index 9adf5714bab41..834a7de59e0db 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorPlacementTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorPlacementTest.kt @@ -101,7 +101,7 @@ class AnchorPlacementTest { @Test fun anchorPlacementAddingToSemanticTypesAfterCreation_doesNotUpdateAnchorPlacement() { - val anchorSemanticSet: MutableSet = + val anchorSemanticSet: MutableSet = mutableSetOf(PlaneSemanticType.CEILING, PlaneSemanticType.FLOOR) val anchorPlacement = AnchorPlacement.createForPlanes(anchorablePlaneSemanticTypes = anchorSemanticSet) @@ -115,7 +115,8 @@ class AnchorPlacementTest { @Test fun anchorPlacementAddingToOrientationsAfterCreation_doesNotUpdateAnchorPlacement() { - val anchorOrientationSet: MutableSet = mutableSetOf(PlaneOrientation.VERTICAL) + val anchorOrientationSet: MutableSet = + mutableSetOf(PlaneOrientation.VERTICAL) val anchorPlacement = AnchorPlacement.createForPlanes(anchorablePlaneOrientations = anchorOrientationSet) @@ -139,7 +140,7 @@ class AnchorPlacementTest { assertThat(anchorPlacementString) .isEqualTo( - "AnchorPlacement(anchorablePlaneOrientations=[1], anchorablePlaneSemanticTypes=[2, 3])" + "AnchorPlacement(anchorablePlaneOrientations=[2], anchorablePlaneSemanticTypes=[3, 4])" ) } diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/BoundsComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/BoundsComponentTest.kt index d249656936515..c7a86aa3daa93 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/BoundsComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/BoundsComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.os.Build @@ -120,8 +122,8 @@ class BoundsComponentTest { AnchorEntity.create( session, FloatSize2d(), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, 10.seconds.toJavaDuration(), ) val activityPanelEntity = diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityRegistryTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityRegistryTest.kt index 45233ace73163..539457a6dc0ae 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityRegistryTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityRegistryTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.os.Build @@ -218,8 +220,8 @@ class EntityRegistryTest { session, entityRegistry, FloatSize2d(), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, 10.seconds.toJavaDuration(), ) } diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityTest.kt index 96bb42f3627c7..a7720d8e6ec3f 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/EntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.content.Intent @@ -163,8 +165,8 @@ class EntityTest { AnchorEntity.create( session, FloatSize2d(), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, 10.seconds.toJavaDuration(), ) activityPanelEntity = @@ -328,7 +330,7 @@ class EntityTest { @Test fun anchorEntityCreateWithNullTimeout_passesNullToImpl() { anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) assertThat(anchorEntity).isNotNull() } @@ -338,7 +340,7 @@ class EntityTest { session.configure(Config(planeTracking = PlaneTrackingMode.DISABLED)) assertFailsWith { - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) } } diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ExrImageTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ExrImageTest.kt index 033bb5b638020..8eef78f426088 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ExrImageTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ExrImageTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/GltfModelTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/GltfModelTest.kt index dfd52df9abb4f..caa1287716bee 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/GltfModelTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/GltfModelTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/InteractableComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/InteractableComponentTest.kt index 5655ca34c47e4..e075e3514a442 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/InteractableComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/InteractableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.widget.TextView diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MainPanelEntityTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MainPanelEntityTest.kt index 49fa07fe708ac..6f36c6d766e40 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MainPanelEntityTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MainPanelEntityTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MovableComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MovableComponentTest.kt index 7e0e8226aa381..3afd2fda5bd27 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MovableComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MovableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.os.SystemClock @@ -309,7 +311,7 @@ class MovableComponentTest { fun addMovableComponentToAnchorEntity_returnsFalse() { createCustomSession() val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) assertThat(anchorEntity).isNotNull() val movableComponent = MovableComponent.createSystemMovable(session) diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PointerCaptureComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PointerCaptureComponentTest.kt index e395e10574b72..0cc1153b0c798 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PointerCaptureComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PointerCaptureComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PositionalAudioComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PositionalAudioComponentTest.kt index bce50d82aeba5..153a2cfd328ba 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PositionalAudioComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/PositionalAudioComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ResizableComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ResizableComponentTest.kt index 4b99d34521e75..2f188634cd15d 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ResizableComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ResizableComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.widget.TextView diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ScenePoseTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ScenePoseTest.kt index ff635c17da8fe..971751c7f8b79 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ScenePoseTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/ScenePoseTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.app.Activity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SceneTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SceneTest.kt index dea3ceef18de9..23ce16ccb1509 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SceneTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SceneTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.os.Looper @@ -142,7 +144,7 @@ class SceneTest { parent = session.scene.activitySpace, ) val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) assertThat(session.scene.getEntitiesOfType(Entity::class.java)) .containsAtLeast(panelEntity, anchorEntity) @@ -412,7 +414,7 @@ class SceneTest { @Test fun keyEntity_setWithAnchorEntity_throwsIllegalArgumentException() { val anchorEntity = - AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ANY, PlaneSemanticType.ANY) + AnchorEntity.create(session, FloatSize2d(), PlaneOrientation.ALL, PlaneSemanticType.ALL) val exception = assertFailsWith { session.scene.keyEntity = anchorEntity } diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolComponentTest.kt index 0d4dc32a9093e..876325e8947af 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolTest.kt index 8128b5aad116d..491769a3bf067 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundEffectPoolTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.content.res.AssetFileDescriptor diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundFieldAudioComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundFieldAudioComponentTest.kt index 64c6c45a07421..bf73969bdf195 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundFieldAudioComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SoundFieldAudioComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.activity.ComponentActivity diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialAudioTrackTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialAudioTrackTest.kt index 7b5ac645163ce..e3817b6020b0f 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialAudioTrackTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialAudioTrackTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.media.AudioTrack diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialEnvironmentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialEnvironmentTest.kt index b43a86c952fd3..5a15e3db3e1ed 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialEnvironmentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialEnvironmentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.annotation.SuppressLint diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialMediaPlayerTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialMediaPlayerTest.kt index d3567360880ef..e5a801e522742 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialMediaPlayerTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialMediaPlayerTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.media.MediaPlayer diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialPointerComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialPointerComponentTest.kt index 262361c63b467..aa48f7e130594 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialPointerComponentTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SpatialPointerComponentTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import android.widget.TextView diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/UtilsTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/UtilsTest.kt index 2a6eea519fafe..a59a88a9a8f5e 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/UtilsTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/UtilsTest.kt @@ -535,13 +535,13 @@ class UtilsTest { whenever( mockRuntime.createAnchorPlacementForPlanes( setOf(RtPlaneType.HORIZONTAL), - setOf(RtPlaneSemantic.ANY), + RtPlaneSemantic.entries.toSet(), ) ) .thenReturn(mockAnchorPlacement1) whenever( mockRuntime.createAnchorPlacementForPlanes( - setOf(RtPlaneType.ANY), + RtPlaneType.entries.toSet(), setOf(RtPlaneSemantic.WALL, RtPlaneSemantic.FLOOR), ) ) diff --git a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/XrExtensionsHolderAccessorTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/XrExtensionsHolderAccessorTest.kt index 35c930e16889d..8d35c33cc1e56 100644 --- a/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/XrExtensionsHolderAccessorTest.kt +++ b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/XrExtensionsHolderAccessorTest.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION") + package androidx.xr.scenecore import androidx.xr.runtime.TypeHolder