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.arcore
18 
19 import android.annotation.SuppressLint
20 import androidx.xr.runtime.internal.Hand as RuntimeHand
21 import androidx.xr.runtime.internal.LifecycleManager
22 import androidx.xr.runtime.internal.Plane as RuntimePlane
23 import androidx.xr.runtime.internal.Trackable as RuntimeTrackable
24 import java.util.Queue
25 import java.util.concurrent.ConcurrentLinkedQueue
26 import java.util.concurrent.CopyOnWriteArrayList
27 
28 /** Manages all XR resources that are used by the ARCore for XR API. */
29 internal class XrResourcesManager {
30 
31     internal lateinit var lifecycleManager: LifecycleManager
32 
33     /** List of [Updatable]s that are updated every frame. */
34     private val _updatables = CopyOnWriteArrayList<Updatable>()
35     val updatables: List<Updatable> = _updatables
36 
37     /** Queue of [Anchor]s that will be detached on the next frame update. */
38     private val _anchorsToDetachQueue = ConcurrentLinkedQueue<Anchor>()
39     val anchorsToDetachQueue: Queue<Anchor> = _anchorsToDetachQueue
40 
41     /** Map of runtime trackable pointer to [Trackable]. */
42     @SuppressLint("BanConcurrentHashMap")
43     private val _trackablesMap =
44         java.util.concurrent.ConcurrentHashMap<RuntimeTrackable, Trackable<Trackable.State>>()
45     val trackablesMap: Map<RuntimeTrackable, Trackable<Trackable.State>> = _trackablesMap
46 
47     /** The data of hands */
48     private var _leftRuntimeHand: RuntimeHand? = null
49     private var _rightRuntimeHand: RuntimeHand? = null
<lambda>null50     val leftHand: Hand? by lazy { _leftRuntimeHand?.let { Hand(it) } }
<lambda>null51     val rightHand: Hand? by lazy { _rightRuntimeHand?.let { Hand(it) } }
52 
initiateHandsnull53     internal fun initiateHands(leftRuntimeHand: RuntimeHand?, rightRuntimeHand: RuntimeHand?) {
54         _leftRuntimeHand = leftRuntimeHand
55         _rightRuntimeHand = rightRuntimeHand
56     }
57 
addUpdatablenull58     internal fun addUpdatable(updatable: Updatable) {
59         _updatables.add(updatable)
60     }
61 
removeUpdatablenull62     internal fun removeUpdatable(updatable: Updatable) {
63         _updatables.remove(updatable)
64     }
65 
queueAnchorToDetachnull66     internal fun queueAnchorToDetach(anchor: Anchor) {
67         _anchorsToDetachQueue.add(anchor)
68     }
69 
updatenull70     internal suspend fun update() {
71         while (!_anchorsToDetachQueue.isEmpty()) {
72             _anchorsToDetachQueue.poll()?.runtimeAnchor?.detach()
73         }
74 
75         for (updatable in updatables) {
76             updatable.update()
77         }
78     }
79 
syncTrackablesnull80     internal fun syncTrackables(runtimeTrackables: Collection<RuntimeTrackable>) {
81         val toRemoveTrackables = _trackablesMap.keys - runtimeTrackables
82         val toAddTrackables = runtimeTrackables - _trackablesMap.keys
83 
84         for (runtimeTrackable in toRemoveTrackables) {
85             removeUpdatable(_trackablesMap[runtimeTrackable]!! as Updatable)
86             _trackablesMap.remove(runtimeTrackable)
87         }
88 
89         for (runtimeTrackable in toAddTrackables) {
90             val trackable = createTrackable(runtimeTrackable)
91             _trackablesMap[runtimeTrackable] = trackable
92             addUpdatable(trackable as Updatable)
93         }
94     }
95 
clearnull96     internal fun clear() {
97         _updatables.clear()
98         _trackablesMap.clear()
99     }
100 
createTrackablenull101     private fun createTrackable(runtimeTrackable: RuntimeTrackable): Trackable<Trackable.State> {
102         if (_trackablesMap.containsKey(runtimeTrackable)) {
103             return _trackablesMap[runtimeTrackable]!!
104         }
105 
106         val trackable =
107             when (runtimeTrackable) {
108                 is RuntimePlane -> Plane(runtimeTrackable, this)
109                 else ->
110                     throw IllegalArgumentException(
111                         "Unsupported trackable type: ${runtimeTrackable.javaClass}"
112                     )
113             }
114         _trackablesMap[runtimeTrackable] = trackable
115         return trackable
116     }
117 }
118