Skip to content

Commit 56c49e9

Browse files
committed
RUM-6195: Add cache key to ImageWireframeHelper
1 parent 8743eb1 commit 56c49e9

File tree

17 files changed

+247
-76
lines changed

17 files changed

+247
-76
lines changed

features/dd-sdk-android-session-replay-material/src/main/kotlin/com/datadog/android/sessionreplay/material/internal/ChipWireframeMapper.kt

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ internal class ChipWireframeMapper(
5555
height = view.chipDrawable.intrinsicHeight,
5656
usePIIPlaceholder = false,
5757
drawable = view.chipDrawable,
58+
resourceIdCacheKey = null,
5859
asyncJobStatusCallback = asyncJobStatusCallback
5960
)
6061
backgroundWireframe?.let {

features/dd-sdk-android-session-replay-material/src/test/kotlin/com/datadog/android/sessionreplay/material/ChipWireframeMapperTest.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ import org.mockito.Mock
4141
import org.mockito.junit.jupiter.MockitoExtension
4242
import org.mockito.junit.jupiter.MockitoSettings
4343
import org.mockito.kotlin.any
44+
import org.mockito.kotlin.anyOrNull
4445
import org.mockito.kotlin.doReturn
4546
import org.mockito.kotlin.eq
4647
import org.mockito.kotlin.isNull
4748
import org.mockito.kotlin.mock
48-
import org.mockito.kotlin.times
4949
import org.mockito.kotlin.verify
5050
import org.mockito.kotlin.whenever
5151
import org.mockito.quality.Strictness
@@ -176,7 +176,8 @@ class ChipWireframeMapperTest {
176176
clipping = isNull(),
177177
shapeStyle = isNull(),
178178
border = isNull(),
179-
prefix = any()
179+
prefix = any(),
180+
resourceIdCacheKey = anyOrNull()
180181
)
181182
}
182183

features/dd-sdk-android-session-replay/api/apiSurface

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ data class com.datadog.android.sessionreplay.utils.GlobalBounds
126126
constructor(Long, Long, Long, Long)
127127
interface com.datadog.android.sessionreplay.utils.ImageWireframeHelper
128128
fun createImageWireframeByBitmap(Long, GlobalBounds, android.graphics.Bitmap, Float, Boolean, com.datadog.android.sessionreplay.ImagePrivacy, AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
129-
fun createImageWireframeByDrawable(android.view.View, com.datadog.android.sessionreplay.ImagePrivacy, Int, Long, Long, Int, Int, Boolean, android.graphics.drawable.Drawable, com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier = DefaultDrawableCopier(), AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null, String? = DRAWABLE_CHILD_NAME): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
130-
fun createCompoundDrawableWireframes(android.widget.TextView, com.datadog.android.sessionreplay.recorder.MappingContext, Int, AsyncJobStatusCallback): MutableList<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
129+
fun createImageWireframeByDrawable(android.view.View, com.datadog.android.sessionreplay.ImagePrivacy, Int, Long, Long, Int, Int, Boolean, android.graphics.drawable.Drawable, com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier = DefaultDrawableCopier(), AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null, String? = DRAWABLE_CHILD_NAME, String?): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
130+
fun createCompoundDrawableWireframes(android.widget.TextView, com.datadog.android.sessionreplay.recorder.MappingContext, Int, String?, AsyncJobStatusCallback): MutableList<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
131131
companion object
132132
open class com.datadog.android.sessionreplay.utils.LegacyDrawableToColorMapper : DrawableToColorMapper
133133
constructor(List<DrawableToColorMapper> = emptyList())

features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api

+3-3
Original file line numberDiff line numberDiff line change
@@ -1584,17 +1584,17 @@ public final class com/datadog/android/sessionreplay/utils/GlobalBounds {
15841584

15851585
public abstract interface class com/datadog/android/sessionreplay/utils/ImageWireframeHelper {
15861586
public static final field Companion Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper$Companion;
1587-
public abstract fun createCompoundDrawableWireframes (Landroid/widget/TextView;Lcom/datadog/android/sessionreplay/recorder/MappingContext;ILcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;)Ljava/util/List;
1587+
public abstract fun createCompoundDrawableWireframes (Landroid/widget/TextView;Lcom/datadog/android/sessionreplay/recorder/MappingContext;ILjava/lang/String;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;)Ljava/util/List;
15881588
public abstract fun createImageWireframeByBitmap (JLcom/datadog/android/sessionreplay/utils/GlobalBounds;Landroid/graphics/Bitmap;FZLcom/datadog/android/sessionreplay/ImagePrivacy;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
1589-
public abstract fun createImageWireframeByDrawable (Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
1589+
public abstract fun createImageWireframeByDrawable (Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
15901590
}
15911591

15921592
public final class com/datadog/android/sessionreplay/utils/ImageWireframeHelper$Companion {
15931593
}
15941594

15951595
public final class com/datadog/android/sessionreplay/utils/ImageWireframeHelper$DefaultImpls {
15961596
public static synthetic fun createImageWireframeByBitmap$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;JLcom/datadog/android/sessionreplay/utils/GlobalBounds;Landroid/graphics/Bitmap;FZLcom/datadog/android/sessionreplay/ImagePrivacy;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
1597-
public static synthetic fun createImageWireframeByDrawable$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
1597+
public static synthetic fun createImageWireframeByDrawable$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
15981598
}
15991599

16001600
public class com/datadog/android/sessionreplay/utils/LegacyDrawableToColorMapper : com/datadog/android/sessionreplay/utils/DrawableToColorMapper {

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableTextViewMapper.kt

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ internal abstract class CheckableTextViewMapper<T>(
125125
border = null,
126126
usePIIPlaceholder = true,
127127
clipping = MobileSegment.WireframeClip(),
128+
resourceIdCacheKey = null,
128129
asyncJobStatusCallback = asyncJobStatusCallback
129130
)
130131
}

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapper.kt

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ internal open class SwitchCompatMapper(
9797
shapeStyle = null,
9898
border = null,
9999
usePIIPlaceholder = true,
100+
resourceIdCacheKey = null,
100101
asyncJobStatusCallback = asyncJobStatusCallback
101102
)
102103
}
@@ -141,6 +142,7 @@ internal open class SwitchCompatMapper(
141142
border = null,
142143
usePIIPlaceholder = true,
143144
clipping = null,
145+
resourceIdCacheKey = null,
144146
asyncJobStatusCallback = asyncJobStatusCallback
145147
)
146148
}

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelper.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ internal class DefaultImageWireframeHelper(
115115
clipping: MobileSegment.WireframeClip?,
116116
shapeStyle: MobileSegment.ShapeStyle?,
117117
border: MobileSegment.ShapeBorder?,
118-
prefix: String?
118+
prefix: String?,
119+
resourceIdCacheKey: String?
119120
): MobileSegment.Wireframe? {
120121
val id = viewIdentifierResolver.resolveChildUniqueIdentifier(view, prefix + currentWireframeIndex)
121122
val drawableProperties = resolveDrawableProperties(
@@ -204,6 +205,7 @@ internal class DefaultImageWireframeHelper(
204205
drawableCopier = drawableCopier,
205206
drawableWidth = width,
206207
drawableHeight = height,
208+
resourceIdCacheKey = resourceIdCacheKey,
207209
resourceResolverCallback = object : ResourceResolverCallback {
208210
override fun onSuccess(resourceId: String) {
209211
populateResourceIdInWireframe(resourceId, imageWireframe)
@@ -225,6 +227,7 @@ internal class DefaultImageWireframeHelper(
225227
textView: TextView,
226228
mappingContext: MappingContext,
227229
prevWireframeIndex: Int,
230+
resourceIdCacheKey: String?,
228231
asyncJobStatusCallback: AsyncJobStatusCallback
229232
): MutableList<MobileSegment.Wireframe> {
230233
val result = mutableListOf<MobileSegment.Wireframe>()
@@ -265,6 +268,7 @@ internal class DefaultImageWireframeHelper(
265268
border = null,
266269
usePIIPlaceholder = true,
267270
clipping = MobileSegment.WireframeClip(),
271+
resourceIdCacheKey = resourceIdCacheKey,
268272
asyncJobStatusCallback = asyncJobStatusCallback
269273
)?.let { resultWireframe ->
270274
result.add(resultWireframe)

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolver.kt

+22-5
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,12 @@ internal class ResourceResolver(
8080
drawableCopier: DrawableCopier,
8181
drawableWidth: Int,
8282
drawableHeight: Int,
83+
resourceIdCacheKey: String?,
8384
resourceResolverCallback: ResourceResolverCallback
8485
) {
8586
bitmapCachesManager.registerCallbacks(applicationContext)
8687

87-
val resourceId = tryToGetResourceFromCache(drawable = originalDrawable)
88+
val resourceId = tryToGetResourceFromCache(drawable = originalDrawable, key = resourceIdCacheKey)
8889

8990
if (resourceId != null) {
9091
// if we got here it means we saw the bitmap before,
@@ -115,6 +116,7 @@ internal class ResourceResolver(
115116
drawableHeight = drawableHeight,
116117
displayMetrics = displayMetrics,
117118
bitmapFromDrawable = bitmapFromDrawable,
119+
resourceIdCacheKey = resourceIdCacheKey,
118120
resolveResourceCallback = object : ResolveResourceCallback {
119121
override fun onResolved(resourceId: String, resourceData: ByteArray) {
120122
resourceItemCreationHandler.queueItem(resourceId, resourceData)
@@ -141,12 +143,14 @@ internal class ResourceResolver(
141143
drawableHeight: Int,
142144
displayMetrics: DisplayMetrics,
143145
bitmapFromDrawable: Bitmap?,
146+
resourceIdCacheKey: String?,
144147
resolveResourceCallback: ResolveResourceCallback
145148
) {
146149
val handledBitmap = if (bitmapFromDrawable != null) {
147150
tryToGetBitmapFromBitmapDrawable(
148151
drawable = drawable as BitmapDrawable,
149152
bitmapFromDrawable = bitmapFromDrawable,
153+
resourceIdCacheKey = resourceIdCacheKey,
150154
resolveResourceCallback = resolveResourceCallback
151155
)
152156
} else {
@@ -160,6 +164,7 @@ internal class ResourceResolver(
160164
drawableWidth = drawableWidth,
161165
drawableHeight = drawableHeight,
162166
displayMetrics = displayMetrics,
167+
resourceIdCacheKey = resourceIdCacheKey,
163168
resolveResourceCallback = resolveResourceCallback
164169
)
165170
}
@@ -195,6 +200,7 @@ internal class ResourceResolver(
195200
bitmap: Bitmap,
196201
compressedBitmapBytes: ByteArray,
197202
shouldCacheBitmap: Boolean,
203+
resourceIdCacheKey: String?,
198204
resolveResourceCallback: ResolveResourceCallback
199205
) {
200206
// failed to get image data
@@ -217,6 +223,7 @@ internal class ResourceResolver(
217223
shouldCacheBitmap = shouldCacheBitmap,
218224
bitmap = bitmap,
219225
resourceId = resourceId,
226+
resourceIdCacheKey = resourceIdCacheKey,
220227
drawable = drawable
221228
)
222229

@@ -227,13 +234,16 @@ internal class ResourceResolver(
227234
shouldCacheBitmap: Boolean,
228235
bitmap: Bitmap,
229236
resourceId: String,
237+
resourceIdCacheKey: String?,
230238
drawable: Drawable
231239
) {
232240
if (shouldCacheBitmap) {
233241
bitmapCachesManager.putInBitmapPool(bitmap)
234242
}
235243

236-
val key = bitmapCachesManager.generateResourceKeyFromDrawable(drawable) ?: return
244+
val key = resourceIdCacheKey
245+
?: bitmapCachesManager.generateResourceKeyFromDrawable(drawable)
246+
?: return
237247
bitmapCachesManager.putInResourceCache(key, resourceId)
238248
}
239249

@@ -244,6 +254,7 @@ internal class ResourceResolver(
244254
drawableWidth: Int,
245255
drawableHeight: Int,
246256
displayMetrics: DisplayMetrics,
257+
resourceIdCacheKey: String?,
247258
resolveResourceCallback: ResolveResourceCallback
248259
) {
249260
drawableUtils.createBitmapOfApproxSizeFromDrawable(
@@ -268,6 +279,7 @@ internal class ResourceResolver(
268279
bitmap = bitmap,
269280
compressedBitmapBytes = compressedBitmapBytes,
270281
shouldCacheBitmap = true,
282+
resourceIdCacheKey = resourceIdCacheKey,
271283
resolveResourceCallback = resolveResourceCallback
272284
)
273285
}
@@ -285,6 +297,7 @@ internal class ResourceResolver(
285297
private fun tryToGetBitmapFromBitmapDrawable(
286298
drawable: BitmapDrawable,
287299
bitmapFromDrawable: Bitmap,
300+
resourceIdCacheKey: String?,
288301
resolveResourceCallback: ResolveResourceCallback
289302
): Bitmap? {
290303
val scaledBitmap = drawableUtils.createScaledBitmap(bitmapFromDrawable)
@@ -314,17 +327,21 @@ internal class ResourceResolver(
314327
bitmap = scaledBitmap,
315328
compressedBitmapBytes = compressedBitmapBytes,
316329
shouldCacheBitmap = shouldCacheBitmap,
330+
resourceIdCacheKey = resourceIdCacheKey,
317331
resolveResourceCallback = resolveResourceCallback
318332
)
319333

320334
return scaledBitmap
321335
}
322336

323337
private fun tryToGetResourceFromCache(
324-
drawable: Drawable
338+
drawable: Drawable,
339+
key: String?
325340
): String? {
326-
val key = bitmapCachesManager.generateResourceKeyFromDrawable(drawable) ?: return null
327-
return bitmapCachesManager.getFromResourceCache(key)
341+
val cacheKey = key
342+
?: bitmapCachesManager.generateResourceKeyFromDrawable(drawable)
343+
?: return null
344+
return bitmapCachesManager.getFromResourceCache(cacheKey)
328345
}
329346

330347
private fun shouldUseDrawableBitmap(drawable: BitmapDrawable): Boolean {

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ abstract class BaseAsyncBackgroundWireframeMapper<in T : View> internal construc
139139
clipping = MobileSegment.WireframeClip(),
140140
shapeStyle = null,
141141
border = null,
142-
prefix = PREFIX_BACKGROUND_DRAWABLE
142+
prefix = PREFIX_BACKGROUND_DRAWABLE,
143+
resourceIdCacheKey = null
143144
)
144145
}
145146

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
101101
clipping = clipping,
102102
shapeStyle = null,
103103
border = null,
104-
prefix = ImageWireframeHelper.DRAWABLE_CHILD_NAME
104+
prefix = ImageWireframeHelper.DRAWABLE_CHILD_NAME,
105+
resourceIdCacheKey = null
105106
)?.let {
106107
wireframes.add(it)
107108
}

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/TextViewMapper.kt

+14-13
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ open class TextViewMapper<in T : TextView>(
3434
viewBoundsResolver: ViewBoundsResolver,
3535
drawableToColorMapper: DrawableToColorMapper
3636
) : BaseAsyncBackgroundWireframeMapper<T>(
37-
viewIdentifierResolver,
38-
colorStringFormatter,
39-
viewBoundsResolver,
40-
drawableToColorMapper
37+
viewIdentifierResolver = viewIdentifierResolver,
38+
colorStringFormatter = colorStringFormatter,
39+
viewBoundsResolver = viewBoundsResolver,
40+
drawableToColorMapper = drawableToColorMapper
4141
) {
4242

4343
@UiThread
@@ -54,24 +54,25 @@ open class TextViewMapper<in T : TextView>(
5454

5555
val density = mappingContext.systemInformation.screenDensity
5656
val viewGlobalBounds = viewBoundsResolver.resolveViewGlobalBounds(
57-
view,
58-
density
57+
view = view,
58+
screenDensity = density
5959
)
6060

6161
wireframes.add(
6262
createTextWireframe(
63-
view,
64-
mappingContext,
65-
viewGlobalBounds
63+
textView = view,
64+
mappingContext = mappingContext,
65+
viewGlobalBounds = viewGlobalBounds
6666
)
6767
)
6868

6969
wireframes.addAll(
7070
mappingContext.imageWireframeHelper.createCompoundDrawableWireframes(
71-
view,
72-
mappingContext,
73-
wireframes.size,
74-
asyncJobStatusCallback
71+
textView = view,
72+
mappingContext = mappingContext,
73+
prevWireframeIndex = wireframes.size,
74+
resourceIdCacheKey = null,
75+
asyncJobStatusCallback = asyncJobStatusCallback
7576
)
7677
)
7778

0 commit comments

Comments
 (0)