Skip to content

Commit 7f05efa

Browse files
RumTTIDReporter fix and refactoring
1 parent 589437e commit 7f05efa

File tree

5 files changed

+131
-81
lines changed

5 files changed

+131
-81
lines changed

detekt_custom_safe_calls.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ datadog:
8686
- "android.view.MotionEvent.getRawX(kotlin.Int)"
8787
- "android.view.MotionEvent.getRawY(kotlin.Int)"
8888
- "android.view.MotionEvent.recycle()"
89+
- "android.view.View.addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener?)"
8990
- "android.view.View.getChildAt(kotlin.Int)"
9091
- "android.view.View.getTag(kotlin.Int)"
9192
- "android.view.View.hashCode()"
9293
- "android.view.View.post(java.lang.Runnable?)"
94+
- "android.view.View.removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener?)"
9395
- "android.view.View.takeIf(kotlin.Function1)"
9496
- "android.view.View.setTag(kotlin.Int, kotlin.Any?)"
9597
- "android.view.ViewGroup.findViewById(kotlin.Int)"

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ import com.datadog.android.rum.internal.monitor.AdvancedRumMonitor
7373
import com.datadog.android.rum.internal.monitor.DatadogRumMonitor
7474
import com.datadog.android.rum.internal.net.RumRequestFactory
7575
import com.datadog.android.rum.internal.startup.RumAppStartupDetector
76+
import com.datadog.android.rum.internal.startup.RumFirstDrawTimeReporter
7677
import com.datadog.android.rum.internal.startup.RumStartupScenario
7778
import com.datadog.android.rum.internal.startup.RumTTIDInfo
78-
import com.datadog.android.rum.internal.startup.RumTTIDReporter
7979
import com.datadog.android.rum.internal.thread.NoOpScheduledExecutorService
8080
import com.datadog.android.rum.internal.tracking.JetpackViewAttributesProvider
8181
import com.datadog.android.rum.internal.tracking.NoOpInteractionPredicate
@@ -678,20 +678,26 @@ internal class RumFeature(
678678
application = appContext.applicationContext as Application,
679679
sdkCore = sdkCore as InternalSdkCore,
680680
listener = object : RumAppStartupDetector.Listener {
681-
private val rumTTIDReporter = RumTTIDReporter.create(
682-
sdkCore = sdkCore,
683-
listener = object : RumTTIDReporter.Listener {
684-
override fun onTTIDCalculated(
685-
info: RumTTIDInfo
686-
) {
681+
private val rumFirstDrawTimeReporter = RumFirstDrawTimeReporter.create(sdkCore = sdkCore)
682+
683+
override fun onAppStartupDetected(scenario: RumStartupScenario) {
684+
val activity = scenario.activity.get() ?: return
685+
686+
val callback = object : RumFirstDrawTimeReporter.Callback {
687+
override fun onFirstFrameDrawn(timestampNs: Long) {
688+
val info = RumTTIDInfo(
689+
scenario = scenario,
690+
durationNs = timestampNs - scenario.initialTimeNs
691+
)
687692
(GlobalRumMonitor.get(sdkCore) as? AdvancedRumMonitor)
688693
?.sendTTIDEvent(info)
689694
}
690695
}
691-
)
692696

693-
override fun onAppStartupDetected(scenario: RumStartupScenario) {
694-
rumTTIDReporter.onAppStartupDetected(scenario)
697+
rumFirstDrawTimeReporter.subscribeToFirstFrameDrawn(
698+
activity = activity,
699+
callback = callback
700+
)
695701
}
696702
}
697703
)
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@
66

77
package com.datadog.android.rum.internal.startup
88

9+
import android.app.Activity
910
import android.os.Handler
1011
import android.os.Looper
1112
import com.datadog.android.core.InternalSdkCore
1213
import com.datadog.android.rum.internal.utils.window.RumWindowCallbacksRegistryImpl
1314

14-
internal interface RumTTIDReporter {
15-
interface Listener {
16-
fun onTTIDCalculated(info: RumTTIDInfo)
15+
internal interface RumFirstDrawTimeReporter {
16+
interface Callback {
17+
fun onFirstFrameDrawn(timestampNs: Long)
1718
}
1819

19-
fun onAppStartupDetected(scenario: RumStartupScenario)
20+
fun subscribeToFirstFrameDrawn(activity: Activity, callback: Callback)
2021

2122
companion object {
22-
fun create(sdkCore: InternalSdkCore, listener: Listener): RumTTIDReporter {
23-
return RumTTIDReporterImpl(
23+
fun create(sdkCore: InternalSdkCore): RumFirstDrawTimeReporter {
24+
return RumFirstDrawTimeReporterImpl(
2425
internalLogger = sdkCore.internalLogger,
2526
timeProviderNs = { System.nanoTime() },
2627
windowCallbacksRegistry = RumWindowCallbacksRegistryImpl(),
27-
handler = Handler(Looper.getMainLooper()),
28-
listener = listener
28+
handler = Handler(Looper.getMainLooper())
2929
)
3030
}
3131
}
Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,72 @@ package com.datadog.android.rum.internal.startup
99
import android.app.Activity
1010
import android.os.Handler
1111
import android.os.Message
12+
import android.view.View
1213
import android.view.ViewTreeObserver
1314
import com.datadog.android.api.InternalLogger
1415
import com.datadog.android.rum.internal.utils.window.RumWindowCallbackListener
1516
import com.datadog.android.rum.internal.utils.window.RumWindowCallbacksRegistry
16-
import java.lang.IllegalStateException
17-
import java.util.WeakHashMap
1817

19-
internal class RumTTIDReporterImpl(
18+
internal class RumFirstDrawTimeReporterImpl(
2019
private val internalLogger: InternalLogger,
2120
private val timeProviderNs: () -> Long,
2221
private val windowCallbacksRegistry: RumWindowCallbacksRegistry,
23-
private val handler: Handler,
24-
private val listener: RumTTIDReporter.Listener
25-
) : RumTTIDReporter {
22+
private val handler: Handler
23+
) : RumFirstDrawTimeReporter {
2624

27-
private val onDrawListeners = WeakHashMap<Activity, ViewTreeObserver.OnDrawListener>()
28-
29-
override fun onAppStartupDetected(scenario: RumStartupScenario) {
30-
val activity = scenario.activity.get() ?: return
25+
override fun subscribeToFirstFrameDrawn(
26+
activity: Activity,
27+
callback: RumFirstDrawTimeReporter.Callback
28+
) {
3129
val window = activity.window
3230
val decorView = window.peekDecorView()
3331

3432
if (decorView == null) {
3533
val listener = object : RumWindowCallbackListener {
3634
override fun onContentChanged() {
3735
windowCallbacksRegistry.removeListener(activity, this)
38-
onDecorViewReady(scenario)
36+
onDecorViewReady(activity, callback)
3937
}
4038
}
4139
windowCallbacksRegistry.addListener(activity, listener)
4240
} else {
43-
onDecorViewReady(scenario)
41+
onDecorViewReady(activity, callback)
4442
}
4543
}
4644

47-
private fun onDecorViewReady(scenario: RumStartupScenario) {
48-
val activity = scenario.activity.get() ?: return
45+
private fun onDecorViewReady(
46+
activity: Activity,
47+
callback: RumFirstDrawTimeReporter.Callback
48+
) {
4949
val window = activity.window
5050
val decorView = window.decorView
5151

52+
if (decorView.isAttachedToWindow) {
53+
registerOnDrawListener(
54+
decorView = decorView,
55+
callback = callback
56+
)
57+
} else {
58+
val attachListener = object : View.OnAttachStateChangeListener {
59+
override fun onViewAttachedToWindow(v: View) {
60+
registerOnDrawListener(
61+
decorView = decorView,
62+
callback = callback
63+
)
64+
decorView.removeOnAttachStateChangeListener(this)
65+
}
66+
67+
override fun onViewDetachedFromWindow(v: View) {
68+
}
69+
}
70+
decorView.addOnAttachStateChangeListener(attachListener)
71+
}
72+
}
73+
74+
private fun registerOnDrawListener(
75+
decorView: View,
76+
callback: RumFirstDrawTimeReporter.Callback
77+
) {
5278
val listener = object : ViewTreeObserver.OnDrawListener {
5379
private var invoked = false
5480

@@ -57,11 +83,9 @@ internal class RumTTIDReporterImpl(
5783
return
5884
}
5985
invoked = true
60-
onFirstDraw(scenario)
86+
onFirstDraw(callback)
6187

6288
handler.post {
63-
onDrawListeners.remove(activity)
64-
6589
if (decorView.viewTreeObserver.isAlive) {
6690
try {
6791
decorView.viewTreeObserver.removeOnDrawListener(this)
@@ -81,26 +105,22 @@ internal class RumTTIDReporterImpl(
81105
if (decorView.viewTreeObserver.isAlive) {
82106
try {
83107
decorView.viewTreeObserver.addOnDrawListener(listener)
84-
onDrawListeners.put(activity, listener)
85108
} catch (e: IllegalStateException) {
86109
internalLogger.log(
87110
InternalLogger.Level.WARN,
88111
InternalLogger.Target.TELEMETRY,
89-
{ "RumTTIDReporterImpl unable to add onDrawListener onto viewTreeObserver" },
112+
{ "RumFirstDrawTimeReporterImpl unable to add onDrawListener onto viewTreeObserver" },
90113
e
91114
)
92115
}
93116
}
94117
}
95118

96-
private fun onFirstDraw(scenario: RumStartupScenario) {
119+
private fun onFirstDraw(callback: RumFirstDrawTimeReporter.Callback) {
97120
val nowNs = timeProviderNs()
98-
val durationNs = nowNs - scenario.initialTimeNs
99121

100122
val block = Runnable {
101-
listener.onTTIDCalculated(
102-
RumTTIDInfo(scenario = scenario, durationNs = durationNs)
103-
)
123+
callback.onFirstFrameDrawn(nowNs)
104124
}
105125

106126
handler.sendMessageAtFrontOfQueue(

0 commit comments

Comments
 (0)