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 45587ac50..0eafaf3ef 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 @@ -13,6 +13,7 @@ import com.facebook.flipper.plugins.uidebugger.LogTag import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver import com.facebook.flipper.plugins.uidebugger.core.UIDContext +import com.facebook.flipper.plugins.uidebugger.descriptors.Id import com.facebook.flipper.plugins.uidebugger.util.objectIdentity /** @@ -23,7 +24,7 @@ class ApplicationTreeObserver(val context: UIDContext) : TreeObserver() { override val type = "DecorView" - override fun subscribe(node: Any) { + override fun subscribe(node: Any, parentId: Id?) { node as View nodeRef = WeakReference(node) Log.i(LogTag, "Subscribing to decor view changes") context.sharedThrottle.registerCallback(this.objectIdentity()) { - nodeRef?.get()?.let { traverseAndSendWithSnapshot() } + nodeRef?.get()?.let { traverseAndSendWithSnapshot(parentId) } } preDrawListener = @@ -46,16 +47,21 @@ class DecorViewObserver(val context: UIDContext) : TreeObserver() { // It can be the case that the DecorView the current observer owns has already // drawn. In this case, manually trigger an update. - traverseAndSendWithSnapshot() + traverseAndSendWithSnapshot(parentId) } - private fun traverseAndSendWithSnapshot() { + private fun traverseAndSendWithSnapshot(parentId: Id?) { nodeRef?.get()?.let { view -> var snapshotBitmap: BitmapPool.ReusableBitmap? = null if (view.width > 0 && view.height > 0) { snapshotBitmap = context.bitmapPool.getBitmap(view.width, view.height) } - traverseAndSend(context, view, snapshotBitmap) + traverseAndSend( + parentId, + context, + view, + snapshotBitmap, + ) } } 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 061af2eaa..7e23a9b2d 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 @@ -35,35 +35,37 @@ abstract class TreeObserver { abstract val type: String - abstract fun subscribe(node: Any) + abstract fun subscribe(node: Any, parentId: Id?) abstract fun unsubscribe() /** Traverses the layout hierarchy while managing any encountered child observers. */ fun traverseAndSend( + parentId: Id?, context: UIDContext, root: Any, snapshotBitmap: BitmapPool.ReusableBitmap? = null, frameworkEvents: List? = null ) { val traversalStartTimestamp = System.currentTimeMillis() - val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root) + val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root, parentId) // Add any new observers - observableRoots.forEach { observable -> + observableRoots.forEach { (observable, parentId) -> if (!children.containsKey(observable.objectIdentity())) { context.observerFactory.createObserver(observable, context)?.let { observer -> Log.d( LogTag, "Observer ${this.type} discovered new child of type ${observer.type} Node ID ${observable.objectIdentity()}") - observer.subscribe(observable) + observer.subscribe(observable, parentId) children[observable.objectIdentity()] = observer } } } // Remove any old observers - val observableRootsIdentifiers = observableRoots.map { it.objectIdentity() } + val observableRootsIdentifiers = + observableRoots.map { (observable, _) -> observable.objectIdentity() } val removables = mutableListOf() children.keys.forEach { key -> if (!observableRootsIdentifiers.contains(key)) { 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 c46fe63b4..0d3722267 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 @@ -78,7 +78,7 @@ class TreeObserverManager(val context: UIDContext) { mainScope.launch { start() } } batchedUpdates = Channel(Channel.UNLIMITED) - rootObserver.subscribe(context.applicationRef) + rootObserver.subscribe(context.applicationRef, null) job = workerScope.launch { diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt index 60b2b207c..110019734 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt @@ -31,14 +31,14 @@ class PartialLayoutTraversal( @Suppress("unchecked_cast") internal fun NodeDescriptor<*>.asAny(): NodeDescriptor = this as NodeDescriptor - fun traverse(root: Any): Pair>, List> { + fun traverse(root: Any, parentId: Id?): Pair>, List>> { val visited = mutableListOf>() - val observableRoots = mutableListOf() + val observableRoots = mutableListOf>() // cur and parent Id val stack = mutableListOf>() - stack.add(Pair(root, null)) + stack.add(Pair(root, parentId)) val shallow = mutableSetOf() @@ -48,7 +48,7 @@ class PartialLayoutTraversal( try { // If we encounter a node that has it own observer, don't traverse if (node != root && treeObserverFactory.hasObserverFor(node)) { - observableRoots.add(node) + observableRoots.add((node to parentId)) continue }