From 5aff69d1c9627a9c960697a2c0df9f11090c7e79 Mon Sep 17 00:00:00 2001 From: Lorenzo Blasa Date: Tue, 23 Aug 2022 05:45:29 -0700 Subject: [PATCH] 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 --- .../uidebugger/UIDebuggerFlipperPlugin.kt | 4 ++ .../flipper/plugins/uidebugger/common/Node.kt | 17 +++++ .../uidebugger/core/ApplicationInspector.kt | 22 +++--- .../uidebugger/core/LayoutTraversal.kt | 69 +++++++++++++++++++ .../descriptors/AbstractChainedDescriptor.kt | 4 +- .../uidebugger/descriptors/NodeDescriptor.kt | 4 +- 6 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 android/src/main/java/com/facebook/flipper/plugins/uidebugger/common/Node.kt create mode 100644 android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/LayoutTraversal.kt diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPlugin.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPlugin.kt index 9eb084b47..7eefc8ca1 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPlugin.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPlugin.kt @@ -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) diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/common/Node.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/common/Node.kt new file mode 100644 index 000000000..52a979acc --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/common/Node.kt @@ -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) { + var id: String? = null + var name: String? = null + var attributes: Map? = null + var children: List? = null +} diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/ApplicationInspector.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/ApplicationInspector.kt index e8c8cdeca..cff6a2a7c 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/ApplicationInspector.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/ApplicationInspector.kt @@ -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) {} + override fun onRootViewsChanged(views: java.util.List) {} }) 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) {} } } } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/LayoutTraversal.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/LayoutTraversal.kt new file mode 100644 index 000000000..890657488 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/LayoutTraversal.kt @@ -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? = null + } + + internal inline fun Descriptor<*>.asAny(): Descriptor = this as Descriptor + + 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() + anyDescriptor.getData(obj, attributes) + intermediate.node.attributes = attributes + + val children = mutableListOf() + 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() + queue.add(intermediate) + + while (queue.isNotEmpty()) { + val intermediateNode = queue.removeFirst() + + val children = mutableListOf() + 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) + } +} diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/AbstractChainedDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/AbstractChainedDescriptor.kt index cb1ad1bf3..6b161359c 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/AbstractChainedDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/AbstractChainedDescriptor.kt @@ -36,7 +36,7 @@ abstract class AbstractChainedDescriptor : Descriptor(), 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 : Descriptor(), 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) } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/NodeDescriptor.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/NodeDescriptor.kt index b1bc3fd5a..f1a06934f 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/NodeDescriptor.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/descriptors/NodeDescriptor.kt @@ -15,13 +15,13 @@ interface NodeDescriptor { * 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)