-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RUM-6197: Add ImageSemanticsNodeMapper to support image role for SR
- Loading branch information
1 parent
a0a5cf8
commit 830ef53
Showing
17 changed files
with
605 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
140 changes: 140 additions & 0 deletions
140
...adog/android/sessionreplay/compose/internal/mappers/semantics/ImageSemanticsNodeMapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
package com.datadog.android.sessionreplay.compose.internal.mappers.semantics | ||
|
||
import android.content.Context | ||
import android.graphics.Bitmap | ||
import android.view.ViewGroup | ||
import androidx.compose.ui.graphics.painter.BitmapPainter | ||
import androidx.compose.ui.graphics.painter.Painter | ||
import androidx.compose.ui.graphics.vector.VectorPainter | ||
import androidx.compose.ui.semantics.SemanticsNode | ||
import com.datadog.android.sessionreplay.ImagePrivacy | ||
import com.datadog.android.sessionreplay.compose.internal.data.ComposeWireframe | ||
import com.datadog.android.sessionreplay.compose.internal.data.UiContext | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.BitmapField | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ContentPainterModifierClass | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ImageField | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.LayoutNodeOwnerField | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterElementClass | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterField | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfAsyncImagePainter | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfContentPainter | ||
import com.datadog.android.sessionreplay.compose.internal.reflection.getSafe | ||
import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback | ||
import com.datadog.android.sessionreplay.utils.ColorStringFormatter | ||
|
||
internal class ImageSemanticsNodeMapper( | ||
colorStringFormatter: ColorStringFormatter | ||
) : AbstractSemanticsNodeMapper(colorStringFormatter) { | ||
|
||
private var applicationContext: Context? = null | ||
|
||
override fun map( | ||
semanticsNode: SemanticsNode, | ||
parentContext: UiContext, | ||
asyncJobStatusCallback: AsyncJobStatusCallback | ||
): ComposeWireframe? { | ||
val bounds = resolveBound(semanticsNode) | ||
val bitmapInfo = resolveSemanticsPainter(semanticsNode) | ||
if (applicationContext == null) { | ||
applicationContext = resolveApplicationContext(semanticsNode) | ||
} | ||
val imageWireframe = applicationContext?.let { context -> | ||
if (bitmapInfo != null) { | ||
parentContext.imageWireframeHelper.createImageWireframe( | ||
id = semanticsNode.id.toLong(), | ||
globalBounds = bounds, | ||
applicationContext = context, | ||
bitmap = bitmapInfo.bitmap, | ||
density = parentContext.density, | ||
isContextualImage = bitmapInfo.isContextualImage, | ||
imagePrivacy = ImagePrivacy.MASK_NONE, | ||
asyncJobStatusCallback = asyncJobStatusCallback, | ||
clipping = null, | ||
shapeStyle = null, | ||
border = null | ||
) | ||
} else { | ||
null | ||
} | ||
} | ||
return imageWireframe?.let { | ||
ComposeWireframe( | ||
imageWireframe, | ||
null | ||
) | ||
} | ||
} | ||
|
||
private fun resolveSemanticsPainter( | ||
semanticsNode: SemanticsNode | ||
): BitmapInfo? { | ||
var isContextualImage = false | ||
var painter = tryParseLocalImagePainter(semanticsNode) | ||
if (painter == null) { | ||
painter = tryParseAsyncImagePainter(semanticsNode) | ||
if (painter != null) { | ||
isContextualImage = true | ||
} | ||
} | ||
// TODO RUM-6535: support more painters. | ||
val bitmap = when (painter) { | ||
is BitmapPainter -> tryParseBitmapPainterToBitmap(painter) | ||
is VectorPainter -> tryParseVectorPainterToBitmap(painter) | ||
else -> { | ||
null | ||
} | ||
} | ||
|
||
val newBitmap = bitmap?.let { | ||
@Suppress("UnsafeThirdPartyFunctionCall") // isMutable is always false | ||
it.copy(it.config, false) | ||
} | ||
return newBitmap?.let { | ||
BitmapInfo(it, isContextualImage) | ||
} | ||
} | ||
|
||
private fun resolveApplicationContext(semanticsNode: SemanticsNode): Context? { | ||
val owner = LayoutNodeOwnerField?.getSafe(semanticsNode.layoutInfo) as? ViewGroup | ||
return owner?.context | ||
} | ||
|
||
private fun tryParseVectorPainterToBitmap(vectorPainter: VectorPainter): Bitmap? { | ||
val vector = ComposeReflection.VectorField?.getSafe(vectorPainter) | ||
val cacheDrawScope = ComposeReflection.CacheDrawScopeField?.getSafe(vector) | ||
val mCachedImage = ComposeReflection.CachedImageField?.getSafe(cacheDrawScope) | ||
return BitmapField?.getSafe(mCachedImage) as? Bitmap | ||
} | ||
|
||
private fun tryParseBitmapPainterToBitmap(bitmapPainter: BitmapPainter): Bitmap? { | ||
val image = ImageField?.getSafe(bitmapPainter) | ||
return BitmapField?.getSafe(image) as? Bitmap | ||
} | ||
|
||
private fun tryParseLocalImagePainter(semanticsNode: SemanticsNode): Painter? { | ||
val modifier = semanticsNode.layoutInfo.getModifierInfo().firstOrNull { | ||
PainterElementClass?.isInstance(it.modifier) == true | ||
}?.modifier | ||
return PainterField?.getSafe(modifier) as? Painter | ||
} | ||
|
||
private fun tryParseAsyncImagePainter(semanticsNode: SemanticsNode): Painter? { | ||
val modifier = semanticsNode.layoutInfo.getModifierInfo().firstOrNull { | ||
ContentPainterModifierClass?.isInstance(it.modifier) == true | ||
}?.modifier | ||
val asyncPainter = PainterFieldOfContentPainter?.getSafe(modifier) | ||
return PainterFieldOfAsyncImagePainter?.getSafe(asyncPainter) as? Painter | ||
} | ||
|
||
private data class BitmapInfo( | ||
val bitmap: Bitmap, | ||
val isContextualImage: Boolean | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.