1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.xr.scenecore
18 
19 import android.os.Handler
20 import android.os.Looper
21 import androidx.xr.runtime.internal.ActivityPose.HitTestFilter as RtHitTestFilter
22 import androidx.xr.runtime.internal.AnchorEntity as RtAnchorEntity
23 import androidx.xr.runtime.internal.AnchorPlacement as RtAnchorPlacement
24 import androidx.xr.runtime.internal.Dimensions as RtDimensions
25 import androidx.xr.runtime.internal.HitTestResult as RtHitTestResult
26 import androidx.xr.runtime.internal.HitTestResult.HitTestSurfaceType as RtHitTestSurfaceType
27 import androidx.xr.runtime.internal.InputEvent as RtInputEvent
28 import androidx.xr.runtime.internal.InputEvent.Companion.HitInfo as RtHitInfo
29 import androidx.xr.runtime.internal.JxrPlatformAdapter
30 import androidx.xr.runtime.internal.MoveEvent as RtMoveEvent
31 import androidx.xr.runtime.internal.PixelDimensions as RtPixelDimensions
32 import androidx.xr.runtime.internal.PlaneSemantic as RtPlaneSemantic
33 import androidx.xr.runtime.internal.PlaneType as RtPlaneType
34 import androidx.xr.runtime.internal.ResizeEvent as RtResizeEvent
35 import androidx.xr.runtime.internal.Space as RtSpace
36 import androidx.xr.runtime.internal.SpatialCapabilities as RtSpatialCapabilities
37 import androidx.xr.runtime.internal.SpatialVisibility as RtSpatialVisibility
38 import androidx.xr.runtime.internal.TextureSampler as RtTextureSampler
39 import androidx.xr.runtime.math.Ray
40 import androidx.xr.scenecore.ActivityPose.HitTestFilter
41 import androidx.xr.scenecore.HitTestResult.SurfaceType
42 import androidx.xr.scenecore.InputEvent.HitInfo
43 import java.util.concurrent.Executor
44 
45 internal class HandlerExecutor(val handler: Handler) : Executor {
executenull46     override fun execute(command: Runnable) {
47         handler.post(command)
48     }
49 
50     companion object {
51         val mainThreadExecutor: Executor = HandlerExecutor(Handler(Looper.getMainLooper()))
52     }
53 }
54 
55 /** Extension function that converts a [Dimensions] to [RtDimensions]. */
toRtDimensionsnull56 internal fun Dimensions.toRtDimensions(): RtDimensions {
57     return RtDimensions(width, height, depth)
58 }
59 
60 /** Extension function that converts a [RtDimensions] to [Dimensions]. */
toDimensionsnull61 internal fun RtDimensions.toDimensions(): Dimensions {
62     return Dimensions(width, height, depth)
63 }
64 
65 /** Extension function that converts a [PixelDimensions] to [RtPixelDimensions]. */
toRtPixelDimensionsnull66 internal fun PixelDimensions.toRtPixelDimensions(): RtPixelDimensions {
67     return RtPixelDimensions(width, height)
68 }
69 
70 /** Extension function that converts a [RtPixelDimensions] to [PixelDimensions]. */
toPixelDimensionsnull71 internal fun RtPixelDimensions.toPixelDimensions(): PixelDimensions {
72     return PixelDimensions(width, height)
73 }
74 
75 /** Extension function that converts [Int] to [JxrPlatformAdapter.PlaneType]. */
toRtPlaneTypenull76 internal fun Int.toRtPlaneType(): RtPlaneType {
77     return when (this) {
78         PlaneType.HORIZONTAL -> RtPlaneType.HORIZONTAL
79         PlaneType.VERTICAL -> RtPlaneType.VERTICAL
80         PlaneType.ANY -> RtPlaneType.ANY
81         else -> error("Unknown Plane Type: $PlaneType")
82     }
83 }
84 
85 /** Extension function that converts [Int] to [JxrPlatformAdapter.PlaneSemantic]. */
toRtPlaneSemanticnull86 internal fun Int.toRtPlaneSemantic(): RtPlaneSemantic {
87     return when (this) {
88         PlaneSemantic.WALL -> RtPlaneSemantic.WALL
89         PlaneSemantic.FLOOR -> RtPlaneSemantic.FLOOR
90         PlaneSemantic.CEILING -> RtPlaneSemantic.CEILING
91         PlaneSemantic.TABLE -> RtPlaneSemantic.TABLE
92         PlaneSemantic.ANY -> RtPlaneSemantic.ANY
93         else -> error("Unknown Plane Semantic: $PlaneSemantic")
94     }
95 }
96 
97 /** Extension function that converts [Space] value to [JxrPlatformAdapter.Space] value. */
toRtSpacenull98 internal fun Int.toRtSpace(): Int {
99     return when (this) {
100         Space.PARENT -> RtSpace.PARENT
101         Space.ACTIVITY -> RtSpace.ACTIVITY
102         Space.REAL_WORLD -> RtSpace.REAL_WORLD
103         else -> error("Unknown Space Value: $this")
104     }
105 }
106 
107 /** Extension function that converts a [RtMoveEvent] to a [MoveEvent]. */
toMoveEventnull108 internal fun RtMoveEvent.toMoveEvent(entityManager: EntityManager): MoveEvent {
109 
110     disposedEntity?.let { entityManager.removeEntity(it) }
111     return MoveEvent(
112         moveState.toMoveState(),
113         Ray(initialInputRay.origin, initialInputRay.direction),
114         Ray(currentInputRay.origin, currentInputRay.direction),
115         previousPose,
116         currentPose,
117         previousScale.x,
118         currentScale.x,
119         entityManager.getEntityForRtEntity(initialParent)!!,
120         updatedParent?.let {
121             entityManager.getEntityForRtEntity(it)
122                 ?: AnchorEntity.create(it as RtAnchorEntity, entityManager)
123         },
124     )
125 }
126 
127 /** Extension function that converts a [RtHitInfo] to a [HitInfo]. */
toHitInfonull128 internal fun RtHitInfo.toHitInfo(entityManager: EntityManager): HitInfo? {
129     // TODO: b/377541143 - Replace instance equality check in EntityManager.
130     val hitEntity = entityManager.getEntityForRtEntity(inputEntity)
131     return if (hitEntity == null) {
132         null
133     } else {
134         HitInfo(inputEntity = hitEntity, hitPosition = hitPosition, transform = transform)
135     }
136 }
137 
138 /** Extension function that converts a [RtInputEvent] to a [InputEvent]. */
toInputEventnull139 internal fun RtInputEvent.toInputEvent(entityManager: EntityManager): InputEvent {
140     return InputEvent(
141         source.toInputEventSource(),
142         pointerType.toInputEventPointerType(),
143         timestamp,
144         origin,
145         direction,
146         action.toInputEventAction(),
147         hitInfo?.toHitInfo(entityManager),
148         secondaryHitInfo?.toHitInfo(entityManager),
149     )
150 }
151 
152 /** Extension function that converts a [RtSpatialCapabilities] to a [SpatialCapabilities]. */
toSpatialCapabilitiesnull153 internal fun RtSpatialCapabilities.toSpatialCapabilities(): SpatialCapabilities {
154     return SpatialCapabilities(capabilities.toSpatialCapability())
155 }
156 
157 /** Extension function that converts a [RtSpatialVisibility] to a [SpatialVisibility]. */
toSpatialVisibilitynull158 internal fun RtSpatialVisibility.toSpatialVisibility(): SpatialVisibility {
159     return SpatialVisibility(visibility.toSpatialVisibilityValue())
160 }
161 
162 /** Extension function that converts a [RtResizeEvent] to a [ResizeEvent]. */
toResizeEventnull163 internal fun RtResizeEvent.toResizeEvent(): ResizeEvent {
164     return ResizeEvent(resizeState.toResizeState(), newSize.toDimensions())
165 }
166 
167 /**
168  * Extension function that converts a [Set] of [AnchorPlacement] to a [Set] of
169  * [JxrPlatformAdapter.AnchorPlacement].
170  */
toRtAnchorPlacementnull171 internal fun Set<AnchorPlacement>.toRtAnchorPlacement(
172     runtime: JxrPlatformAdapter
173 ): Set<RtAnchorPlacement> {
174     val rtAnchorPlacementSet = HashSet<RtAnchorPlacement>()
175     for (placement in this) {
176         val planeTypeFilter = placement.planeTypeFilter.map { it.toRtPlaneType() }.toMutableSet()
177         val planeSemanticFilter =
178             placement.planeSemanticFilter.map { it.toRtPlaneSemantic() }.toMutableSet()
179 
180         val rtAnchorPlacement =
181             runtime.createAnchorPlacementForPlanes(planeTypeFilter, planeSemanticFilter)
182         rtAnchorPlacementSet.add(rtAnchorPlacement)
183     }
184     return rtAnchorPlacementSet
185 }
186 
187 /** Extension function that converts a [Int] to [MoveEvent.MoveState]. */
188 @MoveEvent.MoveState
toMoveStatenull189 internal fun Int.toMoveState(): Int {
190     return when (this) {
191         RtMoveEvent.MOVE_STATE_START -> MoveEvent.MOVE_STATE_START
192         RtMoveEvent.MOVE_STATE_ONGOING -> MoveEvent.MOVE_STATE_ONGOING
193         RtMoveEvent.MOVE_STATE_END -> MoveEvent.MOVE_STATE_END
194         else -> error("Unknown Move State: $this")
195     }
196 }
197 
198 /** Extension function that converts a [Int] to [ResizeEvent.ResizeState]. */
199 @ResizeEvent.ResizeState
toResizeStatenull200 internal fun Int.toResizeState(): Int {
201     return when (this) {
202         RtResizeEvent.RESIZE_STATE_UNKNOWN -> ResizeEvent.RESIZE_STATE_UNKNOWN
203         RtResizeEvent.RESIZE_STATE_START -> ResizeEvent.RESIZE_STATE_START
204         RtResizeEvent.RESIZE_STATE_ONGOING -> ResizeEvent.RESIZE_STATE_ONGOING
205         RtResizeEvent.RESIZE_STATE_END -> ResizeEvent.RESIZE_STATE_END
206         else -> error("Unknown Resize State: $this")
207     }
208 }
209 
210 /** Extension function that converts a [Int] to [InputEvent.Source]. */
211 @InputEvent.Source
toInputEventSourcenull212 internal fun Int.toInputEventSource(): Int {
213     return when (this) {
214         RtInputEvent.SOURCE_UNKNOWN -> InputEvent.SOURCE_UNKNOWN
215         RtInputEvent.SOURCE_HEAD -> InputEvent.SOURCE_HEAD
216         RtInputEvent.SOURCE_CONTROLLER -> InputEvent.SOURCE_CONTROLLER
217         RtInputEvent.SOURCE_HANDS -> InputEvent.SOURCE_HANDS
218         RtInputEvent.SOURCE_MOUSE -> InputEvent.SOURCE_MOUSE
219         RtInputEvent.SOURCE_GAZE_AND_GESTURE -> InputEvent.SOURCE_GAZE_AND_GESTURE
220         else -> error("Unknown Input Event Source: $this")
221     }
222 }
223 
224 /** Extension function that converts a [Int] to [InputEvent.PointerType]. */
225 @InputEvent.PointerType
toInputEventPointerTypenull226 internal fun Int.toInputEventPointerType(): Int {
227     return when (this) {
228         RtInputEvent.POINTER_TYPE_DEFAULT -> InputEvent.POINTER_TYPE_DEFAULT
229         RtInputEvent.POINTER_TYPE_LEFT -> InputEvent.POINTER_TYPE_LEFT
230         RtInputEvent.POINTER_TYPE_RIGHT -> InputEvent.POINTER_TYPE_RIGHT
231         else -> error("Unknown Input Event Pointer Type: $this")
232     }
233 }
234 
235 /** Extension function that converts a [Int] to [SpatialCapabilities.SpatialCapability]. */
236 @SpatialCapabilities.SpatialCapability
toSpatialCapabilitynull237 internal fun Int.toSpatialCapability(): Int {
238     return this
239 }
240 
241 /** Extension function that converts a [Int] to [SpatialVisibilityValue]. */
242 @SpatialVisibility.SpatialVisibilityValue
toSpatialVisibilityValuenull243 internal fun Int.toSpatialVisibilityValue(): Int {
244     return when (this) {
245         RtSpatialVisibility.UNKNOWN -> SpatialVisibility.UNKNOWN
246         RtSpatialVisibility.OUTSIDE_FOV -> SpatialVisibility.OUTSIDE_FOV
247         RtSpatialVisibility.PARTIALLY_WITHIN_FOV -> SpatialVisibility.PARTIALLY_WITHIN_FOV
248         RtSpatialVisibility.WITHIN_FOV -> SpatialVisibility.WITHIN_FOV
249         else -> error("Unknown Spatial Visibility Value: $this")
250     }
251 }
252 
253 /** Extension function that converts a [Int] to [InputEvent.Action]. */
254 @InputEvent.Action
toInputEventActionnull255 internal fun Int.toInputEventAction(): Int {
256     return when (this) {
257         RtInputEvent.ACTION_DOWN -> InputEvent.ACTION_DOWN
258         RtInputEvent.ACTION_UP -> InputEvent.ACTION_UP
259         RtInputEvent.ACTION_MOVE -> InputEvent.ACTION_MOVE
260         RtInputEvent.ACTION_CANCEL -> InputEvent.ACTION_CANCEL
261         RtInputEvent.ACTION_HOVER_MOVE -> InputEvent.ACTION_HOVER_MOVE
262         RtInputEvent.ACTION_HOVER_ENTER -> InputEvent.ACTION_HOVER_ENTER
263         RtInputEvent.ACTION_HOVER_EXIT -> InputEvent.ACTION_HOVER_EXIT
264         else -> error("Unknown Input Event Action: $this")
265     }
266 }
267 
268 /** Extension function that converts a [TextureSampler] to [RtTextureSampler]. */
toRtTextureSamplernull269 internal fun TextureSampler.toRtTextureSampler(): RtTextureSampler {
270     return RtTextureSampler(
271         wrapModeS,
272         wrapModeT,
273         wrapModeR,
274         minFilter,
275         magFilter,
276         compareMode,
277         compareFunc,
278         anisotropyLog2,
279     )
280 }
281 
282 /** Extension function that converts a [HitTestFilter] to a [RtHitTestFilter]. */
toRtHitTestFilternull283 internal fun Int.toRtHitTestFilter(): Int {
284     var filters: Int = 0
285     if (this and HitTestFilter.OTHER_SCENES != 0) {
286         filters = filters or RtHitTestFilter.OTHER_SCENES
287     }
288     if (this and HitTestFilter.SELF_SCENE != 0) {
289         filters = filters or RtHitTestFilter.SELF_SCENE
290     }
291     return filters
292 }
293 
294 /** Extension function that converts a [RtHitTestSurfaceType] to a [HitTestResult.SurfaceType]. */
toHitTestSurfaceTypenull295 internal fun Int.toHitTestSurfaceType(): Int {
296     return when (this) {
297         RtHitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_UNKNOWN -> SurfaceType.UNKNOWN
298         RtHitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_PLANE -> SurfaceType.PLANE
299         RtHitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_OBJECT -> SurfaceType.OBJECT
300         else -> SurfaceType.UNKNOWN
301     }
302 }
303 
304 /** Extension function that converts a [RtHitTestResult] to a [HitTestResult]. */
toHitTestResultnull305 internal fun RtHitTestResult.toHitTestResult(): HitTestResult {
306     return HitTestResult(hitPosition, surfaceNormal, surfaceType.toHitTestSurfaceType(), distance)
307 }
308