7
7
package com.datadog.android.sessionreplay.compose.internal.utils
8
8
9
9
import android.graphics.Bitmap
10
+ import android.os.Build
10
11
import android.view.View
11
12
import androidx.compose.foundation.shape.RoundedCornerShape
12
13
import androidx.compose.ui.Modifier
@@ -28,6 +29,7 @@ import androidx.compose.ui.unit.Density
28
29
import com.datadog.android.Datadog
29
30
import com.datadog.android.api.InternalLogger
30
31
import com.datadog.android.api.feature.FeatureSdkCore
32
+ import com.datadog.android.core.sampling.RateBasedSampler
31
33
import com.datadog.android.sessionreplay.ImagePrivacy
32
34
import com.datadog.android.sessionreplay.TextAndInputPrivacy
33
35
import com.datadog.android.sessionreplay.TouchPrivacy
@@ -42,7 +44,10 @@ import com.datadog.android.sessionreplay.compose.internal.mappers.semantics.Text
42
44
import com.datadog.android.sessionreplay.utils.GlobalBounds
43
45
44
46
@Suppress(" TooManyFunctions" )
45
- internal class SemanticsUtils (private val reflectionUtils : ReflectionUtils = ReflectionUtils ()) {
47
+ internal class SemanticsUtils (
48
+ private val reflectionUtils : ReflectionUtils = ReflectionUtils (),
49
+ private val sampler : RateBasedSampler <Unit > = RateBasedSampler (BITMAP_TELEMETRY_SAMPLE_RATE )
50
+ ) {
46
51
47
52
internal fun findRootSemanticsNode (view : View ): SemanticsNode ? {
48
53
reflectionUtils.apply {
@@ -273,6 +278,15 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
273
278
}
274
279
}
275
280
281
+ // Send telemetry about the original bitmap before copying it.
282
+ bitmap?.let {
283
+ sendBitmapInfoTelemetry(it, isContextualImage)
284
+ }
285
+
286
+ // Avoid copying hardware bitmap because it is slow and may violate [StrictMode#noteSlowCall]
287
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O && bitmap?.config == Bitmap .Config .HARDWARE ) {
288
+ return BitmapInfo (bitmap, isContextualImage)
289
+ }
276
290
val newBitmap = bitmap?.let {
277
291
@Suppress(" UnsafeThirdPartyFunctionCall" ) // isMutable is always false
278
292
it.copy(Bitmap .Config .ARGB_8888 , false )
@@ -282,6 +296,24 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
282
296
}
283
297
}
284
298
299
+ private fun sendBitmapInfoTelemetry (bitmap : Bitmap , isContextual : Boolean ) {
300
+ if (sampler.sample(Unit )) {
301
+ (Datadog .getInstance() as ? FeatureSdkCore )?.internalLogger?.log(
302
+ level = InternalLogger .Level .INFO ,
303
+ target = InternalLogger .Target .TELEMETRY ,
304
+ messageBuilder = { " Resolved the bitmap from semantics node with id:${bitmap.generationId} " },
305
+ additionalProperties = mapOf (
306
+ " bitmap.id" to bitmap.generationId,
307
+ " bitmap.byteCount" to bitmap.byteCount,
308
+ " bitmap.width" to bitmap.width,
309
+ " bitmap.height" to bitmap.height,
310
+ " bitmap.config" to bitmap.config,
311
+ " bitmap.isContextual" to isContextual
312
+ )
313
+ )
314
+ }
315
+ }
316
+
285
317
private fun logUnsupportedPainter (painter : Painter ? ) {
286
318
val painterType = painter?.javaClass?.simpleName ? : " null"
287
319
(Datadog .getInstance() as ? FeatureSdkCore )?.internalLogger?.log(
@@ -390,6 +422,7 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
390
422
}
391
423
internal const val DEFAULT_COLOR_BLACK = " #000000FF"
392
424
internal const val DEFAULT_COLOR_WHITE = " #FFFFFFFF"
425
+ private const val BITMAP_TELEMETRY_SAMPLE_RATE = 1f
393
426
}
394
427
395
428
internal fun getProgressBarRangeInfo (semanticsNode : SemanticsNode ): ProgressBarRangeInfo ? {
0 commit comments