1 /*
<lambda>null2  * 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.compose.testing
18 
19 import androidx.annotation.RestrictTo
20 import androidx.compose.ui.test.junit4.AndroidComposeTestRule
21 import androidx.compose.ui.util.fastForEach
22 import androidx.xr.compose.platform.SceneManager
23 import androidx.xr.compose.subspace.node.SubspaceSemanticsInfo
24 
25 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
26 public class SubspaceTestContext(private val testRule: AndroidComposeTestRule<*, *>) {
27     /**
28      * Collects all [SubspaceSemanticsNode]s from all compose hierarchies.
29      *
30      * Can crash in case it hits time out. This is not supposed to be handled as it surfaces only in
31      * incorrect tests.
32      */
33     internal fun getAllSemanticsNodes(
34         atLeastOneRootRequired: Boolean
35     ): Iterable<SubspaceSemanticsInfo> {
36         // Block and wait for compose state to settle before looking for root nodes.
37         testRule.waitForIdle()
38         val roots = SceneManager.getAllRootSubspaceSemanticsNodes()
39         check(!atLeastOneRootRequired || roots.isNotEmpty()) {
40             """No subspace compose hierarchies found in the app. Possible reasons include:
41         (1) the Activity that calls setSubspaceContent did not launch;
42         (2) setSubspaceContent was not called;
43         (3) setSubspaceContent was called before the ComposeTestRule ran;
44         (4) a Subspace was not used in setContent
45         If setSubspaceContent is called by the Activity, make sure the Activity is
46         launched after the ComposeTestRule runs"""
47         }
48 
49         return roots.flatMap { it.getAllSemanticsNodes() }
50     }
51 }
52 
SubspaceSemanticsInfonull53 private fun SubspaceSemanticsInfo.getAllSemanticsNodes(): Iterable<SubspaceSemanticsInfo> {
54     val nodes = mutableListOf<SubspaceSemanticsInfo>()
55 
56     fun findAllSemanticNodesRecursive(currentNode: SubspaceSemanticsInfo) {
57         nodes.add(currentNode)
58         currentNode.semanticsChildren.fastForEach { child -> findAllSemanticNodesRecursive(child) }
59     }
60 
61     findAllSemanticNodesRecursive(this)
62 
63     return nodes
64 }
65