Extracted snapshot out of descriptor
Summary: Snapshot never made much sense in the descriptor since we only snapshot the decor views. Additionally in the next diff i will introduce a new way to snapshot so this will make it easier Reviewed By: lblasa Differential Revision: D50845280 fbshipit-source-id: c2eac351b72786e7b66951d0fa09cea52a6dcc69
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c93c494ef4
commit
6bf93347ee
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.jetpackcompose.descriptors
|
package com.facebook.flipper.plugins.jetpackcompose.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.facebook.flipper.plugins.jetpackcompose.model.ComposeInnerViewNode
|
import com.facebook.flipper.plugins.jetpackcompose.model.ComposeInnerViewNode
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
@@ -49,13 +48,6 @@ object ComposeInnerViewDescriptor : NodeDescriptor<ComposeInnerViewNode> {
|
|||||||
return ViewDescriptor.getChildren(node.view)
|
return ViewDescriptor.getChildren(node.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSnapshot(node: ComposeInnerViewNode, bitmap: Bitmap?): Bitmap? {
|
|
||||||
if (node.view is ViewGroup) {
|
|
||||||
return ViewGroupDescriptor.getSnapshot(node.view, bitmap)
|
|
||||||
}
|
|
||||||
return ViewDescriptor.getSnapshot(node.view, bitmap)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getActiveChild(node: ComposeInnerViewNode): Any? {
|
override fun getActiveChild(node: ComposeInnerViewNode): Any? {
|
||||||
if (node.view is ViewGroup) {
|
if (node.view is ViewGroup) {
|
||||||
return ViewGroupDescriptor.getActiveChild(node.view)
|
return ViewGroupDescriptor.getActiveChild(node.view)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.jetpackcompose.descriptors
|
package com.facebook.flipper.plugins.jetpackcompose.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import com.facebook.flipper.plugins.jetpackcompose.model.ComposeNode
|
import com.facebook.flipper.plugins.jetpackcompose.model.ComposeNode
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.BaseTags
|
import com.facebook.flipper.plugins.uidebugger.descriptors.BaseTags
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
@@ -130,8 +129,6 @@ object ComposeNodeDescriptor : NodeDescriptor<ComposeNode> {
|
|||||||
|
|
||||||
override fun getQualifiedName(node: ComposeNode): String = node.inspectorNode.name
|
override fun getQualifiedName(node: ComposeNode): String = node.inspectorNode.name
|
||||||
|
|
||||||
override fun getSnapshot(node: ComposeNode, bitmap: Bitmap?): Bitmap? = null
|
|
||||||
|
|
||||||
override fun getActiveChild(node: ComposeNode): Any? = null
|
override fun getActiveChild(node: ComposeNode): Any? = null
|
||||||
|
|
||||||
override fun getTags(node: ComposeNode): Set<String> = setOf(BaseTags.Android, "Compose")
|
override fun getTags(node: ComposeNode): Set<String> = setOf(BaseTags.Android, "Compose")
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import kotlinx.coroutines.launch
|
|||||||
class BitmapPool(private val config: Bitmap.Config = Bitmap.Config.RGB_565) {
|
class BitmapPool(private val config: Bitmap.Config = Bitmap.Config.RGB_565) {
|
||||||
|
|
||||||
interface ReusableBitmap {
|
interface ReusableBitmap {
|
||||||
val bitmap: Bitmap?
|
val bitmap: Bitmap
|
||||||
|
|
||||||
fun readyForReuse()
|
fun readyForReuse()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.util.Log
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.ViewDescriptor
|
import com.facebook.flipper.plugins.uidebugger.descriptors.ViewDescriptor
|
||||||
import com.facebook.flipper.plugins.uidebugger.util.StopWatch
|
import com.facebook.flipper.plugins.uidebugger.util.StopWatch
|
||||||
import com.facebook.flipper.plugins.uidebugger.util.Throttler
|
import com.facebook.flipper.plugins.uidebugger.util.Throttler
|
||||||
@@ -22,7 +21,7 @@ import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
|||||||
* to it This predraw observer triggers a full traversal of the UI. There should only ever be one
|
* to it This predraw observer triggers a full traversal of the UI. There should only ever be one
|
||||||
* active predraw listener at once
|
* active predraw listener at once
|
||||||
*/
|
*/
|
||||||
class DecorViewTracker(val context: UIDContext) {
|
class DecorViewTracker(private val context: UIDContext, private val snapshotter: Snapshotter) {
|
||||||
|
|
||||||
private var currentDecorView: View? = null
|
private var currentDecorView: View? = null
|
||||||
private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
|
private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
|
||||||
@@ -88,18 +87,7 @@ class DecorViewTracker(val context: UIDContext) {
|
|||||||
val (nodes, traversalTime) =
|
val (nodes, traversalTime) =
|
||||||
StopWatch.time { context.layoutTraversal.traverse(context.applicationRef) }
|
StopWatch.time { context.layoutTraversal.traverse(context.applicationRef) }
|
||||||
|
|
||||||
mStopWatch.start()
|
val (reusableBitmap, snapshotMs) = StopWatch.time { snapshotter.takeSnapshot(decorView) }
|
||||||
var snapshotBitmap: BitmapPool.ReusableBitmap? = null
|
|
||||||
if (decorView.width > 0 && decorView.height > 0) {
|
|
||||||
snapshotBitmap = context.bitmapPool.getBitmap(decorView.width, decorView.height)
|
|
||||||
context.bitmapPool.getBitmap(decorView.width, decorView.height)
|
|
||||||
Log.i(
|
|
||||||
LogTag,
|
|
||||||
"Snapshotting view ${ViewDescriptor.getId(decorView)}",
|
|
||||||
)
|
|
||||||
ViewDescriptor.getSnapshot(decorView, snapshotBitmap.bitmap)
|
|
||||||
}
|
|
||||||
val snapshotTime = mStopWatch.stop()
|
|
||||||
|
|
||||||
context.updateQueue.enqueueUpdate(
|
context.updateQueue.enqueueUpdate(
|
||||||
Update(
|
Update(
|
||||||
@@ -107,8 +95,8 @@ class DecorViewTracker(val context: UIDContext) {
|
|||||||
nodes,
|
nodes,
|
||||||
startTimestamp,
|
startTimestamp,
|
||||||
traversalTime,
|
traversalTime,
|
||||||
snapshotTime,
|
snapshotMs,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
snapshotBitmap))
|
reusableBitmap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.core
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||||
|
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||||
|
|
||||||
|
interface Snapshotter {
|
||||||
|
fun takeSnapshot(view: View): BitmapPool.ReusableBitmap?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a snapshot by redrawing the view into a bitmap backed canvas, Since this is software
|
||||||
|
* rendering there can be discrepancies between the real image and the snapshot:
|
||||||
|
* 1. It can be unreliable when snapshotting views that are added directly to window manager
|
||||||
|
* 2. It doesnt include certain types of content (video / images)
|
||||||
|
*/
|
||||||
|
class CanvasSnapshotter(private val bitmapPool: BitmapPool) : Snapshotter {
|
||||||
|
override fun takeSnapshot(view: View): BitmapPool.ReusableBitmap? {
|
||||||
|
|
||||||
|
if (view.width <= 0 || view.height <= 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val reuseAbleBitmap = bitmapPool.getBitmap(view.width, view.height)
|
||||||
|
val canvas = Canvas(reuseAbleBitmap.bitmap)
|
||||||
|
view.draw(canvas)
|
||||||
|
reuseAbleBitmap
|
||||||
|
} catch (e: OutOfMemoryError) {
|
||||||
|
Log.e(LogTag, "OOM when taking snapshot")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,12 +31,11 @@ class UIDContext(
|
|||||||
private val pendingFrameworkEvents: MutableList<FrameworkEvent>
|
private val pendingFrameworkEvents: MutableList<FrameworkEvent>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val decorViewTracker = DecorViewTracker(this)
|
val bitmapPool = BitmapPool()
|
||||||
|
val decorViewTracker = DecorViewTracker(this, CanvasSnapshotter(bitmapPool))
|
||||||
val updateQueue = UpdateQueue(this)
|
val updateQueue = UpdateQueue(this)
|
||||||
val layoutTraversal: LayoutTraversal = LayoutTraversal(this)
|
val layoutTraversal: LayoutTraversal = LayoutTraversal(this)
|
||||||
|
|
||||||
val bitmapPool = BitmapPool()
|
|
||||||
|
|
||||||
fun addFrameworkEvent(frameworkEvent: FrameworkEvent) {
|
fun addFrameworkEvent(frameworkEvent: FrameworkEvent) {
|
||||||
synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) }
|
synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||||
@@ -133,15 +132,6 @@ abstract class ChainedDescriptor<T> : NodeDescriptor<T> {
|
|||||||
*/
|
*/
|
||||||
open fun onGetAttributes(node: T, attributeSections: MutableMap<MetadataId, InspectableObject>) {}
|
open fun onGetAttributes(node: T, attributeSections: MutableMap<MetadataId, InspectableObject>) {}
|
||||||
|
|
||||||
/** Get a snapshot of the node. */
|
|
||||||
final override fun getSnapshot(node: T, bitmap: Bitmap?): Bitmap? {
|
|
||||||
return onGetSnapshot(node, bitmap) ?: mSuper?.onGetSnapshot(node, bitmap)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun onGetSnapshot(node: T, bitmap: Bitmap?): Bitmap? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
final override fun getInlineAttributes(node: T): Map<String, String> {
|
final override fun getInlineAttributes(node: T): Map<String, String> {
|
||||||
|
|
||||||
val builder = mutableMapOf<String, String>()
|
val builder = mutableMapOf<String, String>()
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||||
@@ -58,13 +57,6 @@ interface NodeDescriptor<T> {
|
|||||||
/** The children this node exposes in the inspector. */
|
/** The children this node exposes in the inspector. */
|
||||||
fun getChildren(node: T): List<Any>
|
fun getChildren(node: T): List<Any>
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a snapshot of the node. Bitmaps are not cheap to create, so accept one as an optional
|
|
||||||
* parameter. If a bitmap is provided, it will be used by the canvas to draw on it. Otherwise, a
|
|
||||||
* bitmap will be created.
|
|
||||||
*/
|
|
||||||
fun getSnapshot(node: T, bitmap: Bitmap?): Bitmap? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* listen to / traverse this child. If return null we assume all children are 'active'
|
* listen to / traverse this child. If return null we assume all children are 'active'
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||||
@@ -34,6 +33,4 @@ object ObjectDescriptor : NodeDescriptor<Any> {
|
|||||||
override fun getBounds(node: Any): Bounds = Bounds(0, 0, 0, 0)
|
override fun getBounds(node: Any): Bounds = Bounds(0, 0, 0, 0)
|
||||||
|
|
||||||
override fun getTags(node: Any): Set<String> = setOf(BaseTags.Unknown)
|
override fun getTags(node: Any): Set<String> = setOf(BaseTags.Unknown)
|
||||||
|
|
||||||
override fun getSnapshot(node: Any, bitmap: Bitmap?): Bitmap? = null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||||
@@ -42,7 +41,4 @@ object OffsetChildDescriptor : NodeDescriptor<OffsetChild> {
|
|||||||
node.descriptor.getAttributes(node.child)
|
node.descriptor.getAttributes(node.child)
|
||||||
|
|
||||||
override fun getTags(node: OffsetChild): Set<String> = node.descriptor.getTags(node.child)
|
override fun getTags(node: OffsetChild): Set<String> = node.descriptor.getTags(node.child)
|
||||||
|
|
||||||
override fun getSnapshot(node: OffsetChild, bitmap: Bitmap?): Bitmap? =
|
|
||||||
node.descriptor.getSnapshot(node.child, bitmap)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
package com.facebook.flipper.plugins.uidebugger.descriptors
|
package com.facebook.flipper.plugins.uidebugger.descriptors
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@@ -380,30 +378,6 @@ object ViewDescriptor : ChainedDescriptor<View>() {
|
|||||||
attributes["id"] = value
|
attributes["id"] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetSnapshot(node: View, bitmap: Bitmap?): Bitmap? {
|
|
||||||
if (node.width <= 0 || node.height <= 0) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
var workingBitmap = bitmap
|
|
||||||
|
|
||||||
try {
|
|
||||||
val differentSize =
|
|
||||||
if (bitmap != null) (node.width != bitmap.width || node.height != bitmap.height)
|
|
||||||
else false
|
|
||||||
if (workingBitmap == null || differentSize) {
|
|
||||||
val viewWidth: Int = node.width
|
|
||||||
val viewHeight: Int = node.height
|
|
||||||
|
|
||||||
workingBitmap = BitmapPool.createBitmapWithDefaultConfig(viewWidth, viewHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
val canvas = Canvas(workingBitmap)
|
|
||||||
node.draw(canvas)
|
|
||||||
} catch (e: OutOfMemoryError) {}
|
|
||||||
|
|
||||||
return workingBitmap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fromDrawable(d: Drawable?): Inspectable? {
|
private fun fromDrawable(d: Drawable?): Inspectable? {
|
||||||
return if (d is ColorDrawable) {
|
return if (d is ColorDrawable) {
|
||||||
InspectableValue.Color(Color.fromColor(d.color))
|
InspectableValue.Color(Color.fromColor(d.color))
|
||||||
|
|||||||
Reference in New Issue
Block a user