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
@@ -16,7 +16,7 @@ import kotlinx.coroutines.launch
|
||||
class BitmapPool(private val config: Bitmap.Config = Bitmap.Config.RGB_565) {
|
||||
|
||||
interface ReusableBitmap {
|
||||
val bitmap: Bitmap?
|
||||
val bitmap: Bitmap
|
||||
|
||||
fun readyForReuse()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.util.Log
|
||||
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.descriptors.ViewDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.util.StopWatch
|
||||
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
|
||||
* 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 preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
|
||||
@@ -88,18 +87,7 @@ class DecorViewTracker(val context: UIDContext) {
|
||||
val (nodes, traversalTime) =
|
||||
StopWatch.time { context.layoutTraversal.traverse(context.applicationRef) }
|
||||
|
||||
mStopWatch.start()
|
||||
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()
|
||||
val (reusableBitmap, snapshotMs) = StopWatch.time { snapshotter.takeSnapshot(decorView) }
|
||||
|
||||
context.updateQueue.enqueueUpdate(
|
||||
Update(
|
||||
@@ -107,8 +95,8 @@ class DecorViewTracker(val context: UIDContext) {
|
||||
nodes,
|
||||
startTimestamp,
|
||||
traversalTime,
|
||||
snapshotTime,
|
||||
snapshotMs,
|
||||
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>
|
||||
) {
|
||||
|
||||
val decorViewTracker = DecorViewTracker(this)
|
||||
val bitmapPool = BitmapPool()
|
||||
val decorViewTracker = DecorViewTracker(this, CanvasSnapshotter(bitmapPool))
|
||||
val updateQueue = UpdateQueue(this)
|
||||
val layoutTraversal: LayoutTraversal = LayoutTraversal(this)
|
||||
|
||||
val bitmapPool = BitmapPool()
|
||||
|
||||
fun addFrameworkEvent(frameworkEvent: FrameworkEvent) {
|
||||
synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
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.InspectableObject
|
||||
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>) {}
|
||||
|
||||
/** 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> {
|
||||
|
||||
val builder = mutableMapOf<String, String>()
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
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.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
@@ -58,13 +57,6 @@ interface NodeDescriptor<T> {
|
||||
/** The children this node exposes in the inspector. */
|
||||
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
|
||||
* 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
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
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 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
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
@@ -42,7 +41,4 @@ object OffsetChildDescriptor : NodeDescriptor<OffsetChild> {
|
||||
node.descriptor.getAttributes(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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
@@ -380,30 +378,6 @@ object ViewDescriptor : ChainedDescriptor<View>() {
|
||||
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? {
|
||||
return if (d is ColorDrawable) {
|
||||
InspectableValue.Color(Color.fromColor(d.color))
|
||||
|
||||
Reference in New Issue
Block a user