From a15dce734d265bf571e8057ea78daaa8d5ac759a Mon Sep 17 00:00:00 2001 From: Marc Richards Date: Thu, 9 Apr 2026 11:12:39 -0400 Subject: [PATCH 01/12] Cleanup some remaining SceneCore RestrictTo usages Added clarifying comments to remaining LIBRARY_GROUP_PREFIX usages, and cleaned up a few missed in aosp/4017626 Bug: 452961674 Test: Unit tests are sufficient Change-Id: Ief9818559a6599fab8cff326151ce392e9a9d31e --- .../api/restricted_current.txt | 29 ------------------- .../scenecore/runtime/GltfAnimationFeature.kt | 2 -- .../xr/scenecore/runtime/SoundEffectPool.kt | 10 +++---- .../extensions/XrExtensionsProvider.kt | 2 +- 4 files changed, 6 insertions(+), 37 deletions(-) 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/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" From ed3949224e2cf8a262e3d8e0c7516e48d1b8a585 Mon Sep 17 00:00:00 2001 From: Marc Richards Date: Tue, 7 Apr 2026 12:22:30 -0400 Subject: [PATCH 02/12] Update SceneCore's PlaneOrientation & PlaneSemanticType Both classes have been migrated from IntDef to custom types. Both `ANY` constants have been deprecated & restricted: Usages of `ANY` can be replaced with new `ALL` constant that is a proper Set containing all the orientation / semantic type constants. The AnchorEntity factory method has been updated to accept a `Set` rather than a specific constant. The previous version of the factory is now deprecated and will be removed in a later CL. Changing from Ints to the custom types does not cause 1P breakages. The other potentially breaking API changes for 1Ps have been mitigated by using deprecation and RestrictTo, which will be cleaned up in b/500464864. This change is fairly extensive because the use of `ANY` was piped through the runtime levels, rather than being represented as a Set throughout. Test: Manually validated the CUJs for each touched Activity in the test apps. Bug: 421161788 RelNote: "SceneCore's `PlaneSemanticType` `PlaneOrientation` constants have been migrated from Ints to custom types. Their `ANY` constants will be removed, clients should explicitly enumerate all desired constants instead, or use the new `.ALL` immutable Set constants. The `AnchorEntity` factory method now accepts a Set of these types, instead of a single value." Change-Id: Ib10339399d6255907dad0ed135c20f245c967c48 --- xr/compose/compose/api/current.txt | 24 ++--- xr/compose/compose/api/restricted_current.txt | 24 ++--- .../xr/compose/subspace/layout/Anchorable.kt | 35 +++--- .../xr/compose/spatial/SubspaceTest.kt | 6 +- .../anchorentity/AnchorEntityActivity.kt | 4 +- .../testapp/movable/MovableActivity.kt | 7 +- .../transformation/TransformationActivity.kt | 4 +- .../xr/scenecore/runtime/PlaneSemantic.kt | 1 - .../xr/scenecore/runtime/PlaneType.kt | 1 - .../spatial/core/SpatialSceneRuntimeTest.kt | 5 +- .../scenecore/testing/FakeAnchorPlacement.kt | 4 +- xr/scenecore/scenecore/api/current.txt | 68 ++++++------ .../scenecore/api/restricted_current.txt | 68 ++++++------ .../androidx/xr/scenecore/AnchorEntity.kt | 74 ++++++++++--- .../androidx/xr/scenecore/AnchorPlacement.kt | 26 +++-- .../androidx/xr/scenecore/MovableComponent.kt | 10 +- .../main/java/androidx/xr/scenecore/Types.kt | 101 ++++++++++++------ .../main/java/androidx/xr/scenecore/Utils.kt | 15 ++- .../androidx/xr/scenecore/AnchorEntityTest.kt | 24 ++--- .../xr/scenecore/AnchorPlacementTest.kt | 7 +- .../xr/scenecore/BoundsComponentTest.kt | 4 +- .../xr/scenecore/EntityRegistryTest.kt | 4 +- .../java/androidx/xr/scenecore/EntityTest.kt | 8 +- .../xr/scenecore/MovableComponentTest.kt | 2 +- .../java/androidx/xr/scenecore/SceneTest.kt | 4 +- .../java/androidx/xr/scenecore/UtilsTest.kt | 4 +- 26 files changed, 313 insertions(+), 221 deletions(-) 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/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..40fdb2c275420 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 @@ -1838,7 +1838,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 +1859,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 +1883,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/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 159be475d8684..49c39a347775a 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/movable/MovableActivity.kt b/xr/scenecore/integration-tests/testapp/src/main/kotlin/androidx/xr/scenecore/testapp/movable/MovableActivity.kt index 219fd21654b50..b8652373d2894 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" @@ -233,6 +233,7 @@ class MovableActivity : AppCompatActivity() { movablePanelContentView.findViewById(R.id.custom_behavior_group) } + @Suppress("RestrictedApiAndroidX", "DEPRECATION") private fun setupAnchorPlacementCheckboxes(view: View, movablePanelEntity: Entity) { val planeOrientationCheckboxMap = mapOf( @@ -337,7 +338,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 3a2b7560a81b4..e0ecf4926903c 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/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-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..ddb83a9e4534e 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 @@ -76,7 +76,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 +984,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-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..f69be2b9623cd 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 @@ -39,7 +39,7 @@ import androidx.xr.scenecore.runtime.PlaneType @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/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/AnchorEntityTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/AnchorEntityTest.kt index 27addc03b2793..e09a6a20f7d83 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 @@ -125,8 +125,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 +147,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 +173,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 +202,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 +246,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 +275,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..4c7252fc63a6b 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 @@ -120,8 +120,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..e058e2be6cacb 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 @@ -218,8 +218,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..546314aa8f7cf 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 @@ -163,8 +163,8 @@ class EntityTest { AnchorEntity.create( session, FloatSize2d(), - PlaneOrientation.ANY, - PlaneSemanticType.ANY, + PlaneOrientation.ALL, + PlaneSemanticType.ALL, 10.seconds.toJavaDuration(), ) activityPanelEntity = @@ -328,7 +328,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 +338,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/MovableComponentTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/MovableComponentTest.kt index 7e0e8226aa381..46613009699d2 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 @@ -309,7 +309,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/SceneTest.kt b/xr/scenecore/scenecore/src/test/java/androidx/xr/scenecore/SceneTest.kt index dea3ceef18de9..52bf3930a10d7 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 @@ -142,7 +142,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 +412,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/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), ) ) From a627c969e32ec49210fde65126734983bbec05e6 Mon Sep 17 00:00:00 2001 From: Tim Wong Date: Thu, 9 Apr 2026 16:43:26 +0800 Subject: [PATCH 03/12] Fix Animation State text display in GltfModelAnimationActivity The text of the Animation State in the GLTF Model Animation test case was not displaying normally when using `toString()`. To fix this, explicitly map `GltfAnimation.AnimationState` values to "PLAYING", "STOPPED", and "PAUSED" strings instead of relying on `toString()`. Bug: 500965079 Test: GltfModelAnimationActivity integration test on the emulator Change-Id: I4f270266c10b4808c13a9d80875129340d2e9313 --- .../model/GltfModelAnimationActivity.kt | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) 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 } From 48b62e64a73879313833fa78cb7a420b73888b8b Mon Sep 17 00:00:00 2001 From: Lucas Muller Oliveira Date: Fri, 10 Apr 2026 10:49:07 -0700 Subject: [PATCH 04/12] Bump version for Glance Wear for upcoming release. Change-Id: I6ea768ca7370d6e8dcaa90e9be20e4e55ef6e80b --- libraryversions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraryversions.toml b/libraryversions.toml index 934e865edcdd7..7cf6a1b2b38b1 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" From 52c4d1aac50d996f569bb0a44695a738a9fb85f9 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Mon, 6 Apr 2026 10:29:28 -0700 Subject: [PATCH 05/12] Upgrade to AGP 9.2.0-alpha07 Test: None Change-Id: I502d4a418e4c7c0c4c02ca6552d59263d4f874d2 --- buildSrc-tests/lint-baseline.xml | 26 +- camera/camera-camera2-pipe/lint-baseline.xml | 20 +- camera/camera-testing/lint-baseline.xml | 11 +- car/app/app-automotive/lint-baseline.xml | 272 +--- .../showcase/automotive/lint-baseline.xml | 13 + car/app/app/lint-baseline.xml | 29 +- .../macrobenchmark-target/lint-baseline.xml | 13 + .../animation-graphics/lint-baseline.xml | 2 +- .../lint-baseline.xml | 20 +- compose/material/material/lint-baseline.xml | 2 +- .../adaptive-layout/lint-baseline.xml | 2 +- .../adaptive/adaptive/lint-baseline.xml | 2 +- .../adaptive/samples/lint-baseline.xml | 20 +- .../macrobenchmark-target/lint-baseline.xml | 13 + compose/material3/material3/lint-baseline.xml | 2 +- .../material3/samples/lint-baseline.xml | 11 +- .../player-view-demos/lint-baseline.xml | 98 +- compose/test-utils/lint-baseline.xml | 2 +- .../samples/lint-baseline.xml | 20 +- compose/ui/ui-test/lint-baseline.xml | 29 +- .../ui/ui-text-google-fonts/lint-baseline.xml | 13 - compose/ui/ui-text/lint-baseline.xml | 11 +- compose/ui/ui-tooling-data/lint-baseline.xml | 58 - .../samples/lint-baseline.xml | 22 + .../ui/ui-viewbinding/samples/build.gradle | 2 +- .../ui-viewbinding/samples/lint-baseline.xml | 31 - compose/ui/ui/lint-baseline.xml | 20 +- compose/ui/ui/samples/lint-baseline.xml | 29 +- .../lint-baseline.xml | 2 +- core/core/lint-baseline.xml | 956 +------------ core/core/samples/lint-baseline.xml | 11 +- .../lint-baseline.xml | 47 +- credentials/credentials/lint-baseline.xml | 11 +- development/update_studio.sh | 4 +- .../integration-tests/demos/lint-baseline.xml | 119 +- glance/glance/lint-baseline.xml | 20 +- glance/wear/wear-samples/lint-baseline.xml | 533 +------ glance/wear/wear/lint-baseline.xml | 10 +- gradle/libs.versions.toml | 8 +- .../connect/connect-client/lint-baseline.xml | 20 +- .../connect-client/samples/lint-baseline.xml | 238 ++++ .../lint-baseline.xml | 2 +- mediarouter/mediarouter/lint-baseline.xml | 20 +- navigation3/navigation3-ui/lint-baseline.xml | 20 +- paging/paging-common/lint-baseline.xml | 26 +- pdf/pdf-viewer/lint-baseline.xml | 40 - samples/AndroidXDemos/build.gradle | 1 + samples/MediaRoutingDemo/build.gradle | 1 + security/security-state/lint-baseline.xml | 11 +- settings.gradle | 2 +- sqlite/sqlite-framework/lint-baseline.xml | 2 +- .../stableaidl-gradle-plugin/build.gradle | 2 +- .../test-app/lint-baseline.xml | 13 + .../samples/lint-baseline.xml | 11 +- .../samples/lint-baseline.xml | 20 +- .../samples/lint-baseline.xml | 13 + .../samples/lint-baseline.xml | 1264 +++++++++++++++++ wear/tiles/tiles/lint-baseline.xml | 10 +- .../tiles/snippet-samples/lint-baseline.xml | 652 +++++++++ .../lint-baseline.xml | 18 +- .../testapp/lint-baseline.xml | 11 +- xr/compose/compose/lint-baseline.xml | 59 +- xr/glimmer/glimmer/samples/lint-baseline.xml | 14 +- 63 files changed, 2422 insertions(+), 2562 deletions(-) create mode 100644 car/app/app-samples/showcase/automotive/lint-baseline.xml create mode 100644 compose/animation/animation-benchmark/integration-tests/macrobenchmark-target/lint-baseline.xml create mode 100644 compose/material3/integration-tests/macrobenchmark-target/lint-baseline.xml delete mode 100644 compose/ui/ui-text-google-fonts/lint-baseline.xml delete mode 100644 compose/ui/ui-tooling-data/lint-baseline.xml create mode 100644 compose/ui/ui-tooling-preview/samples/lint-baseline.xml delete mode 100644 compose/ui/ui-viewbinding/samples/lint-baseline.xml create mode 100644 health/connect/connect-client/samples/lint-baseline.xml delete mode 100644 pdf/pdf-viewer/lint-baseline.xml create mode 100644 startup/integration-tests/test-app/lint-baseline.xml create mode 100644 wear/compose/compose-navigation3/samples/lint-baseline.xml create mode 100644 wear/compose/remote/remote-material3/samples/lint-baseline.xml create mode 100644 wear/tiles/tiles/snippet-samples/lint-baseline.xml 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 @@ - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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/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/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 fe530c455a700..894d62478d6ac 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/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 @@ - + + + + + - - - - - + @@ -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/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=" ~~~"> From b4b333ec25bd53db2b5584127bef63de826409ca Mon Sep 17 00:00:00 2001 From: Dima Trubnikov Date: Fri, 10 Apr 2026 19:28:35 +0100 Subject: [PATCH 06/12] Fix Icon caching bug by invalidating draw cache when painter is changed The icon's tint modifier caches the graphics layer, so even if the painter changes, the icon remains the same. Fix: 501465498 Test: IconTest#painter_updatesWhenPainterChanges Change-Id: If98ec57ffd96a4385b273dee75a57a4b38ebd6d2 --- .../kotlin/androidx/xr/glimmer/IconTest.kt | 53 +++++++++++++++++++ .../src/main/java/androidx/xr/glimmer/Icon.kt | 26 ++++++--- 2 files changed, 73 insertions(+), 6 deletions(-) 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() + } } } } From a19ee43f9a9453e53af0694dbfd9e20bba736613 Mon Sep 17 00:00:00 2001 From: Ben Sawyer Date: Fri, 6 Feb 2026 12:33:25 -0500 Subject: [PATCH 07/12] Add ArCoreTestRule and suite of Test classes The ArCoreTestRule API is a new construct for mocking the "real-world" environment during a unit test. It consists of a collection of TestTrackables which the tester can add, such as planes, that will then be detected by the FakePerceptionRuntime. It also has dedicated mocks for user body parts like hands and eyes, as well as mocks for device-based singletons such as viewpoints, depth maps, and VPS. Going forward, ARCore unit tests should avoid creating and/or interacting with the Fake* classes directly. They should instead employ the ArCoreTestRule as a kind of emulator with which to test the public-facing API surfaces with real patterns a developer would actually use. See go/jxr-arcore-unit-testing-strategy Bug: 479574533 RelNote: Added ArCoreTestRule API, including TestArDevice, TestAugmentableObject, TestDepthMap, TestEye, TestFace, TestGeospatial, TestHand, TestPlane, TestRenderViewpoint, & TestTrackable Change-Id: I0ad3c7a75510b0078696558fa2e275785c0f3cc5 --- xr/arcore/arcore-testing/api/current.txt | 197 +++++++++++ .../arcore-testing/api/restricted_current.txt | 197 +++++++++++ xr/arcore/arcore-testing/build.gradle | 4 +- .../xr/arcore/testing/ArCoreTestRule.kt | 330 ++++++++++++++++++ .../xr/arcore/testing/FakeRuntimePlane.kt | 3 +- .../xr/arcore/testing/TestArDevice.kt | 66 ++++ .../xr/arcore/testing/TestAugmentedObject.kt | 82 +++++ .../androidx/xr/arcore/testing/TestDepth.kt | 101 ++++++ .../androidx/xr/arcore/testing/TestEye.kt | 66 ++++ .../androidx/xr/arcore/testing/TestFace.kt | 178 ++++++++++ .../xr/arcore/testing/TestGeospatial.kt | 172 +++++++++ .../androidx/xr/arcore/testing/TestHand.kt | 86 +++++ .../androidx/xr/arcore/testing/TestPlane.kt | 145 ++++++++ .../xr/arcore/testing/TestRenderViewpoint.kt | 56 +++ .../xr/arcore/testing/TestTrackable.kt | 32 ++ .../testing/internal/FakeLifecycleManager.kt | 18 +- .../testing/internal/FakePerceptionManager.kt | 21 +- .../internal/FakePerceptionRuntimeFactory.kt | 5 + .../testing/internal/FakeRuntimeAnchor.kt | 1 + .../testing/internal/FakeRuntimeFace.kt | 26 +- .../testing/internal/FakeRuntimeGeospatial.kt | 17 +- .../testing/internal/FakeRuntimeHand.kt | 10 +- .../testing/internal/FakeRuntimePlane.kt | 32 +- .../xr/arcore/testing/ArCoreTestRuleTest.kt | 82 +++++ .../internal/FakeLifecycleManagerTest.kt | 5 +- .../internal/FakeRuntimeGeospatialTest.kt | 27 +- 26 files changed, 1872 insertions(+), 87 deletions(-) create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/ArCoreTestRule.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestArDevice.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestAugmentedObject.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestDepth.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestEye.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestFace.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestGeospatial.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestHand.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestPlane.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestRenderViewpoint.kt create mode 100644 xr/arcore/arcore-testing/src/main/kotlin/androidx/xr/arcore/testing/TestTrackable.kt create mode 100644 xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/ArCoreTestRuleTest.kt 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() - } } From 72f9e1ef76df9f6ecc959562455ea40eb1d84513 Mon Sep 17 00:00:00 2001 From: Jasmine Chen Date: Wed, 8 Apr 2026 18:42:35 -0700 Subject: [PATCH 08/12] Use MAX_PIPELINE_DEPTH for calculating ImageReader capacity margins This CL ports the logic and calculation from FrameServer that calculates the capacity set on ImageReaders. In FrameServer, the upper bound for ImageReader capacity ("maxImages") is determined by 64 - MAX_PIPELINE_DEPTH. This is currently hardcoded in CameraPipe with 54 (64 - 10). Bug: 476508341 Test: CameraPipe test app Change-Id: Ic0b1b768494940d115e2f1c097563d9325ad2b5c --- .../pipe/config/CameraGraphComponent.kt | 15 ++++++ .../pipe/config/CameraPipeComponent.kt | 13 ----- .../camera2/pipe/media/AndroidImageReaders.kt | 23 -------- .../camera2/pipe/media/AndroidImageWriter.kt | 6 --- .../pipe/media/ImageReaderImageSource.kt | 53 +++++++++++++------ 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraGraphComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraGraphComponent.kt index cd4ac35827a8a..8ee2a3253dd3b 100644 --- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraGraphComponent.kt +++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraGraphComponent.kt @@ -25,6 +25,7 @@ import androidx.camera.camera2.pipe.CameraController import androidx.camera.camera2.pipe.CameraGraph import androidx.camera.camera2.pipe.CameraGraphId import androidx.camera.camera2.pipe.CameraMetadata +import androidx.camera.camera2.pipe.CameraPipe import androidx.camera.camera2.pipe.CameraSurfaceManager import androidx.camera.camera2.pipe.Parameters import androidx.camera.camera2.pipe.Request @@ -46,6 +47,8 @@ import androidx.camera.camera2.pipe.internal.CameraGraphRequestListenersImpl import androidx.camera.camera2.pipe.internal.FrameCaptureQueue import androidx.camera.camera2.pipe.internal.FrameDistributor import androidx.camera.camera2.pipe.internal.GraphSessionLock +import androidx.camera.camera2.pipe.media.ImageReaderImageSources +import androidx.camera.camera2.pipe.media.ImageSources import dagger.Binds import dagger.Module import dagger.Provides @@ -202,6 +205,18 @@ internal abstract class SharedCameraGraphModules { } @CameraGraphScope @Provides fun provideSystemClockOffsets() = SystemClockOffsets.estimate() + + @CameraGraphScope + @Provides + fun configureImageSources( + imageReaderImageSources: ImageReaderImageSources, + cameraPipeConfig: CameraPipe.Config, + ): ImageSources { + if (cameraPipeConfig.imageSources != null) { + return cameraPipeConfig.imageSources + } + return imageReaderImageSources + } } } diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt index 7ff8652eb29c9..4f5e5cc855a48 100644 --- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt +++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt @@ -41,8 +41,6 @@ import androidx.camera.camera2.pipe.core.TimeSource import androidx.camera.camera2.pipe.internal.CameraBackendsImpl import androidx.camera.camera2.pipe.internal.CameraDevicesImpl import androidx.camera.camera2.pipe.internal.CameraPipeLifetime -import androidx.camera.camera2.pipe.media.ImageReaderImageSources -import androidx.camera.camera2.pipe.media.ImageSources import androidx.camera.featurecombinationquery.CameraDeviceSetupCompatFactory import dagger.Binds import dagger.Component @@ -188,17 +186,6 @@ internal abstract class CameraPipeModule { ) } - @Provides - fun configureImageSources( - imageReaderImageSources: ImageReaderImageSources, - cameraPipeConfig: CameraPipe.Config, - ): ImageSources { - if (cameraPipeConfig.imageSources != null) { - return cameraPipeConfig.imageSources - } - return imageReaderImageSources - } - @Singleton @Provides fun provideCameraSurfaceManager() = CameraSurfaceManager() @Singleton diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageReaders.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageReaders.kt index 14ddc53417b3a..53e058b710575 100644 --- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageReaders.kt +++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/media/AndroidImageReaders.kt @@ -106,18 +106,6 @@ private constructor( } public companion object { - // 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). - // - // One of the worst cases observed is the HAL reserving 10 images, which gives a maximum - // capacity of 54 (64 - 10). For safety and compatibility reasons, set the maximum capacity - // to be 54, which leaves headroom for an app configured limit of 50. - internal const val IMAGEREADER_MAX_CAPACITY = 54 - /** * Create and configure a new ImageReader instance as an [ImageReaderWrapper]. * @@ -138,11 +126,6 @@ private constructor( require(width > 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 From 8f2be204bac986e3f8eed92497176e93dbbb2453 Mon Sep 17 00:00:00 2001 From: Anastasia Soboleva Date: Fri, 10 Apr 2026 14:17:30 -0700 Subject: [PATCH 09/12] Revert "Use layout bounds for accessibility sibling occlusion subtraction" This reverts commit 4c5d98cd7a7f41f2e6c068b46b3a1b25027ef0bd. Reason for revert: G3 drop blocked as this change caused some https://support.google.com/accessibility/android/answer/6378943 failures Change-Id: Ib6793c92163cf8ea347a2d37b09ab77529c55cfd --- .../java/androidx/compose/ui/demos/UiDemos.kt | 2 - .../AccessibilitySiblingBoundsDemo.kt | 66 ------------------ .../compose/ui/AndroidAccessibilityTest.kt | 69 ------------------- .../compose/ui/semantics/SemanticsOwner.kt | 20 +----- 4 files changed, 3 insertions(+), 154 deletions(-) delete mode 100644 compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/accessibility/AccessibilitySiblingBoundsDemo.kt 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/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) { From f8e163f60001eef0d13327df00287f4a860f5935 Mon Sep 17 00:00:00 2001 From: Ben Sawyer Date: Mon, 9 Feb 2026 16:48:44 -0500 Subject: [PATCH 10/12] Update PlaneTest.kt to use ArCoreTestRule Includes necessary updates to relevant Fakes to support new test workflow Bug: 483110585 Change-Id: I08a253959245b227f6f88446ee3736fb851f2e4a --- .../testing/internal/FakeRuntimePlaneTest.kt | 63 +++ .../kotlin/androidx/xr/arcore/PlaneTest.kt | 426 ++++++++++-------- 2 files changed, 307 insertions(+), 182 deletions(-) create mode 100644 xr/arcore/arcore-testing/src/test/kotlin/androidx/xr/arcore/testing/internal/FakeRuntimePlaneTest.kt 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) + } } From f8a0537ab206909e78910dad8f5a2e2506cf70be Mon Sep 17 00:00:00 2001 From: Cary Haynie Date: Fri, 20 Mar 2026 21:21:44 +0000 Subject: [PATCH 11/12] [3/7] Lifecycle Manager Removal - Play Services Runtime Bug: 465834229 Change-Id: I01b598f01b23f85bd4be938b00400a8667192673 --- .../xr/arcore/playservices/ArCoreManager.kt | 183 +------ .../xr/arcore/playservices/ArCoreRuntime.kt | 193 +++++++- .../playservices/ArCoreRuntimeFactory.kt | 3 +- .../arcore/playservices/ArCoreManagerTest.kt | 452 ----------------- .../arcore/playservices/ArCoreRuntimeTest.kt | 457 +++++++++++++++++- .../playservices/CameraStateExtenderTest.kt | 11 +- 6 files changed, 642 insertions(+), 657 deletions(-) delete mode 100644 xr/arcore/arcore-play-services/src/test/kotlin/androidx/xr/arcore/playservices/ArCoreManagerTest.kt diff --git a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreManager.kt b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreManager.kt index 5be0d0a030960..b0e8edb02e0f4 100644 --- a/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreManager.kt +++ b/xr/arcore/arcore-play-services/src/main/kotlin/androidx/xr/arcore/playservices/ArCoreManager.kt @@ -16,57 +16,23 @@ package androidx.xr.arcore.playservices -import android.content.Context -import android.os.Build -import androidx.annotation.RequiresApi import androidx.annotation.RestrictTo -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.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.LifecycleManager -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.AugmentedFaceMode -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.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 // TODO: b/396240241 -- Appropriately handle or translate any exceptions thrown by Android 1.x /** * Manages the lifecycle of an ARCore session. * - * @property context The [Context] instance - * @property perceptionManager the [ArCorePerceptionManager] instance * @property timeSource the [ArCoreTimeSource] instance * @property config the current [Config] of the session */ @Suppress("NotCloseable") @RestrictTo(RestrictTo.Scope.LIBRARY) -public class ArCoreManager -internal constructor( - internal val context: Context, - internal val perceptionManager: ArCorePerceptionManager, - internal val timeSource: ArCoreTimeSource, - private val arCoreApkInstance: ArCoreApk = ArCoreApk.getInstance(), -) : LifecycleManager { +public class ArCoreManager internal constructor(internal val timeSource: ArCoreTimeSource) : + LifecycleManager { internal lateinit var _session: Session @@ -84,160 +50,23 @@ internal constructor( * This method must be called before any operations can be performed by the * [ArCorePerceptionManager]. */ - override fun create() { - checkARCoreSupportedAndUpToDate(context) - _session = Session(context) - perceptionManager.session = _session - perceptionManager.geospatial.arCoreSession = _session - } + override fun create() {} // TODO(b/392660855): Disable all features by default once this API is fully implemented. override var config: Config = Config() private set override fun configure(config: 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 == 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) From d8c58d3cc1fb243f77d19e565bede780dd169f02 Mon Sep 17 00:00:00 2001 From: babelsw Date: Fri, 10 Apr 2026 01:31:00 +0000 Subject: [PATCH 12/12] Migrate scenecore-testing Fakes to internal folders - deprecates old fakes Refer to ARCore: aosp/3946721 Deprecates current scenecore.testing fakes, will remove them after migrated to G3. Bug: 483229952 Test: Unit tests. Change-Id: I338d164479263e406b0320013787d0227dcd8277 --- .../xr/compose/spatial/SubspaceTest.kt | 2 + .../compose/subspace/SpatialGltfModelTest.kt | 2 + .../subspace/layout/AnchorableModifierTest.kt | 2 + .../subspace/layout/MovableModifierTest.kt | 2 + .../compose/testing/ConfigureFakeSession.kt | 2 + .../runtime/impl/OpenXrScenePoseTest.kt | 2 + .../spatial/core/ActivitySpaceImplTest.kt | 23 +++++++--- .../spatial/core/AnchorEntityImplTest.kt | 44 +++++++++---------- .../spatial/core/MeshEntityImplTest.kt | 3 ++ .../spatial/core/MovableComponentImplTest.kt | 3 ++ .../spatial/core/OpenXrScenePoseTest.kt | 15 ++++--- .../spatial/core/PanelEntityImplTest.kt | 9 ++-- .../core/PerceivedResolutionUtilsTest.kt | 27 ++++++++---- .../core/PositionalAudioComponentImplTest.kt | 2 + .../core/ResizableComponentImplTest.kt | 3 ++ .../spatial/core/SceneNodeRegistryTest.kt | 27 +++++------- .../spatial/core/SoundEffectPoolImplTest.kt | 2 + .../spatial/core/SpatialSceneRuntimeTest.kt | 3 ++ .../spatial/core/SurfaceEntityImplTest.kt | 3 ++ .../rendering/SpatialRenderingRuntimeTest.kt | 11 +++-- .../testing/FakeActivityPanelEntity.kt | 3 ++ .../xr/scenecore/testing/FakeActivitySpace.kt | 3 ++ .../xr/scenecore/testing/FakeAnchorEntity.kt | 3 ++ .../scenecore/testing/FakeAnchorPlacement.kt | 3 ++ .../FakeAudioTrackExtensionsWrapper.kt | 3 ++ .../testing/FakeBaseRenderingFeature.kt | 3 ++ .../scenecore/testing/FakeBoundsComponent.kt | 3 +- .../xr/scenecore/testing/FakeComponent.kt | 3 ++ .../xr/scenecore/testing/FakeEntity.kt | 3 ++ .../scenecore/testing/FakeExrImageResource.kt | 3 ++ .../testing/FakeGltfAnimationFeature.kt | 3 ++ .../xr/scenecore/testing/FakeGltfEntity.kt | 3 ++ .../xr/scenecore/testing/FakeGltfFeature.kt | 3 ++ .../testing/FakeGltfModelNodeFeature.kt | 3 ++ .../testing/FakeGltfModelResource.kt | 15 ++++--- .../testing/FakeInteractableComponent.kt | 3 ++ .../FakeMediaPlayerExtensionsWrapper.kt | 3 ++ .../xr/scenecore/testing/FakeMeshEntity.kt | 3 ++ .../xr/scenecore/testing/FakeMeshFeature.kt | 3 ++ .../scenecore/testing/FakeMovableComponent.kt | 3 ++ .../androidx/xr/scenecore/testing/FakeNode.kt | 7 ++- .../xr/scenecore/testing/FakePanelEntity.kt | 3 ++ .../testing/FakePerceptionSpaceScenePose.kt | 3 ++ .../testing/FakePointerCaptureComponent.kt | 3 ++ .../testing/FakePositionalAudioComponent.kt | 3 ++ .../scenecore/testing/FakeRenderingRuntime.kt | 13 ++++-- .../testing/FakeRenderingRuntimeFactory.kt | 3 ++ .../testing/FakeResizableComponent.kt | 4 ++ .../xr/scenecore/testing/FakeResource.kt | 3 ++ .../xr/scenecore/testing/FakeScenePose.kt | 3 ++ .../xr/scenecore/testing/FakeSceneRuntime.kt | 3 ++ .../testing/FakeSceneRuntimeFactory.kt | 3 ++ .../scenecore/testing/FakeSoundEffectPool.kt | 3 ++ .../testing/FakeSoundEffectPoolComponent.kt | 3 ++ .../testing/FakeSoundFieldAudioComponent.kt | 3 ++ .../testing/FakeSoundPoolExtensionsWrapper.kt | 3 ++ .../testing/FakeSpatialEnvironment.kt | 3 ++ .../testing/FakeSpatialEnvironmentFeature.kt | 3 ++ .../testing/FakeSpatialModeChangeListener.kt | 3 ++ .../testing/FakeSpatialPointerComponent.kt | 3 ++ .../testing/FakeSubspaceNodeEntity.kt | 3 ++ .../xr/scenecore/testing/FakeSurfaceEntity.kt | 3 ++ .../scenecore/testing/FakeSurfaceFeature.kt | 3 ++ .../testing/FakeSystemSpaceEntity.kt | 3 ++ .../testing/FakeXrExtensionsHolderProvider.kt | 3 ++ .../testing/FakeActivityPanelEntityTest.kt | 2 + .../testing/FakeActivitySpaceTest.kt | 2 + .../scenecore/testing/FakeAnchorEntityTest.kt | 2 + .../testing/FakeAnchorPlacementTest.kt | 2 + .../FakeAudioTrackExtensionsWrapperTest.kt | 2 + .../testing/FakeBoundsComponentTest.kt | 2 + .../xr/scenecore/testing/FakeComponentTest.kt | 2 + .../xr/scenecore/testing/FakeEntityTest.kt | 2 + .../testing/FakeGltfAnimationFeatureTest.kt | 2 + .../scenecore/testing/FakeGltfEntityTest.kt | 2 + .../testing/FakeGltfModelNodeFeatureTest.kt | 2 + .../testing/FakeInteractableComponentTest.kt | 2 + .../FakeMediaPlayerExtensionsWrapperTest.kt | 2 + .../testing/FakeMovableComponentTest.kt | 2 + .../scenecore/testing/FakePanelEntityTest.kt | 2 + .../FakePointerCaptureComponentTest.kt | 2 + .../FakeRenderingRuntimeFactoryTest.kt | 2 + .../testing/FakeRenderingRuntimeTest.kt | 2 + .../testing/FakeResizableComponentTest.kt | 2 + .../xr/scenecore/testing/FakeScenePoseTest.kt | 2 + .../testing/FakeSceneRuntimeFactoryTest.kt | 2 + .../scenecore/testing/FakeSceneRuntimeTest.kt | 2 + .../FakeSoundPoolExtensionsWrapperTest.kt | 2 + .../testing/FakeSpatialEnvironmentTest.kt | 2 + .../FakeSpatialPointerComponentTest.kt | 2 + .../testing/FakeSubspaceNodeEntityTest.kt | 2 + .../testing/FakeSurfaceEntityTest.kt | 2 + .../testing/FakeSurfaceFeatureTest.kt | 2 + .../testing/FakeSystemSpaceEntityTest.kt | 2 + .../xr/scenecore/ActivitySpaceTest.kt | 2 + .../androidx/xr/scenecore/AnchorEntityTest.kt | 2 + .../xr/scenecore/BoundsComponentTest.kt | 2 + .../xr/scenecore/EntityRegistryTest.kt | 2 + .../java/androidx/xr/scenecore/EntityTest.kt | 2 + .../androidx/xr/scenecore/ExrImageTest.kt | 2 + .../androidx/xr/scenecore/GltfModelTest.kt | 2 + .../xr/scenecore/InteractableComponentTest.kt | 2 + .../xr/scenecore/MainPanelEntityTest.kt | 2 + .../xr/scenecore/MovableComponentTest.kt | 2 + .../scenecore/PointerCaptureComponentTest.kt | 2 + .../scenecore/PositionalAudioComponentTest.kt | 2 + .../xr/scenecore/ResizableComponentTest.kt | 2 + .../androidx/xr/scenecore/ScenePoseTest.kt | 2 + .../java/androidx/xr/scenecore/SceneTest.kt | 2 + .../scenecore/SoundEffectPoolComponentTest.kt | 2 + .../xr/scenecore/SoundEffectPoolTest.kt | 2 + .../scenecore/SoundFieldAudioComponentTest.kt | 2 + .../xr/scenecore/SpatialAudioTrackTest.kt | 2 + .../xr/scenecore/SpatialEnvironmentTest.kt | 2 + .../xr/scenecore/SpatialMediaPlayerTest.kt | 2 + .../scenecore/SpatialPointerComponentTest.kt | 2 + .../XrExtensionsHolderAccessorTest.kt | 2 + 117 files changed, 375 insertions(+), 78 deletions(-) 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 40fdb2c275420..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 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/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 ddb83a9e4534e..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 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 f69be2b9623cd..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,6 +38,7 @@ 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( 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/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 e09a6a20f7d83..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 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 4c7252fc63a6b..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 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 e058e2be6cacb..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 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 546314aa8f7cf..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 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 46613009699d2..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 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 52bf3930a10d7..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 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/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