Basic Litho support
Summary: Added an initial litho Tree observer and descriptors, its quiet naive and will be improved in a future diff Reviewed By: lblasa Differential Revision: D39466931 fbshipit-source-id: 66a462882af2e585b9719ee2f61595449f99c5e5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
24ec43eb92
commit
0562178739
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.compileSdkVersion
|
compileSdkVersion rootProject.compileSdkVersion
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.litho
|
||||||
|
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.common.InspectableObject
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Descriptor
|
||||||
|
import com.facebook.litho.DebugComponent
|
||||||
|
import com.facebook.litho.LithoView
|
||||||
|
|
||||||
|
object LithoViewDescriptor : Descriptor<LithoView>() {
|
||||||
|
override fun getId(node: LithoView): String = System.identityHashCode(node).toString()
|
||||||
|
|
||||||
|
override fun getName(node: LithoView): String = "LithoView"
|
||||||
|
|
||||||
|
override fun getChildren(node: LithoView, children: MutableList<Any>) {
|
||||||
|
val debugComponent = DebugComponent.getRootInstance(node)
|
||||||
|
if (debugComponent != null) {
|
||||||
|
children.add(debugComponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActiveChild(node: LithoView): Any? = null
|
||||||
|
|
||||||
|
override fun getData(node: LithoView, builder: MutableMap<String, InspectableObject>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
object DebugComponentDescriptor : Descriptor<DebugComponent>() {
|
||||||
|
override fun getId(node: DebugComponent): String = System.identityHashCode(node).toString()
|
||||||
|
|
||||||
|
override fun getName(node: DebugComponent): String {
|
||||||
|
return node.component.simpleName
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO the mutable list thing doesnt make sense for non chained descriptors, should just return
|
||||||
|
override fun getChildren(node: DebugComponent, children: MutableList<Any>) {
|
||||||
|
val mountedView = node.mountedView
|
||||||
|
val mountedDrawable = node.mountedDrawable
|
||||||
|
|
||||||
|
if (mountedView != null) {
|
||||||
|
children.add(mountedView)
|
||||||
|
} else if (mountedDrawable != null) {
|
||||||
|
children.add(mountedDrawable)
|
||||||
|
} else {
|
||||||
|
for (child in node.childComponents) {
|
||||||
|
children.add(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActiveChild(node: DebugComponent): Any? = null
|
||||||
|
|
||||||
|
// todo same here
|
||||||
|
override fun getData(node: DebugComponent, builder: MutableMap<String, InspectableObject>) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.facebook.flipper.plugins.uidebugger.litho
|
||||||
|
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.SubtreeUpdate
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.TreeObserver
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.identityHashCode
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverBuilder
|
||||||
|
import com.facebook.litho.LithoView
|
||||||
|
|
||||||
|
class LithoViewTreeObserver(val context: Context) : TreeObserver<LithoView>() {
|
||||||
|
|
||||||
|
var nodeRef: LithoView? = null
|
||||||
|
override fun subscribe(node: Any) {
|
||||||
|
node as LithoView
|
||||||
|
|
||||||
|
nodeRef = node
|
||||||
|
|
||||||
|
val listener: (view: LithoView) -> Unit = {
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
|
val (nodes, skipped) = context.layoutTraversal.traverse(it)
|
||||||
|
|
||||||
|
for (observerRoot in skipped) {
|
||||||
|
if (!children.containsKey(observerRoot.identityHashCode())) {
|
||||||
|
val observer = context.observerFactory.createObserver(observerRoot, context)!!
|
||||||
|
observer.subscribe(observerRoot)
|
||||||
|
children[observerRoot.identityHashCode()] = observer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.treeObserverManager.emit(
|
||||||
|
SubtreeUpdate("Litho", nodes, start, System.currentTimeMillis()))
|
||||||
|
}
|
||||||
|
node.setOnDirtyMountListener(listener)
|
||||||
|
|
||||||
|
listener(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unsubscribe() {
|
||||||
|
nodeRef?.setOnDirtyMountListener(null)
|
||||||
|
nodeRef = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object LithoViewTreeObserverBuilder : TreeObserverBuilder<LithoView> {
|
||||||
|
override fun canBuildFor(node: Any): Boolean {
|
||||||
|
return node is LithoView
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun build(context: Context): TreeObserver<LithoView> {
|
||||||
|
return LithoViewTreeObserver(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.litho
|
||||||
|
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||||
|
import com.facebook.litho.DebugComponent
|
||||||
|
import com.facebook.litho.LithoView
|
||||||
|
|
||||||
|
object UIDebuggerLithoSupport {
|
||||||
|
|
||||||
|
fun addDescriptors(register: DescriptorRegister) {
|
||||||
|
register.register(LithoView::class.java, LithoViewDescriptor)
|
||||||
|
register.register(DebugComponent::class.java, DebugComponentDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addObserver(observerFactory: TreeObserverFactory) {
|
||||||
|
observerFactory.register(LithoViewTreeObserverBuilder)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,9 @@ import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
|||||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin.SharedPreferencesDescriptor;
|
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin.SharedPreferencesDescriptor;
|
||||||
import com.facebook.flipper.plugins.uidebugger.UIDebuggerFlipperPlugin;
|
import com.facebook.flipper.plugins.uidebugger.UIDebuggerFlipperPlugin;
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister;
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.litho.UIDebuggerLithoSupport;
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory;
|
||||||
import com.facebook.litho.config.ComponentsConfiguration;
|
import com.facebook.litho.config.ComponentsConfiguration;
|
||||||
import com.facebook.litho.editor.flipper.LithoFlipperDescriptors;
|
import com.facebook.litho.editor.flipper.LithoFlipperDescriptors;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -56,7 +59,15 @@ public final class FlipperInitializer {
|
|||||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
client.addPlugin(CrashReporterPlugin.getInstance());
|
||||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
client.addPlugin(new DatabasesFlipperPlugin(context));
|
||||||
client.addPlugin(NavigationFlipperPlugin.getInstance());
|
client.addPlugin(NavigationFlipperPlugin.getInstance());
|
||||||
client.addPlugin(new UIDebuggerFlipperPlugin((Application) context));
|
|
||||||
|
DescriptorRegister descriptorRegister = DescriptorRegister.Companion.withDefaults();
|
||||||
|
TreeObserverFactory treeObserverFactory = TreeObserverFactory.Companion.withDefaults();
|
||||||
|
UIDebuggerLithoSupport.INSTANCE.addDescriptors(descriptorRegister);
|
||||||
|
UIDebuggerLithoSupport.INSTANCE.addObserver(treeObserverFactory);
|
||||||
|
|
||||||
|
client.addPlugin(
|
||||||
|
new UIDebuggerFlipperPlugin(
|
||||||
|
(Application) context, descriptorRegister, treeObserverFactory));
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
final OkHttpClient okHttpClient =
|
final OkHttpClient okHttpClient =
|
||||||
|
|||||||
@@ -21,14 +21,18 @@ import kotlinx.serialization.json.Json
|
|||||||
|
|
||||||
const val LogTag = "FlipperUIDebugger"
|
const val LogTag = "FlipperUIDebugger"
|
||||||
|
|
||||||
class UIDebuggerFlipperPlugin(val application: Application) : FlipperPlugin {
|
class UIDebuggerFlipperPlugin(
|
||||||
|
val application: Application,
|
||||||
|
descriptorRegister: DescriptorRegister?,
|
||||||
|
observerFactory: TreeObserverFactory?
|
||||||
|
) : FlipperPlugin {
|
||||||
|
|
||||||
private val context: Context =
|
private val context: Context =
|
||||||
Context(
|
Context(
|
||||||
ApplicationRef(application),
|
ApplicationRef(application),
|
||||||
ConnectionRef(null),
|
ConnectionRef(null),
|
||||||
DescriptorRegister.withDefaults(),
|
descriptorRegister = descriptorRegister ?: DescriptorRegister.withDefaults(),
|
||||||
TreeObserverFactory.withDefaults())
|
observerFactory = observerFactory ?: TreeObserverFactory.withDefaults())
|
||||||
|
|
||||||
private val nativeScanScheduler = Scheduler(NativeScanScheduler(context))
|
private val nativeScanScheduler = Scheduler(NativeScanScheduler(context))
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.facebook.flipper.plugins.uidebugger.LogTag
|
|||||||
import com.facebook.flipper.plugins.uidebugger.SubtreeUpdate
|
import com.facebook.flipper.plugins.uidebugger.SubtreeUpdate
|
||||||
import com.facebook.flipper.plugins.uidebugger.TreeObserver
|
import com.facebook.flipper.plugins.uidebugger.TreeObserver
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.identityHashCode
|
||||||
|
|
||||||
typealias DecorView = View
|
typealias DecorView = View
|
||||||
|
|
||||||
@@ -40,6 +41,16 @@ class DecorViewObserver(val context: Context) : TreeObserver<DecorView>() {
|
|||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
if (start - lastSend > throttleTimeMs) {
|
if (start - lastSend > throttleTimeMs) {
|
||||||
val (nodes, skipped) = context.layoutTraversal.traverse(node)
|
val (nodes, skipped) = context.layoutTraversal.traverse(node)
|
||||||
|
|
||||||
|
for (observerRoot in skipped) {
|
||||||
|
|
||||||
|
if (!children.containsKey(observerRoot.identityHashCode())) {
|
||||||
|
val observer = context.observerFactory.createObserver(observerRoot, context)!!
|
||||||
|
observer.subscribe(observerRoot)
|
||||||
|
children[observerRoot.identityHashCode()] = observer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val traversalComplete = System.currentTimeMillis()
|
val traversalComplete = System.currentTimeMillis()
|
||||||
context.treeObserverManager.emit(
|
context.treeObserverManager.emit(
|
||||||
SubtreeUpdate("DecorView", nodes, start, traversalComplete))
|
SubtreeUpdate("DecorView", nodes, start, traversalComplete))
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
package com.facebook.flipper.plugins.uidebugger
|
package com.facebook.flipper.plugins.uidebugger
|
||||||
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -30,7 +32,11 @@ class UIDebuggerFlipperPluginTest {
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
@Test
|
@Test
|
||||||
fun emptyTest() {
|
fun emptyTest() {
|
||||||
var plugin = UIDebuggerFlipperPlugin(app)
|
var plugin =
|
||||||
|
UIDebuggerFlipperPlugin(
|
||||||
|
app,
|
||||||
|
DescriptorRegister.Companion.withDefaults(),
|
||||||
|
TreeObserverFactory.Companion.withDefaults())
|
||||||
Assert.assertNotNull(plugin)
|
Assert.assertNotNull(plugin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user