Descriptor clean up
Summary: 1. The base class descriptor was removed, this was given that we have chained descriptor there is no need for this anymore 2. The Base interface node descriptor no longer has a mutable list based api. You simply return a list. The mutable list based api was specifically to allow chaining and this quirk is isoltated to the chained descriptor 3. AbstractChainedDescriptor and ChainedDescriptor were merged Reviewed By: lblasa Differential Revision: D39496073 fbshipit-source-id: fb3ec629ec3b27f587bdbd0b323624a4bc4ebea3
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f5a5e1b19d
commit
2090120cda
@@ -8,52 +8,56 @@
|
|||||||
package com.facebook.flipper.plugins.uidebugger.litho
|
package com.facebook.flipper.plugins.uidebugger.litho
|
||||||
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Descriptor
|
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||||
import com.facebook.litho.DebugComponent
|
import com.facebook.litho.DebugComponent
|
||||||
import com.facebook.litho.LithoView
|
import com.facebook.litho.LithoView
|
||||||
|
|
||||||
object LithoViewDescriptor : Descriptor<LithoView>() {
|
object LithoViewDescriptor : NodeDescriptor<LithoView> {
|
||||||
override fun getId(node: LithoView): String = System.identityHashCode(node).toString()
|
override fun getId(node: LithoView): String = System.identityHashCode(node).toString()
|
||||||
|
|
||||||
override fun getName(node: LithoView): String = "LithoView"
|
override fun getName(node: LithoView): String = "LithoView"
|
||||||
|
|
||||||
override fun getChildren(node: LithoView, children: MutableList<Any>) {
|
override fun getChildren(node: LithoView): List<Any> {
|
||||||
|
val result = mutableListOf<Any>()
|
||||||
val debugComponent = DebugComponent.getRootInstance(node)
|
val debugComponent = DebugComponent.getRootInstance(node)
|
||||||
if (debugComponent != null) {
|
if (debugComponent != null) {
|
||||||
children.add(debugComponent)
|
result.add(debugComponent)
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getActiveChild(node: LithoView): Any? = null
|
override fun getActiveChild(node: LithoView): Any? = null
|
||||||
|
|
||||||
override fun getData(node: LithoView, builder: MutableMap<String, InspectableObject>) {}
|
override fun getData(node: LithoView) = mapOf<String, InspectableObject>()
|
||||||
}
|
}
|
||||||
|
|
||||||
object DebugComponentDescriptor : Descriptor<DebugComponent>() {
|
object DebugComponentDescriptor : NodeDescriptor<DebugComponent> {
|
||||||
override fun getId(node: DebugComponent): String = System.identityHashCode(node).toString()
|
override fun getId(node: DebugComponent): String = System.identityHashCode(node).toString()
|
||||||
|
|
||||||
override fun getName(node: DebugComponent): String {
|
override fun getName(node: DebugComponent): String {
|
||||||
return node.component.simpleName
|
return node.component.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO the mutable list thing doesnt make sense for non chained descriptors, should just return
|
override fun getChildren(node: DebugComponent): List<Any> {
|
||||||
override fun getChildren(node: DebugComponent, children: MutableList<Any>) {
|
val result = mutableListOf<Any>()
|
||||||
|
|
||||||
val mountedView = node.mountedView
|
val mountedView = node.mountedView
|
||||||
val mountedDrawable = node.mountedDrawable
|
val mountedDrawable = node.mountedDrawable
|
||||||
|
|
||||||
if (mountedView != null) {
|
if (mountedView != null) {
|
||||||
children.add(mountedView)
|
result.add(mountedView)
|
||||||
} else if (mountedDrawable != null) {
|
} else if (mountedDrawable != null) {
|
||||||
children.add(mountedDrawable)
|
result.add(mountedDrawable)
|
||||||
} else {
|
} else {
|
||||||
for (child in node.childComponents) {
|
for (child in node.childComponents) {
|
||||||
children.add(child)
|
result.add(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getActiveChild(node: DebugComponent): Any? = null
|
override fun getActiveChild(node: DebugComponent): Any? = null
|
||||||
|
|
||||||
// todo same here
|
override fun getData(node: DebugComponent) = mapOf<String, InspectableObject>()
|
||||||
override fun getData(node: DebugComponent, builder: MutableMap<String, InspectableObject>) {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ package com.facebook.flipper.plugins.uidebugger.core
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Descriptor
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
import com.facebook.flipper.plugins.uidebugger.model.Node
|
||||||
|
|
||||||
class LayoutTraversal(
|
class LayoutTraversal(
|
||||||
@@ -19,7 +18,7 @@ class LayoutTraversal(
|
|||||||
val root: ApplicationRef
|
val root: ApplicationRef
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal inline fun Descriptor<*>.asAny(): Descriptor<Any> = this as Descriptor<Any>
|
internal inline fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
||||||
|
|
||||||
/** Traverses the native android hierarchy */
|
/** Traverses the native android hierarchy */
|
||||||
fun traverse(): List<Node> {
|
fun traverse(): List<Node> {
|
||||||
@@ -36,8 +35,7 @@ class LayoutTraversal(
|
|||||||
|
|
||||||
val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
||||||
|
|
||||||
val children = mutableListOf<Any>()
|
val children = descriptor.getChildren(node)
|
||||||
descriptor.getChildren(node, children)
|
|
||||||
|
|
||||||
val childrenIds = mutableListOf<String>()
|
val childrenIds = mutableListOf<String>()
|
||||||
|
|
||||||
@@ -61,8 +59,7 @@ class LayoutTraversal(
|
|||||||
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass).getId(activeChild)
|
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass).getId(activeChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
val attributes = mutableMapOf<String, InspectableObject>()
|
val attributes = descriptor.getData(node)
|
||||||
descriptor.getData(node, attributes)
|
|
||||||
|
|
||||||
result.add(
|
result.add(
|
||||||
Node(
|
Node(
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class RootViewResolver {
|
|||||||
private var viewsField: Field? = null
|
private var viewsField: Field? = null
|
||||||
private var paramsField: Field? = null
|
private var paramsField: Field? = null
|
||||||
|
|
||||||
class RootView(val view: View, val param: WindowManager.LayoutParams)
|
class RootView(val view: View, val param: WindowManager.LayoutParams?)
|
||||||
interface Listener {
|
interface Listener {
|
||||||
fun onRootViewAdded(rootView: View)
|
fun onRootViewAdded(rootView: View)
|
||||||
fun onRootViewRemoved(rootView: View)
|
fun onRootViewRemoved(rootView: View)
|
||||||
@@ -153,9 +153,9 @@ class RootViewResolver {
|
|||||||
for (i in views.indices) {
|
for (i in views.indices) {
|
||||||
val view = views[i]
|
val view = views[i]
|
||||||
// TODO FIX, len(param) is not always the same as len(views) For now just use first
|
// TODO FIX, len(param) is not always the same as len(views) For now just use first
|
||||||
val param = params[0]
|
|
||||||
// params
|
// params
|
||||||
roots.add(RootView(view, param))
|
roots.add(RootView(view, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.descriptors
|
|
||||||
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class derives from Descriptor and provides a canonical implementation of ChainedDescriptor}.
|
|
||||||
*/
|
|
||||||
abstract class AbstractChainedDescriptor<T> : Descriptor<T>(), ChainedDescriptor<T> {
|
|
||||||
private var mSuper: Descriptor<T>? = null
|
|
||||||
|
|
||||||
final override fun setSuper(superDescriptor: Descriptor<T>) {
|
|
||||||
if (superDescriptor !== mSuper) {
|
|
||||||
check(mSuper == null)
|
|
||||||
mSuper = superDescriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSuper(): Descriptor<T>? {
|
|
||||||
return mSuper
|
|
||||||
}
|
|
||||||
|
|
||||||
final override fun getActiveChild(node: T): Any? {
|
|
||||||
// ask each descriptor in the chain for an active child, if none available look up the chain
|
|
||||||
// until no more super descriptors
|
|
||||||
return onGetActiveChild(node) ?: mSuper?.getActiveChild(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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].
|
|
||||||
*/
|
|
||||||
final override fun getId(node: T): String {
|
|
||||||
return onGetId(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun onGetId(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.
|
|
||||||
*/
|
|
||||||
final override fun getName(node: T): String {
|
|
||||||
return onGetName(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun onGetActiveChild(node: T): Any? = null
|
|
||||||
|
|
||||||
abstract fun onGetName(node: T): String
|
|
||||||
|
|
||||||
/** The children this node exposes in the inspector. */
|
|
||||||
final override fun getChildren(node: T, children: MutableList<Any>) {
|
|
||||||
mSuper?.getChildren(node, children)
|
|
||||||
onGetChildren(node, children)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun onGetChildren(node: T, children: MutableList<Any>) {}
|
|
||||||
|
|
||||||
final override fun getData(node: T, builder: MutableMap<String, InspectableObject>) {
|
|
||||||
mSuper?.getData(node, builder)
|
|
||||||
onGetData(node, builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data to show for this node in the sidebar of the inspector. Each key will be a have its
|
|
||||||
* own section
|
|
||||||
*/
|
|
||||||
open fun onGetData(node: T, attributeSections: MutableMap<String, InspectableObject>) {}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,7 @@ import android.app.Activity
|
|||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.stetho.FragmentCompat
|
import com.facebook.flipper.plugins.uidebugger.stetho.FragmentCompat
|
||||||
|
|
||||||
object ActivityDescriptor : AbstractChainedDescriptor<Activity>() {
|
object ActivityDescriptor : ChainedDescriptor<Activity>() {
|
||||||
|
|
||||||
override fun onGetId(node: Activity): String {
|
override fun onGetId(node: Activity): String {
|
||||||
return System.identityHashCode(node).toString()
|
return System.identityHashCode(node).toString()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import com.facebook.flipper.plugins.uidebugger.LogTag
|
|||||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
||||||
|
|
||||||
object ApplicationRefDescriptor : AbstractChainedDescriptor<ApplicationRef>() {
|
object ApplicationRefDescriptor : ChainedDescriptor<ApplicationRef>() {
|
||||||
|
|
||||||
val rootsLocal = RootViewResolver()
|
val rootsLocal = RootViewResolver()
|
||||||
override fun onGetActiveChild(node: ApplicationRef): Any? {
|
override fun onGetActiveChild(node: ApplicationRef): Any? {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
|
||||||
object ButtonDescriptor : AbstractChainedDescriptor<Button>() {
|
object ButtonDescriptor : ChainedDescriptor<Button>() {
|
||||||
|
|
||||||
override fun onGetId(node: Button): String {
|
override fun onGetId(node: Button): String {
|
||||||
return System.identityHashCode(node).toString()
|
return System.identityHashCode(node).toString()
|
||||||
@@ -20,5 +20,8 @@ object ButtonDescriptor : AbstractChainedDescriptor<Button>() {
|
|||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetData(node: Button, attributeSections: MutableMap<String, InspectableObject>) {}
|
override fun onGetData(
|
||||||
|
node: Button,
|
||||||
|
attributeSections: MutableMap<SectionName, InspectableObject>
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,36 +7,94 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface marks a Descriptor in a way that is specially understood by the register. When
|
* A chained descriptor is a special type of descriptor that models the inheritance hierarchy in
|
||||||
* registered for a particular class 'T', a Descriptor that implements this interface will be
|
* native UI frameworks. With this setup you can define a descriptor for each class in the
|
||||||
* chained (via ChainedDescriptor.setSuper) to the Descriptor that is registered for the super class
|
* inheritance chain and given that we record the super class's descriptor we can automatically
|
||||||
* of 'T'. If the super class of 'T' doesn't have a registration, then the super-super class will be
|
* aggregate the results for each descriptor in the inheritance hierarchy in a chain.
|
||||||
* used (and so on). This allows you to implement Descriptor for any class in an inheritance
|
|
||||||
* hierarchy without having to couple it (via direct inheritance) to the super-class' Descriptor.
|
|
||||||
*
|
*
|
||||||
* To understand why this is useful, let's say you wanted to write a Descriptor for ListView. You
|
* The result is that each descriptor in the inheritance chain only exports the attributes that it
|
||||||
* have three options:
|
* knows about but we still get all the attributes from the parent classes
|
||||||
*
|
|
||||||
* The first option is to derive directly from Descriptor and write code to describe everything
|
|
||||||
* about instances of ListView, including details that are exposed by super classes such as
|
|
||||||
* ViewGroup, View, and even Object. This isn't generally a very good choice because it would
|
|
||||||
* require a lot of duplicated code amongst many descriptor implementations.
|
|
||||||
*
|
|
||||||
* The second option is to derive your ListViewDescriptor from ViewGroupDescriptor and only
|
|
||||||
* implement code to describe how ListView differs from ViewGroup. This will result in a class
|
|
||||||
* hierarchy that is parallel to the one that you are describing, but is also not a good choice for
|
|
||||||
* two reasons (let's assume for the moment that ViewGroupDescriptor is deriving from
|
|
||||||
* ViewDescriptor). The first problem is that you will need to write code for aggregating results
|
|
||||||
* from the super-class in methods such as Descriptor.getChildren and Descriptor.getAttributes. The
|
|
||||||
* second problem is that you'd end up with a log of fragility if you ever want to implement a
|
|
||||||
* descriptor for classes that are in-between ViewGroup and ListView, e.g. AbsListView. Any
|
|
||||||
* descriptor that derived from ViewGroupDescriptor and described a class deriving from AbsListView
|
|
||||||
* would have to be modified to now derive from AbsListViewDescriptor.
|
|
||||||
*
|
|
||||||
* The third option is to implement ChainedDescriptor (e.g. by deriving from
|
|
||||||
* AbstractChainedDescriptor) which solves all of these issues for you.
|
|
||||||
*/
|
*/
|
||||||
interface ChainedDescriptor<T> {
|
abstract class ChainedDescriptor<T> : NodeDescriptor<T> {
|
||||||
fun setSuper(superDescriptor: Descriptor<T>)
|
private var mSuper: ChainedDescriptor<T>? = null
|
||||||
|
|
||||||
|
fun setSuper(superDescriptor: ChainedDescriptor<T>) {
|
||||||
|
if (superDescriptor !== mSuper) {
|
||||||
|
check(mSuper == null)
|
||||||
|
mSuper = superDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSuper(): ChainedDescriptor<T>? {
|
||||||
|
return mSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getActiveChild(node: T): Any? {
|
||||||
|
// ask each descriptor in the chain for an active child, if none available look up the chain
|
||||||
|
// until no more super descriptors
|
||||||
|
return onGetActiveChild(node) ?: mSuper?.getActiveChild(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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].
|
||||||
|
*/
|
||||||
|
final override fun getId(node: T): String {
|
||||||
|
return onGetId(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun onGetId(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.
|
||||||
|
*/
|
||||||
|
final override fun getName(node: T): String {
|
||||||
|
return onGetName(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onGetActiveChild(node: T): Any? = null
|
||||||
|
|
||||||
|
abstract fun onGetName(node: T): String
|
||||||
|
|
||||||
|
/** The children this node exposes in the inspector. */
|
||||||
|
final override fun getChildren(node: T): List<Any> {
|
||||||
|
val builder = mutableListOf<Any>()
|
||||||
|
onGetChildren(node, builder)
|
||||||
|
|
||||||
|
var curDescriptor: ChainedDescriptor<T>? = mSuper
|
||||||
|
while (curDescriptor != null) {
|
||||||
|
curDescriptor.onGetChildren(node, builder)
|
||||||
|
curDescriptor = curDescriptor.mSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
// this probably should not be chained as its unlikely you would want children to come from >1
|
||||||
|
// descriptor
|
||||||
|
open fun onGetChildren(node: T, children: MutableList<Any>) {}
|
||||||
|
|
||||||
|
final override fun getData(node: T): Map<SectionName, InspectableObject> {
|
||||||
|
val builder = mutableMapOf<String, InspectableObject>()
|
||||||
|
onGetData(node, builder)
|
||||||
|
|
||||||
|
var curDescriptor: ChainedDescriptor<T>? = mSuper
|
||||||
|
|
||||||
|
while (curDescriptor != null) {
|
||||||
|
curDescriptor.onGetData(node, builder)
|
||||||
|
curDescriptor = curDescriptor.mSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data to show for this node in the sidebar of the inspector. Each key will be a have its
|
||||||
|
* own section
|
||||||
|
*/
|
||||||
|
open fun onGetData(node: T, attributeSections: MutableMap<SectionName, InspectableObject>) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.descriptors
|
|
||||||
|
|
||||||
abstract class Descriptor<T> : NodeDescriptor<T> {
|
|
||||||
var descritorRegister: DescriptorRegister? = null
|
|
||||||
fun setDescriptorRegister(descriptorMapping: DescriptorRegister) {
|
|
||||||
this.descritorRegister = descriptorMapping
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun descriptorForClass(clazz: Class<*>): Descriptor<*>? {
|
|
||||||
descritorRegister?.let { register ->
|
|
||||||
return register.descriptorForClass(clazz)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun descriptorForObject(obj: Any): Descriptor<*>? {
|
|
||||||
descritorRegister?.let { register ->
|
|
||||||
return register.descriptorForClass(obj::class.java)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,7 @@ import com.facebook.flipper.plugins.uidebugger.common.UIDebuggerException
|
|||||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||||
|
|
||||||
class DescriptorRegister {
|
class DescriptorRegister {
|
||||||
private val register: MutableMap<Class<*>, Descriptor<*>> = HashMap()
|
private val register: MutableMap<Class<*>, NodeDescriptor<*>> = HashMap()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@@ -35,40 +35,37 @@ class DescriptorRegister {
|
|||||||
mapping.register(ViewPager::class.java, ViewPagerDescriptor)
|
mapping.register(ViewPager::class.java, ViewPagerDescriptor)
|
||||||
|
|
||||||
for (clazz in mapping.register.keys) {
|
for (clazz in mapping.register.keys) {
|
||||||
val descriptor: Descriptor<*>? = mapping.register[clazz]
|
val descriptor: NodeDescriptor<*>? = mapping.register[clazz]
|
||||||
descriptor?.let { descriptor ->
|
descriptor?.let { descriptor ->
|
||||||
if (descriptor is ChainedDescriptor<*>) {
|
if (descriptor is ChainedDescriptor<*>) {
|
||||||
val chainedDescriptor = descriptor as ChainedDescriptor<Any>
|
val chainedDescriptor = descriptor as ChainedDescriptor<Any>
|
||||||
val superClass: Class<*> = clazz.getSuperclass()
|
val superClass: Class<*> = clazz.getSuperclass()
|
||||||
val superDescriptor: Descriptor<*>? = mapping.descriptorForClass(superClass)
|
val superDescriptor: NodeDescriptor<*>? = mapping.descriptorForClass(superClass)
|
||||||
superDescriptor?.let { superDescriptor ->
|
// todo we should walk all the way up the superclass hierarchy?
|
||||||
chainedDescriptor.setSuper(superDescriptor as Descriptor<Any>)
|
if (superDescriptor is ChainedDescriptor<*>) {
|
||||||
|
chainedDescriptor.setSuper(superDescriptor as ChainedDescriptor<Any>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (descriptor in mapping.register.values) {
|
|
||||||
descriptor.setDescriptorRegister(mapping)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapping
|
return mapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> register(clazz: Class<T>, descriptor: Descriptor<T>) {
|
fun <T> register(clazz: Class<T>, descriptor: NodeDescriptor<T>) {
|
||||||
register[clazz] = descriptor
|
register[clazz] = descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> descriptorForClass(clazz: Class<T>): Descriptor<T>? {
|
fun <T> descriptorForClass(clazz: Class<T>): NodeDescriptor<T>? {
|
||||||
var clazz: Class<*> = clazz
|
var clazz: Class<*> = clazz
|
||||||
while (!register.containsKey(clazz)) {
|
while (!register.containsKey(clazz)) {
|
||||||
clazz = clazz.superclass
|
clazz = clazz.superclass
|
||||||
}
|
}
|
||||||
return register[clazz] as Descriptor<T>
|
return register[clazz] as NodeDescriptor<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> descriptorForClassUnsafe(clazz: Class<T>): Descriptor<T> {
|
fun <T> descriptorForClassUnsafe(clazz: Class<T>): NodeDescriptor<T> {
|
||||||
return descriptorForClass(clazz)
|
return descriptorForClass(clazz)
|
||||||
?: throw UIDebuggerException("No descriptor found for ${clazz.name}")
|
?: throw UIDebuggerException("No descriptor found for ${clazz.name}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Descriptors are an extension point used during traversal to extract data out of arbitary
|
Descriptors are an extension point used during traversal to extract data out of arbitrary
|
||||||
objects in the hierachy. Descriptors can represent native view or declarative components or
|
objects in the hierarchy. Descriptors can represent native view or declarative components or
|
||||||
any type of object such as an activity
|
any type of object such as an activity
|
||||||
|
|
||||||
Descriptors should be stateless and each descriptor should be a singleton
|
Descriptors should be stateless and each descriptor should be a singleton
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typealias SectionName = String
|
||||||
|
|
||||||
interface NodeDescriptor<T> {
|
interface NodeDescriptor<T> {
|
||||||
/**
|
/**
|
||||||
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
* A globally unique ID used to identify a node in a hierarchy. If your node does not have a
|
||||||
@@ -30,7 +33,7 @@ interface NodeDescriptor<T> {
|
|||||||
fun getName(node: T): String
|
fun getName(node: T): String
|
||||||
|
|
||||||
/** The children this node exposes in the inspector. */
|
/** The children this node exposes in the inspector. */
|
||||||
fun getChildren(node: T, children: MutableList<Any>)
|
fun getChildren(node: T): List<Any>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you have overlapping children this indicates which child is active / on top, we will only
|
* If you have overlapping children this indicates which child is active / on top, we will only
|
||||||
@@ -42,5 +45,5 @@ interface NodeDescriptor<T> {
|
|||||||
* Get the data to show for this node in the sidebar of the inspector. The object will be shown in
|
* Get the data to show for this node in the sidebar of the inspector. The object will be shown in
|
||||||
* order and with a header matching the given name.
|
* order and with a header matching the given name.
|
||||||
*/
|
*/
|
||||||
fun getData(node: T, builder: MutableMap<String, InspectableObject>)
|
fun getData(node: T): Map<SectionName, InspectableObject>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
|
||||||
object ObjectDescriptor : Descriptor<Any>() {
|
object ObjectDescriptor : NodeDescriptor<Any> {
|
||||||
|
|
||||||
override fun getActiveChild(node: Any): Any? = null
|
override fun getActiveChild(node: Any): Any? = null
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ object ObjectDescriptor : Descriptor<Any>() {
|
|||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getChildren(node: Any, children: MutableList<Any>) {}
|
override fun getChildren(node: Any) = listOf<Any>()
|
||||||
|
|
||||||
override fun getData(node: Any, builder: MutableMap<String, InspectableObject>) {}
|
override fun getData(node: Any) = mutableMapOf<SectionName, InspectableObject>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
|
||||||
object TextViewDescriptor : AbstractChainedDescriptor<TextView>() {
|
object TextViewDescriptor : ChainedDescriptor<TextView>() {
|
||||||
|
|
||||||
override fun onGetId(node: TextView): String {
|
override fun onGetId(node: TextView): String {
|
||||||
return System.identityHashCode(node).toString()
|
return System.identityHashCode(node).toString()
|
||||||
@@ -22,6 +22,6 @@ object TextViewDescriptor : AbstractChainedDescriptor<TextView>() {
|
|||||||
|
|
||||||
override fun onGetData(
|
override fun onGetData(
|
||||||
node: TextView,
|
node: TextView,
|
||||||
attributeSections: MutableMap<String, InspectableObject>
|
attributeSections: MutableMap<SectionName, InspectableObject>
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import com.facebook.flipper.plugins.uidebugger.stetho.ResourcesUtil
|
|||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
@SuppressLint("DiscouragedPrivateApi")
|
@SuppressLint("DiscouragedPrivateApi")
|
||||||
object ViewDescriptor : AbstractChainedDescriptor<View>() {
|
object ViewDescriptor : ChainedDescriptor<View>() {
|
||||||
|
|
||||||
override fun onGetId(node: View): String {
|
override fun onGetId(node: View): String {
|
||||||
return Integer.toBinaryString(System.identityHashCode(node))
|
return Integer.toBinaryString(System.identityHashCode(node))
|
||||||
@@ -34,7 +34,10 @@ object ViewDescriptor : AbstractChainedDescriptor<View>() {
|
|||||||
return node.javaClass.simpleName
|
return node.javaClass.simpleName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetData(node: View, attributeSections: MutableMap<String, InspectableObject>) {
|
override fun onGetData(
|
||||||
|
node: View,
|
||||||
|
attributeSections: MutableMap<SectionName, InspectableObject>
|
||||||
|
) {
|
||||||
val positionOnScreen = IntArray(2)
|
val positionOnScreen = IntArray(2)
|
||||||
node.getLocationOnScreen(positionOnScreen)
|
node.getLocationOnScreen(positionOnScreen)
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableValue
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableValue
|
||||||
import com.facebook.flipper.plugins.uidebugger.stetho.FragmentCompat
|
import com.facebook.flipper.plugins.uidebugger.stetho.FragmentCompat
|
||||||
|
|
||||||
object ViewGroupDescriptor : AbstractChainedDescriptor<ViewGroup>() {
|
object ViewGroupDescriptor : ChainedDescriptor<ViewGroup>() {
|
||||||
|
|
||||||
override fun onGetId(node: ViewGroup): String {
|
override fun onGetId(node: ViewGroup): String {
|
||||||
return System.identityHashCode(node).toString()
|
return System.identityHashCode(node).toString()
|
||||||
@@ -41,7 +41,7 @@ object ViewGroupDescriptor : AbstractChainedDescriptor<ViewGroup>() {
|
|||||||
|
|
||||||
override fun onGetData(
|
override fun onGetData(
|
||||||
node: ViewGroup,
|
node: ViewGroup,
|
||||||
attributeSections: MutableMap<String, InspectableObject>
|
attributeSections: MutableMap<SectionName, InspectableObject>
|
||||||
) {
|
) {
|
||||||
val viewGroupAttrs = mutableMapOf<String, Inspectable>()
|
val viewGroupAttrs = mutableMapOf<String, Inspectable>()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
|
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
|
||||||
object ViewPagerDescriptor : AbstractChainedDescriptor<ViewPager>() {
|
object ViewPagerDescriptor : ChainedDescriptor<ViewPager>() {
|
||||||
|
|
||||||
override fun onGetId(node: ViewPager): String = System.identityHashCode(node).toString()
|
override fun onGetId(node: ViewPager): String = System.identityHashCode(node).toString()
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ package com.facebook.flipper.plugins.uidebugger.descriptors
|
|||||||
|
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
|
|
||||||
object WindowDescriptor : AbstractChainedDescriptor<Window>() {
|
object WindowDescriptor : ChainedDescriptor<Window>() {
|
||||||
|
|
||||||
override fun onGetId(node: Window): String {
|
override fun onGetId(node: Window): String {
|
||||||
return System.identityHashCode(node).toString()
|
return System.identityHashCode(node).toString()
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ package com.facebook.flipper.plugins.uidebugger.observers
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Descriptor
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
import com.facebook.flipper.plugins.uidebugger.model.Node
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,7 +23,7 @@ class PartialLayoutTraversal(
|
|||||||
private val treeObserverfactory: TreeObserverFactory,
|
private val treeObserverfactory: TreeObserverFactory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal fun Descriptor<*>.asAny(): Descriptor<Any> = this as Descriptor<Any>
|
internal fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
||||||
|
|
||||||
fun traverse(root: Any): Pair<MutableList<Node>, List<Any>> {
|
fun traverse(root: Any): Pair<MutableList<Node>, List<Any>> {
|
||||||
|
|
||||||
@@ -47,8 +46,7 @@ class PartialLayoutTraversal(
|
|||||||
|
|
||||||
val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
||||||
|
|
||||||
val children = mutableListOf<Any>()
|
val children = descriptor.getChildren(node)
|
||||||
descriptor.getChildren(node, children)
|
|
||||||
|
|
||||||
val childrenIds = mutableListOf<String>()
|
val childrenIds = mutableListOf<String>()
|
||||||
val activeChild = descriptor.getActiveChild(node)
|
val activeChild = descriptor.getActiveChild(node)
|
||||||
@@ -71,8 +69,7 @@ class PartialLayoutTraversal(
|
|||||||
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass).getId(activeChild)
|
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass).getId(activeChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
val attributes = mutableMapOf<String, InspectableObject>()
|
val attributes = descriptor.getData(node)
|
||||||
descriptor.getData(node, attributes)
|
|
||||||
|
|
||||||
visited.add(
|
visited.add(
|
||||||
Node(
|
Node(
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ abstract class TreeObserver<T> {
|
|||||||
children[childKey]!!.cleanUpRecursive()
|
children[childKey]!!.cleanUpRecursive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send
|
||||||
|
Log.d(LogTag, "For Observer ${this.type} Sending ${visitedNodes.size} ")
|
||||||
context.treeObserverManager.send(
|
context.treeObserverManager.send(
|
||||||
SubtreeUpdate(type, visitedNodes, start, System.currentTimeMillis()))
|
SubtreeUpdate(type, visitedNodes, start, System.currentTimeMillis()))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user