Skip to content

Commit 0d7a259

Browse files
authored
Merge pull request #3561 from DataDog/jmoskovich/fix-background-colors
Fix regression of missing tinted backgrounds
2 parents d4b6be3 + f1a1823 commit 0d7a259

4 files changed

Lines changed: 54 additions & 17 deletions

File tree

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ internal open class AndroidMDrawableToColorMapper(
136136

137137
@RequiresApi(Build.VERSION_CODES.N)
138138
internal fun resolveGradientDrawableNPlus(drawable: GradientDrawable): Int? {
139-
return resolveGradientFillColor(drawable)?.let { resolvedColor ->
140-
val colorAlpha = (resolvedColor ushr ALPHA_SHIFT_ANDROID) and MAX_ALPHA_VALUE
141-
val fillAlpha = (colorAlpha * drawable.alpha) / MAX_ALPHA_VALUE
142-
if (fillAlpha == 0) null else mergeColorAndAlpha(resolvedColor, fillAlpha)
143-
}
139+
val resolvedColor = resolveGradientFillColor(drawable)
140+
if (resolvedColor == null || drawable.colorFilter == null) return null
141+
val colorAlpha = (resolvedColor ushr ALPHA_SHIFT_ANDROID) and MAX_ALPHA_VALUE
142+
val fillAlpha = (colorAlpha * drawable.alpha) / MAX_ALPHA_VALUE
143+
return if (fillAlpha == 0) null else mergeColorAndAlpha(resolvedColor, fillAlpha)
144144
}
145145

146146
@Suppress("SwallowedException")

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,17 @@ internal open class AndroidQDrawableToColorMapper(
2828
) : AndroidMDrawableToColorMapper(extensionMappers) {
2929

3030
override fun resolveGradientDrawable(drawable: GradientDrawable, internalLogger: InternalLogger): Int? {
31-
val resolvedColor = resolveGradientFillColor(drawable) ?: return null
31+
val resolvedColor = resolveGradientFillColor(drawable)
32+
val colorFilter = resolveGradientColorFilter(drawable)
33+
if (resolvedColor == null || colorFilter == null) return null
3234
val colorAlpha = (resolvedColor ushr ALPHA_SHIFT_ANDROID) and MAX_ALPHA_VALUE
3335
val fillAlpha = (colorAlpha * drawable.alpha) / MAX_ALPHA_VALUE
34-
val colorFilter = resolveGradientColorFilter(drawable)
35-
val fillColor = if (colorFilter != null) {
36-
resolveBlendModeColorFilter(resolvedColor, colorFilter, internalLogger)
37-
} else {
38-
resolvedColor
39-
}
36+
val fillColor = resolveBlendModeColorFilter(resolvedColor, colorFilter, internalLogger)
4037
return if (fillAlpha == 0) null else mergeColorAndAlpha(fillColor, fillAlpha)
4138
}
4239

43-
protected open fun resolveGradientColorFilter(drawable: GradientDrawable): ColorFilter? = drawable.colorFilter
40+
protected open fun resolveGradientColorFilter(drawable: GradientDrawable): ColorFilter? =
41+
drawable.colorFilter
4442

4543
/**
4644
* This is an oversimplification as the result image would only have some

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ open class AndroidMDrawableToColorMapperTest {
153153
}
154154

155155
@Test
156-
fun `M map GradientDrawable to fill paint's color W mapDrawableToColor()`(
156+
open fun `M map GradientDrawable to fill paint's color W mapDrawableToColor()`(
157157
@IntForgery drawableColor: Int
158158
) {
159159
// Given
@@ -283,20 +283,20 @@ open class AndroidMDrawableToColorMapperTest {
283283
}
284284

285285
@Test
286-
fun `M map GradientDrawable to fill color W resolveGradientDrawableNPlus() {public API path}`(
286+
fun `M return null W resolveGradientDrawableNPlus() {public API path, no color filter}`(
287287
@IntForgery fillColor: Int
288288
) {
289289
// Given
290290
val baseAlpha = (fillColor.toLong() and 0xFF000000) shr 24
291291
assumeTrue(baseAlpha != 0L)
292292
val testableMMapper = TestableMMapper().apply { fakeResolvedColor = fillColor }
293-
val gradientDrawable = GradientDrawable()
293+
val gradientDrawable = GradientDrawable() // colorFilter is null by default
294294

295295
// When
296296
val result = testableMMapper.resolveGradientDrawableNPlus(gradientDrawable)
297297

298298
// Then
299-
assertThat(result).isEqualTo(fillColor)
299+
assertThat(result).isNull()
300300
}
301301

302302
@Test

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,45 @@ class AndroidQDrawableToColorMapperTest : AndroidMDrawableToColorMapperTest() {
144144
assertThat(result).isNull()
145145
}
146146

147+
@Test
148+
fun `M return null W mapDrawableToColor {no accessible color filter}`(
149+
@IntForgery fillColor: Int
150+
) {
151+
// When drawable.colorFilter is null (e.g. tint applied via DrawableCompat.setTintList,
152+
// which stores it in the blocked private Drawable.mTintFilter on API 28+), the mapper
153+
// returns null so the image wireframe path captures the actual tinted appearance.
154+
val baseAlpha = (fillColor.toLong() and 0xFF000000) shr 24
155+
assumeTrue(baseAlpha != 0L)
156+
testableMapper.fakeResolvedColor = fillColor
157+
testableMapper.fakeColorFilter = null
158+
val gradientDrawable = GradientDrawable()
159+
160+
val result = testedMapper.mapDrawableToColor(gradientDrawable, mockInternalLogger)
161+
162+
assertThat(result).isNull()
163+
}
164+
165+
@Test
166+
override fun `M map GradientDrawable to fill paint's color W mapDrawableToColor()`(
167+
@IntForgery drawableColor: Int
168+
) {
169+
// On Q+, when no color filter is accessible (drawable.colorFilter is null), the mapper
170+
// returns null regardless of the fill color so the image wireframe path is used instead.
171+
val baseAlpha = (drawableColor.toLong() and 0xFF000000) shr 24
172+
assumeTrue(baseAlpha != 0L)
173+
val mockFillPaint = mock<Paint>().apply {
174+
whenever(this.color) doReturn (drawableColor and 0xFFFFFF)
175+
whenever(this.alpha) doReturn baseAlpha.toInt()
176+
}
177+
val gradientDrawable = GradientDrawable().apply {
178+
AndroidMDrawableToColorMapper.fillPaintField?.set(this, mockFillPaint)
179+
}
180+
181+
val result = testedMapper.mapDrawableToColor(gradientDrawable, mockInternalLogger)
182+
183+
assertThat(result).isNull()
184+
}
185+
147186
// Seam to avoid calling API 24+ methods on the test JVM; falls back to parent-injected fillPaintField when fakeResolvedColor is null.
148187
private class TestableQMapper : AndroidQDrawableToColorMapper() {
149188
var fakeResolvedColor: Int? = null

0 commit comments

Comments
 (0)