Merge changes I8abf7c0c,I260a6279 into androidx-main
* changes:
Fix tests broken after DEBUG was left sat to true
The ViewFactoryHolder should return itself as viewRoot
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/AndroidViewTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/AndroidViewTest.kt
index 3f51e6b..282b65d 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/AndroidViewTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/AndroidViewTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.ui.inspection
+import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.inspection.rules.ComposeInspectionRule
import androidx.compose.ui.inspection.rules.sendCommand
@@ -44,7 +45,11 @@
it.viewId != 0L
}.single()
assertThat(strings[composeNode.name]).isEqualTo("ComposeNode")
- val viewHolder = (rule.rootsForTest.single() as ViewGroup).getChildAt(0)
- assertThat(composeNode.viewId).isEqualTo(viewHolder.uniqueDrawingId)
+ val androidViewsHandler = rule.rootsForTest.single().view.childAt(0)
+ val viewFactoryHolder = androidViewsHandler.childAt(0)
+ assertThat(composeNode.viewId).isEqualTo(viewFactoryHolder.uniqueDrawingId)
}
+
+ private fun View.childAt(index: Int): View =
+ (this as ViewGroup).getChildAt(index)
}
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
index 09a5db6..6904996 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
@@ -56,6 +56,7 @@
import androidx.compose.ui.R
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.inspection.compose.flatten
import androidx.compose.ui.inspection.testdata.TestActivity
import androidx.compose.ui.layout.GraphicLayerInfo
import androidx.compose.ui.platform.LocalDensity
@@ -93,7 +94,7 @@
import java.util.WeakHashMap
import kotlin.math.roundToInt
-private const val DEBUG = true
+private const val DEBUG = false
private const val ROOT_ID = 3L
private const val MAX_RECURSIONS = 2
private const val MAX_ITERABLE_SIZE = 5
@@ -120,23 +121,26 @@
return findAllAndroidComposeViews().single()
}
- private fun findAllAndroidComposeViews(): List<View> {
- val composeViews = mutableListOf<View>()
+ private fun findAllAndroidComposeViews(): List<View> =
+ findAllViews("AndroidComposeView")
+
+ private fun findAllViews(className: String): List<View> {
+ val views = mutableListOf<View>()
WindowInspector.getGlobalWindowViews().forEach {
- collectAllAndroidComposeView(it.rootView, composeViews)
+ collectAllViews(it.rootView, className, views)
}
- return composeViews
+ return views
}
- private fun collectAllAndroidComposeView(view: View, composeViews: MutableList<View>) {
- if (view.javaClass.simpleName == "AndroidComposeView") {
- composeViews.add(view)
+ private fun collectAllViews(view: View, className: String, views: MutableList<View>) {
+ if (view.javaClass.simpleName == className) {
+ views.add(view)
}
if (view !is ViewGroup) {
return
}
for (i in 0 until view.childCount) {
- collectAllAndroidComposeView(view.getChildAt(i), composeViews)
+ collectAllViews(view.getChildAt(i), className, views)
}
}
@@ -146,6 +150,11 @@
}
@Test
+ fun doNotCommitWithDebugSetToTrue() {
+ assertThat(DEBUG).isFalse()
+ }
+
+ @Test
fun buildTree() {
val slotTableRecord = CompositionDataRecord.create()
@@ -495,6 +504,7 @@
val builder = LayoutInspectorTree()
val appNodes = builder.convert(appView)
+ dumpSlotTableSet(slotTableRecord)
dumpNodes(appNodes, appView, builder)
// Verify that the main app does not contain the Popup
@@ -516,7 +526,7 @@
dumpNodes(dialogNodes, dialogView, builder)
// Verify that the AlertDialog is captured with content
- validate(dialogNodes, builder, ignoreElementsFromShow = false) {
+ validate(dialogNodes, builder) {
node(
name = "AlertDialog",
fileName = "LayoutInspectorTreeTest.kt",
@@ -564,6 +574,7 @@
validate(appNodes, builder) {
node(
name = "Column",
+ isRenderNode = true,
fileName = "LayoutInspectorTreeTest.kt",
children = listOf("Text")
)
@@ -579,7 +590,7 @@
dumpNodes(popupNodes, popupView, builder)
// Verify that the Popup is captured with content
- validate(popupNodes, builder, ignoreElementsFromShow = false) {
+ validate(popupNodes, builder) {
node(
name = "Popup",
fileName = "LayoutInspectorTreeTest.kt",
@@ -617,7 +628,7 @@
dumpNodes(nodes, composeView, builder)
val androidView = nodes.flatMap { flatten(it) }.single { it.name == "AndroidView" }
- validate(listOf(androidView), builder, ignoreElementsFromShow = false) {
+ validate(listOf(androidView), builder) {
node(
name = "AndroidView",
fileName = "LayoutInspectorTreeTest.kt",
@@ -631,6 +642,47 @@
}
}
+ @Test
+ fun testDoubleAndroidView() {
+ val slotTableRecord = CompositionDataRecord.create()
+
+ show {
+ Inspectable(slotTableRecord) {
+ Column {
+ Text("Compose Text1")
+ AndroidView({ context ->
+ TextView(context).apply {
+ text = "first"
+ }
+ })
+ Text("Compose Text2")
+ AndroidView({ context ->
+ TextView(context).apply {
+ text = "second"
+ }
+ })
+ }
+ }
+ }
+ val composeView = findAndroidComposeView() as ViewGroup
+ composeView.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
+ val builder = LayoutInspectorTree()
+ builder.hideSystemNodes = false
+ val nodes = builder.convert(composeView)
+ dumpSlotTableSet(slotTableRecord)
+ dumpNodes(nodes, composeView, builder)
+ val textViews = findAllViews("TextView")
+ val firstTextView = textViews
+ .filterIsInstance<TextView>()
+ .first { it.text == "first" }
+ val secondTextView = textViews
+ .filterIsInstance<TextView>()
+ .first { it.text == "second" }
+ val composeNodes = nodes.flatMap { it.flatten() }.filter { it.name == "ComposeNode" }
+ assertThat(composeNodes[0].viewId).isEqualTo(viewParent(secondTextView)?.uniqueDrawingId)
+ assertThat(composeNodes[1].viewId).isEqualTo(viewParent(firstTextView)?.uniqueDrawingId)
+ }
+
// WARNING: The formatting of the lines below here affect test results.
val titleLine = Throwable().stackTrace[0].lineNumber + 3
@@ -782,16 +834,12 @@
checkSemantics: Boolean = false,
checkLineNumbers: Boolean = false,
checkRenderNodes: Boolean = true,
- ignoreElementsFromShow: Boolean = true,
block: TreeValidationReceiver.() -> Unit = {}
) {
if (DEBUG) {
return
}
val nodes = result.flatMap { flatten(it) }.listIterator()
- if (ignoreElementsFromShow) {
- ignoreStart(nodes, "Box")
- }
val tree = TreeValidationReceiver(
nodes,
density,
@@ -804,12 +852,6 @@
tree.block()
}
- private fun ignoreStart(nodes: ListIterator<InspectorNode>, vararg names: String) {
- for (name in names) {
- assertThat(nodes.next().name).isEqualTo(name)
- }
- }
-
private class TreeValidationReceiver(
val nodeIterator: Iterator<InspectorNode>,
val density: Density,
@@ -899,11 +941,14 @@
}
private fun View.hasChild(id: Long): Boolean {
+ if (uniqueDrawingId == id) {
+ return true
+ }
if (this !is ViewGroup) {
return false
}
for (index in 0..childCount) {
- if (getChildAt(index).uniqueDrawingId == id) {
+ if (getChildAt(index).hasChild(id)) {
return true
}
}
@@ -914,7 +959,11 @@
private fun flatten(node: InspectorNode): List<InspectorNode> =
listOf(node).plus(node.children.flatMap { flatten(it) })
- fun show(composable: @Composable () -> Unit) = composeTestRule.setContent(composable)
+ private fun viewParent(view: View): View? =
+ view.parent as? View
+
+ private fun show(composable: @Composable () -> Unit) =
+ composeTestRule.setContent(composable)
// region DEBUG print methods
private fun dumpNodes(nodes: List<InspectorNode>, view: View, builder: LayoutInspectorTree) {
@@ -1022,12 +1071,14 @@
}
private fun dumpGroup(group: Group, indent: Int) {
+ val location = group.location
val position = group.position?.let { "\"$it\"" } ?: "null"
val box = group.box
val id = group.modifierInfo.mapNotNull { (it.extra as? GraphicLayerInfo)?.layerId }
.singleOrNull() ?: 0
println(
"\"${" ".repeat(indent)}\", ${group.javaClass.simpleName}, \"${group.name}\", " +
+ "file: ${location?.sourceFile} hash: ${location?.packageHash}, " +
"params: ${group.parameters.size}, children: ${group.children.size}, " +
"$id, $position, " +
"${box.left}, ${box.right}, ${box.right - box.left}, ${box.bottom - box.top}"
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
index 3a917f6..74b6615 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
@@ -57,6 +57,7 @@
packageNameHash("androidx.compose.material"),
packageNameHash("androidx.compose.material.ripple"),
packageNameHash("androidx.compose.runtime"),
+ packageNameHash("androidx.compose.runtime.saveable"),
packageNameHash("androidx.compose.ui"),
packageNameHash("androidx.compose.ui.graphics.vector"),
packageNameHash("androidx.compose.ui.layout"),
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
index 85ad0bd..994bf78 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
@@ -135,7 +135,7 @@
internal var typedView: T? = null
- override val viewRoot: View? get() = parent as? View
+ override val viewRoot: View get() = this
var factory: ((Context) -> T)? = null
set(value) {