@@ -38,12 +38,35 @@ internal class FrameTimingsObserver(
3838
3939 @Volatile private var currentWindow: Window ? = null
4040
41- private val frameMetricsListener =
42- Window .OnFrameMetricsAvailableListener { _, frameMetrics, _dropCount ->
43- val beginTimestamp = frameMetrics.getMetric(FrameMetrics .VSYNC_TIMESTAMP )
44- val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics .TOTAL_DURATION )
45- emitFrameTiming(beginTimestamp, endTimestamp)
46- }
41+ fun start () {
42+ if (! isSupported) {
43+ return
44+ }
45+
46+ frameCounter = 0
47+ isStarted = true
48+
49+ // Capture initial screenshot to ensure there's always at least one frame
50+ // recorded at the start of tracing, even if no UI changes occur
51+ val timestamp = System .nanoTime()
52+ emitFrameTiming(timestamp, timestamp)
53+
54+ currentWindow?.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)
55+ }
56+
57+ fun stop () {
58+ if (! isSupported) {
59+ return
60+ }
61+
62+ isStarted = false
63+
64+ currentWindow?.removeOnFrameMetricsAvailableListener(frameMetricsListener)
65+ handler.removeCallbacksAndMessages(null )
66+
67+ bitmapBuffer?.recycle()
68+ bitmapBuffer = null
69+ }
4770
4871 fun setCurrentWindow (window : Window ? ) {
4972 if (! isSupported || currentWindow == = window) {
@@ -57,6 +80,32 @@ internal class FrameTimingsObserver(
5780 }
5881 }
5982
83+ private val frameMetricsListener =
84+ Window .OnFrameMetricsAvailableListener { _, frameMetrics, _ ->
85+ val beginTimestamp = frameMetrics.getMetric(FrameMetrics .VSYNC_TIMESTAMP )
86+ val endTimestamp = beginTimestamp + frameMetrics.getMetric(FrameMetrics .TOTAL_DURATION )
87+ emitFrameTiming(beginTimestamp, endTimestamp)
88+ }
89+
90+ private fun emitFrameTiming (beginTimestamp : Long , endTimestamp : Long ) {
91+ val frameId = frameCounter++
92+ val threadId = Process .myTid()
93+
94+ CoroutineScope (Dispatchers .Default ).launch {
95+ val screenshot = if (screenshotsEnabled) captureScreenshot() else null
96+
97+ onFrameTimingSequence(
98+ FrameTimingSequence (
99+ frameId,
100+ threadId,
101+ beginTimestamp,
102+ endTimestamp,
103+ screenshot,
104+ )
105+ )
106+ }
107+ }
108+
60109 private suspend fun captureScreenshot (): String? = suspendCoroutine { continuation ->
61110 if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
62111 continuation.resume(null )
@@ -122,53 +171,4 @@ internal class FrameTimingsObserver(
122171 handler,
123172 )
124173 }
125-
126- fun start () {
127- if (! isSupported) {
128- return
129- }
130-
131- frameCounter = 0
132- isStarted = true
133-
134- // Capture initial screenshot to ensure there's always at least one frame
135- // recorded at the start of tracing, even if no UI changes occur
136- val timestamp = System .nanoTime()
137- emitFrameTiming(timestamp, timestamp)
138-
139- currentWindow?.addOnFrameMetricsAvailableListener(frameMetricsListener, handler)
140- }
141-
142- private fun emitFrameTiming (beginTimestamp : Long , endTimestamp : Long ) {
143- val frameId = frameCounter++
144- val threadId = Process .myTid()
145-
146- CoroutineScope (Dispatchers .Default ).launch {
147- val screenshot = if (screenshotsEnabled) captureScreenshot() else null
148-
149- onFrameTimingSequence(
150- FrameTimingSequence (
151- frameId,
152- threadId,
153- beginTimestamp,
154- endTimestamp,
155- screenshot,
156- )
157- )
158- }
159- }
160-
161- fun stop () {
162- if (! isSupported) {
163- return
164- }
165-
166- isStarted = false
167-
168- currentWindow?.removeOnFrameMetricsAvailableListener(frameMetricsListener)
169- handler.removeCallbacksAndMessages(null )
170-
171- bitmapBuffer?.recycle()
172- bitmapBuffer = null
173- }
174174}
0 commit comments