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:
Luke De Feo
2022-09-14 05:07:51 -07:00
committed by Facebook GitHub Bot
parent f5a5e1b19d
commit 2090120cda
19 changed files with 156 additions and 195 deletions

View File

@@ -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>) {}
} }

View File

@@ -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(

View File

@@ -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))
} }
} }
} }

View File

@@ -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>) {}
}

View File

@@ -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()

View File

@@ -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? {

View File

@@ -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>
) {}
} }

View File

@@ -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>) {}
} }

View File

@@ -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
}
}

View File

@@ -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}")
} }

View File

@@ -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>
} }

View File

@@ -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>()
} }

View File

@@ -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>
) {} ) {}
} }

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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()

View File

@@ -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()

View File

@@ -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(

View File

@@ -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()))
} }