traversal
Summary: This adds a simple traversal to the UI. As it stands, it will most likely be updated in future iterations. Reviewed By: LukeDefeo Differential Revision: D38907292 fbshipit-source-id: 98cea1f971a4ef37ba2d1c75b882dd44df29bb3a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f1e80b18b1
commit
5aff69d1c9
@@ -11,6 +11,7 @@ import android.app.Application
|
||||
import com.facebook.flipper.core.FlipperConnection
|
||||
import com.facebook.flipper.core.FlipperObject
|
||||
import com.facebook.flipper.core.FlipperPlugin
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationInspector
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
|
||||
@@ -32,6 +33,9 @@ class UIDebuggerFlipperPlugin(val application: Application) : FlipperPlugin {
|
||||
FlipperObject.Builder()
|
||||
.put("rootId", System.identityHashCode(application).toString())
|
||||
.build())
|
||||
|
||||
val inspector = ApplicationInspector(context)
|
||||
val root = inspector.inspect()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.common
|
||||
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class Node(val ref: WeakReference<Any>) {
|
||||
var id: String? = null
|
||||
var name: String? = null
|
||||
var attributes: Map<String, Any?>? = null
|
||||
var children: List<Node>? = null
|
||||
}
|
||||
@@ -9,17 +9,15 @@ package com.facebook.flipper.plugins.uidebugger.core
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import java.util.List
|
||||
import com.facebook.flipper.plugins.uidebugger.common.Node
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
|
||||
class ApplicationInspector(val context: Context) {
|
||||
val descriptorRegister = DescriptorRegister.withDefaults()
|
||||
val traversal = LayoutTraversal(descriptorRegister)
|
||||
|
||||
fun traverse(view: View) {
|
||||
val inspector =
|
||||
LayoutVisitor.create(
|
||||
object : LayoutVisitor.Visitor {
|
||||
override fun visit(view: View) {}
|
||||
})
|
||||
inspector.traverse(view)
|
||||
fun inspect(): Node? {
|
||||
return traversal.inspect(context.application)
|
||||
}
|
||||
|
||||
fun attachListeners(view: View) {
|
||||
@@ -52,14 +50,10 @@ class ApplicationInspector(val context: Context) {
|
||||
|
||||
override fun onRootViewRemoved(view: View) {}
|
||||
|
||||
override fun onRootViewsChanged(views: List<View>) {}
|
||||
override fun onRootViewsChanged(views: java.util.List<View>) {}
|
||||
})
|
||||
|
||||
val activeRoots = rootResolver.listActiveRootViews()
|
||||
activeRoots?.let { roots ->
|
||||
for (root: RootViewResolver.RootView in roots) {
|
||||
traverse(root.view)
|
||||
}
|
||||
}
|
||||
activeRoots?.let { roots -> for (root: RootViewResolver.RootView in roots) {} }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.core
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.common.Node
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Descriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class LayoutTraversal(private val descriptorRegister: DescriptorRegister) {
|
||||
class IntermediateNode(val node: Node) {
|
||||
var children: List<Any>? = null
|
||||
}
|
||||
|
||||
internal inline fun Descriptor<*>.asAny(): Descriptor<Any> = this as Descriptor<Any>
|
||||
|
||||
private fun describe(obj: Any): IntermediateNode {
|
||||
var intermediate = IntermediateNode(Node(WeakReference(obj)))
|
||||
|
||||
val descriptor = descriptorRegister.descriptorForClass(obj::class.java)
|
||||
descriptor?.let { descriptor ->
|
||||
val anyDescriptor = descriptor.asAny()
|
||||
|
||||
intermediate.node.id = anyDescriptor.getId(obj)
|
||||
intermediate.node.name = anyDescriptor.getName(obj)
|
||||
|
||||
val attributes = mutableMapOf<String, Any?>()
|
||||
anyDescriptor.getData(obj, attributes)
|
||||
intermediate.node.attributes = attributes
|
||||
|
||||
val children = mutableListOf<Any>()
|
||||
anyDescriptor.getChildren(obj, children)
|
||||
intermediate.children = children
|
||||
}
|
||||
|
||||
return intermediate
|
||||
}
|
||||
|
||||
private fun traverse(entry: Any): Node? {
|
||||
val root = describe(entry)
|
||||
root?.let { intermediate ->
|
||||
val queue = mutableListOf<IntermediateNode>()
|
||||
queue.add(intermediate)
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val intermediateNode = queue.removeFirst()
|
||||
|
||||
val children = mutableListOf<Node>()
|
||||
intermediateNode.children?.forEach {
|
||||
val intermediateChild = describe(it)
|
||||
children.add(intermediateChild.node)
|
||||
queue.add(intermediateChild)
|
||||
}
|
||||
intermediateNode.node.children = children
|
||||
}
|
||||
}
|
||||
|
||||
return root?.node
|
||||
}
|
||||
|
||||
fun inspect(applicationRef: ApplicationRef): Node? {
|
||||
return traverse(applicationRef)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ abstract class AbstractChainedDescriptor<T> : Descriptor<T>(), ChainedDescriptor
|
||||
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
||||
* globally unique ID it is fine to rely on [System.identityHashCode].
|
||||
*/
|
||||
override fun getId(node: T): String? {
|
||||
override fun getId(node: T): String {
|
||||
return onGetId(node)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class AbstractChainedDescriptor<T> : Descriptor<T>(), ChainedDescriptor
|
||||
* The name used to identify this node in the inspector. Does not need to be unique. A good
|
||||
* default is to use the class name of the node.
|
||||
*/
|
||||
override fun getName(node: T): String? {
|
||||
override fun getName(node: T): String {
|
||||
return onGetName(node)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ interface NodeDescriptor<T> {
|
||||
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
||||
* globally unique ID it is fine to rely on [System.identityHashCode].
|
||||
*/
|
||||
fun getId(node: T): String?
|
||||
fun getId(node: T): String
|
||||
|
||||
/**
|
||||
* The name used to identify this node in the inspector. Does not need to be unique. A good
|
||||
* default is to use the class name of the node.
|
||||
*/
|
||||
fun getName(node: T): String?
|
||||
fun getName(node: T): String
|
||||
|
||||
/** The children this node exposes in the inspector. */
|
||||
fun getChildren(node: T, children: MutableList<Any>)
|
||||
|
||||
Reference in New Issue
Block a user