Skip to content

Commit

Permalink
Merge pull request #1690 from DataDog/jmoskovich/rum-1654/base64-diffing
Browse files Browse the repository at this point in the history
RUM-1654 Add resourceId to ImageWireframe
  • Loading branch information
jonathanmos authored Dec 6, 2023
2 parents 8d7e51f + b76e2f4 commit f38f6be
Show file tree
Hide file tree
Showing 16 changed files with 453 additions and 207 deletions.
4 changes: 2 additions & 2 deletions features/dd-sdk-android-session-replay/api/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ data class com.datadog.android.sessionreplay.model.MobileSegment
fun fromJson(kotlin.String): TextWireframe
fun fromJsonObject(com.google.gson.JsonObject): TextWireframe
data class ImageWireframe : Wireframe
constructor(kotlin.Long, kotlin.Long, kotlin.Long, kotlin.Long, kotlin.Long, WireframeClip? = null, ShapeStyle? = null, ShapeBorder? = null, kotlin.String? = null, kotlin.String? = null, kotlin.Boolean? = null)
constructor(kotlin.Long, kotlin.Long, kotlin.Long, kotlin.Long, kotlin.Long, WireframeClip? = null, ShapeStyle? = null, ShapeBorder? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.Boolean? = null)
val type: kotlin.String
override fun toJson(): com.google.gson.JsonElement
companion object
Expand Down Expand Up @@ -242,7 +242,7 @@ data class com.datadog.android.sessionreplay.model.MobileSegment
fun fromJson(kotlin.String): ShapeWireframeUpdate
fun fromJsonObject(com.google.gson.JsonObject): ShapeWireframeUpdate
data class ImageWireframeUpdate : WireframeUpdateMutation
constructor(kotlin.Long, kotlin.Long? = null, kotlin.Long? = null, kotlin.Long? = null, kotlin.Long? = null, WireframeClip? = null, ShapeStyle? = null, ShapeBorder? = null, kotlin.String? = null, kotlin.String? = null, kotlin.Boolean? = null)
constructor(kotlin.Long, kotlin.Long? = null, kotlin.Long? = null, kotlin.Long? = null, kotlin.Long? = null, WireframeClip? = null, ShapeStyle? = null, ShapeBorder? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.Boolean? = null)
val type: kotlin.String
override fun toJson(): com.google.gson.JsonElement
companion object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -907,11 +907,12 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra

public final class com/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe : com/datadog/android/sessionreplay/model/MobileSegment$Wireframe {
public static final field Companion Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe$Companion;
public fun <init> (JJJJJLcom/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;Ljava/lang/Boolean;)V
public synthetic fun <init> (JJJJJLcom/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;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (JJJJJLcom/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;Ljava/lang/String;Ljava/lang/Boolean;)V
public synthetic fun <init> (JJJJJLcom/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;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()J
public final fun component10 ()Ljava/lang/String;
public final fun component11 ()Ljava/lang/Boolean;
public final fun component11 ()Ljava/lang/String;
public final fun component12 ()Ljava/lang/Boolean;
public final fun component2 ()J
public final fun component3 ()J
public final fun component4 ()J
Expand All @@ -920,8 +921,8 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun component7 ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;
public final fun component8 ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;
public final fun component9 ()Ljava/lang/String;
public final fun copy (JJJJJLcom/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;Ljava/lang/Boolean;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;JJJJJLcom/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;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
public final fun copy (JJJJJLcom/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;Ljava/lang/String;Ljava/lang/Boolean;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;JJJJJLcom/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;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
public fun equals (Ljava/lang/Object;)Z
public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ImageWireframe;
Expand All @@ -931,6 +932,7 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun getHeight ()J
public final fun getId ()J
public final fun getMimeType ()Ljava/lang/String;
public final fun getResourceId ()Ljava/lang/String;
public final fun getShapeStyle ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;
public final fun getType ()Ljava/lang/String;
public final fun getWidth ()J
Expand All @@ -941,6 +943,7 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun setBase64 (Ljava/lang/String;)V
public final fun setEmpty (Ljava/lang/Boolean;)V
public final fun setMimeType (Ljava/lang/String;)V
public final fun setResourceId (Ljava/lang/String;)V
public fun toJson ()Lcom/google/gson/JsonElement;
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -1106,11 +1109,12 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra

public final class com/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate : com/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation {
public static final field Companion Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate$Companion;
public fun <init> (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/Boolean;)V
public synthetic fun <init> (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/String;Ljava/lang/Boolean;)V
public synthetic fun <init> (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()J
public final fun component10 ()Ljava/lang/String;
public final fun component11 ()Ljava/lang/Boolean;
public final fun component11 ()Ljava/lang/String;
public final fun component12 ()Ljava/lang/Boolean;
public final fun component2 ()Ljava/lang/Long;
public final fun component3 ()Ljava/lang/Long;
public final fun component4 ()Ljava/lang/Long;
Expand All @@ -1119,8 +1123,8 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun component7 ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;
public final fun component8 ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;
public final fun component9 ()Ljava/lang/String;
public final fun copy (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/Boolean;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
public final fun copy (JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/String;Ljava/lang/Boolean;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;JLjava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;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;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
public fun equals (Ljava/lang/Object;)Z
public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeUpdateMutation$ImageWireframeUpdate;
Expand All @@ -1130,6 +1134,7 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun getHeight ()Ljava/lang/Long;
public final fun getId ()J
public final fun getMimeType ()Ljava/lang/String;
public final fun getResourceId ()Ljava/lang/String;
public final fun getShapeStyle ()Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;
public final fun getType ()Ljava/lang/String;
public final fun getWidth ()Ljava/lang/Long;
Expand All @@ -1140,6 +1145,7 @@ public final class com/datadog/android/sessionreplay/model/MobileSegment$Wirefra
public final fun setBase64 (Ljava/lang/String;)V
public final fun setEmpty (Ljava/lang/Boolean;)V
public final fun setMimeType (Ljava/lang/String;)V
public final fun setResourceId (Ljava/lang/String;)V
public fun toJson ()Lcom/google/gson/JsonElement;
public fun toString ()Ljava/lang/String;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
"description": "base64 representation of the image. Not required as the ImageWireframe can be initialised without any base64",
"readOnly": false
},
"resourceId": {
"type": "string",
"description": "Unique identifier of the image resource",
"readOnly": false
},
"mimeType": {
"type": "string",
"description": "MIME type of the image file",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
"description": "base64 representation of the image. Not required as the ImageWireframe can be initialised without any base64",
"readOnly": false
},
"resourceId": {
"type": "string",
"description": "Unique identifier of the image resource",
"readOnly": false
},
"mimeType": {
"type": "string",
"description": "MIME type of the image file",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ internal class MutationResolver(private val internalLogger: InternalLogger) {
?: MobileSegment.WireframeClip(0, 0, 0, 0)
)
}
if (prevWireframe.base64 != currentWireframe.base64) {
mutation = mutation.copy(base64 = currentWireframe.base64)
if (prevWireframe.resourceId != currentWireframe.resourceId) {
mutation = mutation.copy(resourceId = currentWireframe.resourceId)
}
if (prevWireframe.mimeType != currentWireframe.mimeType) {
mutation = mutation.copy(mimeType = currentWireframe.mimeType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ import com.datadog.android.sessionreplay.internal.utils.CacheUtils
import com.datadog.android.sessionreplay.internal.utils.InvocationUtils

internal class Base64LRUCache(
private val cacheUtils: CacheUtils<String, ByteArray> = CacheUtils(),
private val cacheUtils: CacheUtils<String, CacheData> = CacheUtils(),
private val invocationUtils: InvocationUtils = InvocationUtils(),
private var cache: LruCache<String, ByteArray> =
private var cache: LruCache<String, CacheData> =
object :
LruCache<String, ByteArray>(MAX_CACHE_MEMORY_SIZE_BYTES) {
override fun sizeOf(key: String, value: ByteArray): Int {
return value.size
LruCache<String, CacheData>(MAX_CACHE_MEMORY_SIZE_BYTES) {
override fun sizeOf(key: String, value: CacheData): Int {
val base64Size = value.base64Encoding.size
val hashSize = value.resourceId?.size ?: 0
return base64Size + hashSize
}
}
) : Cache<Drawable, String>, ComponentCallbacks2 {
) : Cache<Drawable, CacheData>, ComponentCallbacks2 {

override fun onTrimMemory(level: Int) {
cacheUtils.handleTrimMemory(level, cache)
Expand All @@ -45,24 +47,27 @@ internal class Base64LRUCache(
}

@Synchronized
override fun put(element: Drawable, value: String) {
override fun put(element: Drawable, value: CacheData) {
val key = generateKey(element)
val byteArray = value.toByteArray(Charsets.UTF_8)
val base64Encoding = value.base64Encoding
val resourceId = value.resourceId

@Suppress("UnsafeThirdPartyFunctionCall") // Called within a try/catch block
invocationUtils.safeCallWithErrorLogging(
call = { cache.put(key, byteArray) },
call = { cache.put(key, CacheData(base64Encoding, resourceId)) },
failureMessage = FAILURE_MSG_PUT_CACHE
)
}

@Synchronized
override fun get(element: Drawable): String? =
override fun get(element: Drawable): CacheData? =
@Suppress("UnsafeThirdPartyFunctionCall") // Called within a try/catch block
invocationUtils.safeCallWithErrorLogging(
call = {
cache.get(generateKey(element))?.let {
String(it)
val base64Encoding = it.base64Encoding
val resourceId = it.resourceId
CacheData(base64Encoding, resourceId)
}
},
failureMessage = FAILURE_MSG_GET_CACHE
Expand Down Expand Up @@ -119,3 +124,27 @@ internal class Base64LRUCache(
private const val FAILURE_MSG_GET_CACHE = "Failed to get item from cache"
}
}

internal data class CacheData(val base64Encoding: ByteArray, var resourceId: ByteArray?) {
// we must override these methods because we are using arrays as properties
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as CacheData

if (!base64Encoding.contentEquals(other.base64Encoding)) return false
if (resourceId != null) {
if (other.resourceId == null) return false
if (!resourceId.contentEquals(other.resourceId)) return false
} else if (other.resourceId != null) return false

return true
}

override fun hashCode(): Int {
var result = base64Encoding.contentHashCode()
result = 31 * result + (resourceId?.contentHashCode() ?: 0)
return result
}
}
Loading

0 comments on commit f38f6be

Please sign in to comment.