diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt index ba428ef3b..a6241e0f9 100644 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt +++ b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt @@ -7,13 +7,10 @@ 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.flipper.plugins.uidebugger.core.UIDContext // this is not used internally object UIDebuggerLithoSupport { - fun addDescriptors(register: DescriptorRegister) {} - - fun addObserver(observerFactory: TreeObserverFactory) {} + fun enable(context: UIDContext) {} } diff --git a/android/sample/src/debug/java/com/facebook/flipper/sample/FlipperInitializer.java b/android/sample/src/debug/java/com/facebook/flipper/sample/FlipperInitializer.java index 47aeb7353..fe1c38749 100644 --- a/android/sample/src/debug/java/com/facebook/flipper/sample/FlipperInitializer.java +++ b/android/sample/src/debug/java/com/facebook/flipper/sample/FlipperInitializer.java @@ -22,6 +22,7 @@ import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin.SharedPreferencesDescriptor; import com.facebook.flipper.plugins.uidebugger.UIDebuggerFlipperPlugin; +import com.facebook.flipper.plugins.uidebugger.core.UIDContext; import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister; import com.facebook.flipper.plugins.uidebugger.litho.UIDebuggerLithoSupport; import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory; @@ -62,12 +63,10 @@ public final class FlipperInitializer { DescriptorRegister descriptorRegister = DescriptorRegister.Companion.withDefaults(); TreeObserverFactory treeObserverFactory = TreeObserverFactory.Companion.withDefaults(); - UIDebuggerLithoSupport.INSTANCE.addDescriptors(descriptorRegister); - UIDebuggerLithoSupport.INSTANCE.addObserver(treeObserverFactory); + UIDContext uidContext = UIDContext.Companion.create((Application) context); + UIDebuggerLithoSupport.INSTANCE.enable(uidContext); - client.addPlugin( - new UIDebuggerFlipperPlugin( - (Application) context, descriptorRegister, treeObserverFactory)); + client.addPlugin(new UIDebuggerFlipperPlugin(uidContext)); client.start(); final OkHttpClient okHttpClient = 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 b5a5a1d66..791f3fed5 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 @@ -7,33 +7,19 @@ package com.facebook.flipper.plugins.uidebugger -import android.app.Application import android.util.Log import com.facebook.flipper.core.FlipperConnection import com.facebook.flipper.core.FlipperPlugin import com.facebook.flipper.plugins.uidebugger.core.* import com.facebook.flipper.plugins.uidebugger.descriptors.ApplicationRefDescriptor -import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister import com.facebook.flipper.plugins.uidebugger.model.InitEvent import com.facebook.flipper.plugins.uidebugger.model.MetadataUpdateEvent -import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory import kotlinx.serialization.json.Json const val LogTag = "ui-debugger" -class UIDebuggerFlipperPlugin( - val application: Application, - descriptorRegister: DescriptorRegister?, - observerFactory: TreeObserverFactory? -) : FlipperPlugin { - - private val context: Context = - Context( - ApplicationRef(application), - ConnectionRef(null), - descriptorRegister = descriptorRegister ?: DescriptorRegister.withDefaults(), - observerFactory = observerFactory ?: TreeObserverFactory.withDefaults()) +class UIDebuggerFlipperPlugin(val context: UIDContext) : FlipperPlugin { init { Log.i(LogTag, "Initializing ui-debugger") @@ -53,7 +39,9 @@ class UIDebuggerFlipperPlugin( InitEvent.name, Json.encodeToString( InitEvent.serializer(), - InitEvent(ApplicationRefDescriptor.getId(context.applicationRef)))) + InitEvent( + ApplicationRefDescriptor.getId(context.applicationRef), + context.frameworkEventMetadata))) connection.send( MetadataUpdateEvent.name, diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/commands/Command.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/commands/Command.kt index b442ef599..5a79866e5 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/commands/Command.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/commands/Command.kt @@ -11,10 +11,10 @@ import com.facebook.flipper.core.FlipperObject import com.facebook.flipper.core.FlipperReceiver import com.facebook.flipper.core.FlipperResponder import com.facebook.flipper.plugins.common.MainThreadFlipperReceiver -import com.facebook.flipper.plugins.uidebugger.core.Context +import com.facebook.flipper.plugins.uidebugger.core.UIDContext /** An interface for extensions to the UIDebugger plugin */ -abstract class Command(val context: Context) { +abstract class Command(val context: UIDContext) { /** The command identifier to respond to */ abstract fun identifier(): String /** Execute the command */ diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/Context.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt similarity index 68% rename from android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/Context.kt rename to android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt index 28a701bc8..3142b0193 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/Context.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt @@ -7,19 +7,22 @@ package com.facebook.flipper.plugins.uidebugger.core +import android.app.Application import com.facebook.flipper.core.FlipperConnection import com.facebook.flipper.plugins.uidebugger.common.BitmapPool import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister +import com.facebook.flipper.plugins.uidebugger.model.FrameworkEventMetadata import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverManager import com.facebook.flipper.plugins.uidebugger.scheduler.SharedThrottle import com.facebook.flipper.plugins.uidebugger.traversal.PartialLayoutTraversal -data class Context( +data class UIDContext( val applicationRef: ApplicationRef, val connectionRef: ConnectionRef, val descriptorRegister: DescriptorRegister, val observerFactory: TreeObserverFactory, + val frameworkEventMetadata: MutableList ) { val layoutTraversal: PartialLayoutTraversal = PartialLayoutTraversal(descriptorRegister, observerFactory) @@ -27,6 +30,17 @@ data class Context( val treeObserverManager = TreeObserverManager(this) val sharedThrottle: SharedThrottle = SharedThrottle() val bitmapPool = BitmapPool() + + companion object { + fun create(application: Application): UIDContext { + return UIDContext( + ApplicationRef(application), + ConnectionRef(null), + descriptorRegister = DescriptorRegister.withDefaults(), + observerFactory = TreeObserverFactory.withDefaults(), + frameworkEventMetadata = mutableListOf()) + } + } } data class ConnectionRef(var connection: FlipperConnection?) diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt index 7d39bb1dc..4fca29a9b 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt @@ -10,9 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.model import com.facebook.flipper.plugins.uidebugger.descriptors.Id @kotlinx.serialization.Serializable -data class InitEvent( - val rootId: Id, -) { +data class InitEvent(val rootId: Id, val frameworkEventMetadata: List) { companion object { const val name = "init" } @@ -31,7 +29,8 @@ data class SubtreeUpdateEvent( val observerType: String, val rootId: Id, val nodes: List, - val snapshot: String? = null + val snapshot: String?, + val frameworkEvents: List? ) { companion object { const val name = "subtreeUpdate" diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt new file mode 100644 index 000000000..76ebbea04 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt @@ -0,0 +1,23 @@ +/* + * 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.model + +import com.facebook.flipper.plugins.uidebugger.descriptors.Id + +@kotlinx.serialization.Serializable +data class FrameworkEventMetadata( + val type: String, + val documentation: String, +) + +@kotlinx.serialization.Serializable +data class FrameworkEvent( + val nodeId: Id, + val type: String, + val timestamp: Long, +) diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/ApplicationTreeObserver.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/ApplicationTreeObserver.kt index 6c81b1f6b..45587ac50 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/ApplicationTreeObserver.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/ApplicationTreeObserver.kt @@ -11,15 +11,15 @@ import android.util.Log import android.view.View import com.facebook.flipper.plugins.uidebugger.LogTag import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef -import com.facebook.flipper.plugins.uidebugger.core.Context import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver +import com.facebook.flipper.plugins.uidebugger.core.UIDContext import com.facebook.flipper.plugins.uidebugger.util.objectIdentity /** * Responsible for observing the activity stack and managing the subscription to the top most * content view (decor view) */ -class ApplicationTreeObserver(val context: Context) : TreeObserver() { +class ApplicationTreeObserver(val context: UIDContext) : TreeObserver() { override val type = "Application" diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/DecorViewTreeObserver.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/DecorViewTreeObserver.kt index 72b92e754..e036ea4f3 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/DecorViewTreeObserver.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/DecorViewTreeObserver.kt @@ -12,14 +12,14 @@ import android.view.View import android.view.ViewTreeObserver import com.facebook.flipper.plugins.uidebugger.LogTag import com.facebook.flipper.plugins.uidebugger.common.BitmapPool -import com.facebook.flipper.plugins.uidebugger.core.Context +import com.facebook.flipper.plugins.uidebugger.core.UIDContext import com.facebook.flipper.plugins.uidebugger.util.objectIdentity import java.lang.ref.WeakReference typealias DecorView = View /** Responsible for subscribing to updates to the content view of an activity */ -class DecorViewObserver(val context: Context) : TreeObserver() { +class DecorViewObserver(val context: UIDContext) : TreeObserver() { private var nodeRef: WeakReference? = null private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null @@ -78,7 +78,7 @@ object DecorViewTreeObserverBuilder : TreeObserverBuilder { return node.javaClass.simpleName.contains("DecorView") } - override fun build(context: Context): TreeObserver { + override fun build(context: UIDContext): TreeObserver { Log.i(LogTag, "Building DecorView observer") return DecorViewObserver(context) } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserver.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserver.kt index b1ab98226..8cab32093 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserver.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserver.kt @@ -10,9 +10,10 @@ package com.facebook.flipper.plugins.uidebugger.observers import android.util.Log import com.facebook.flipper.plugins.uidebugger.LogTag import com.facebook.flipper.plugins.uidebugger.common.BitmapPool -import com.facebook.flipper.plugins.uidebugger.core.Context +import com.facebook.flipper.plugins.uidebugger.core.UIDContext import com.facebook.flipper.plugins.uidebugger.descriptors.Id import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor +import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent import com.facebook.flipper.plugins.uidebugger.util.objectIdentity /* @@ -40,9 +41,10 @@ abstract class TreeObserver { /** Traverses the layout hierarchy while managing any encountered child observers. */ fun traverseAndSend( - context: Context, + context: UIDContext, root: Any, - snapshotBitmap: BitmapPool.ReusableBitmap? = null + snapshotBitmap: BitmapPool.ReusableBitmap? = null, + frameworkEvents: List? = null ) { val startTimestamp = System.currentTimeMillis() val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root) @@ -97,6 +99,7 @@ abstract class TreeObserver { startTimestamp, traversalCompleteTime, snapshotCompleteTime, + frameworkEvents, snapshotBitmap)) } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverFactory.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverFactory.kt index b4b0bd5fa..769a09813 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverFactory.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverFactory.kt @@ -7,11 +7,11 @@ package com.facebook.flipper.plugins.uidebugger.observers -import com.facebook.flipper.plugins.uidebugger.core.Context +import com.facebook.flipper.plugins.uidebugger.core.UIDContext interface TreeObserverBuilder { fun canBuildFor(node: Any): Boolean - fun build(context: Context): TreeObserver + fun build(context: UIDContext): TreeObserver } class TreeObserverFactory { @@ -28,7 +28,7 @@ class TreeObserverFactory { } // TODO: Not very efficient, need to cache this. Builders cannot be removed. - fun createObserver(node: Any, context: Context): TreeObserver<*>? { + fun createObserver(node: Any, context: UIDContext): TreeObserver<*>? { return builders.find { it.canBuildFor(node) }?.build(context) } diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt index 2e3649ab4..17f8545ad 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt @@ -16,9 +16,10 @@ import android.util.Log import android.view.Choreographer import com.facebook.flipper.plugins.uidebugger.LogTag import com.facebook.flipper.plugins.uidebugger.common.BitmapPool -import com.facebook.flipper.plugins.uidebugger.core.Context +import com.facebook.flipper.plugins.uidebugger.core.UIDContext import com.facebook.flipper.plugins.uidebugger.descriptors.Id import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister +import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent import com.facebook.flipper.plugins.uidebugger.model.MetadataUpdateEvent import com.facebook.flipper.plugins.uidebugger.model.Node import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent @@ -37,13 +38,14 @@ data class SubtreeUpdate( val startTime: Long, val traversalCompleteTime: Long, val snapshotComplete: Long, + val frameworkEvents: List?, val snapshot: BitmapPool.ReusableBitmap? ) data class BatchedUpdate(val updates: List, val frameTimeMs: Long) /** Holds the root observer and manages sending updates to desktop */ -class TreeObserverManager(val context: Context) { +class TreeObserverManager(val context: UIDContext) { private val rootObserver = ApplicationTreeObserver(context) private lateinit var batchedUpdates: Channel @@ -104,6 +106,7 @@ class TreeObserverManager(val context: Context) { val onWorkerThread = System.currentTimeMillis() val nodes = batchedUpdate.updates.flatMap { it.deferredNodes.map { it.value() } } + val frameworkEvents = batchedUpdate.updates.flatMap { it.frameworkEvents ?: listOf() } val snapshotUpdate = batchedUpdate.updates.find { it.snapshot != null } val deferredComptationComplete = System.currentTimeMillis() @@ -116,13 +119,20 @@ class TreeObserverManager(val context: Context) { snapshotUpdate.snapshot.readyForReuse() } + // it is important this comes after deferred processing since the deferred processing can create + // metadata sendMetadata() val serialized = Json.encodeToString( SubtreeUpdateEvent.serializer(), SubtreeUpdateEvent( - batchedUpdate.frameTimeMs, "batched", snapshotUpdate?.rootId ?: 1, nodes, snapshot)) + batchedUpdate.frameTimeMs, + "batched", + snapshotUpdate?.rootId ?: 1, + nodes, + snapshot, + frameworkEvents)) val serializationEnd = System.currentTimeMillis() diff --git a/android/src/test/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPluginTest.kt b/android/src/test/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPluginTest.kt index a8bda3c79..a7ba21948 100644 --- a/android/src/test/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPluginTest.kt +++ b/android/src/test/java/com/facebook/flipper/plugins/uidebugger/UIDebuggerFlipperPluginTest.kt @@ -8,8 +8,7 @@ package com.facebook.flipper.plugins.uidebugger 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 com.facebook.flipper.plugins.uidebugger.core.UIDContext import org.junit.Assert import org.junit.Before import org.junit.Test @@ -32,11 +31,7 @@ class UIDebuggerFlipperPluginTest { @Throws(Exception::class) @Test fun emptyTest() { - var plugin = - UIDebuggerFlipperPlugin( - app, - DescriptorRegister.Companion.withDefaults(), - TreeObserverFactory.Companion.withDefaults()) + var plugin = UIDebuggerFlipperPlugin(UIDContext.create(app)) Assert.assertNotNull(plugin) } }