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