Skip to content

Commit cfbf883

Browse files
authored
Merge 2e7b083 into e2dce0b
2 parents e2dce0b + 2e7b083 commit cfbf883

13 files changed

Lines changed: 308 additions & 73 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Fixes
6+
7+
- Session Replay: Fix Compose text masking mismatch with weighted text ([#5218](https://github.com/getsentry/sentry-java/pull/5218))
8+
59
### Features
610

711
- Android: Add `beforeErrorSampling` callback to Session Replay ([#5214](https://github.com/getsentry/sentry-java/pull/5214))

sentry-android-core/build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import org.jetbrains.kotlin.config.KotlinCompilerVersion
44
plugins {
55
id("com.android.library")
66
alias(libs.plugins.kotlin.android)
7+
alias(libs.plugins.kotlin.compose)
78
jacoco
89
alias(libs.plugins.jacoco.android)
910
alias(libs.plugins.errorprone)
@@ -108,7 +109,11 @@ dependencies {
108109
testImplementation(projects.sentryCompose)
109110
testImplementation(projects.sentryAndroidNdk)
110111
testImplementation(libs.dropbox.differ)
111-
testRuntimeOnly(libs.androidx.compose.ui)
112+
testImplementation(libs.androidx.activity.compose)
113+
testImplementation(libs.androidx.compose.ui)
114+
testImplementation(libs.androidx.compose.foundation)
115+
testImplementation(libs.androidx.compose.foundation.layout)
116+
testImplementation(libs.androidx.compose.material3)
112117
testRuntimeOnly(libs.androidx.fragment.ktx)
113118
testRuntimeOnly(libs.timber)
114119
}

sentry-android-core/src/test/java/io/sentry/android/core/ScreenshotEventProcessorTest.kt

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,27 @@ import android.graphics.Color
99
import android.graphics.drawable.Drawable
1010
import android.os.Bundle
1111
import android.os.Looper
12+
import android.text.TextUtils
1213
import android.view.View
1314
import android.widget.ImageView
1415
import android.widget.LinearLayout
1516
import android.widget.LinearLayout.LayoutParams
1617
import android.widget.RadioButton
1718
import android.widget.TextView
19+
import androidx.activity.ComponentActivity
20+
import androidx.activity.compose.setContent
21+
import androidx.compose.foundation.background
22+
import androidx.compose.foundation.layout.Arrangement
23+
import androidx.compose.foundation.layout.Column
24+
import androidx.compose.foundation.layout.Row
25+
import androidx.compose.foundation.layout.fillMaxWidth
26+
import androidx.compose.foundation.layout.padding
27+
import androidx.compose.material3.Text
28+
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.text.style.TextAlign
30+
import androidx.compose.ui.text.style.TextOverflow
31+
import androidx.compose.ui.unit.dp
32+
import androidx.compose.ui.unit.sp
1833
import androidx.test.ext.junit.runners.AndroidJUnit4
1934
import com.dropbox.differ.Color as DifferColor
2035
import com.dropbox.differ.Image
@@ -410,6 +425,48 @@ class ScreenshotEventProcessorTest {
410425
assertNotNull(bytes)
411426
}
412427

428+
@Test
429+
fun `snapshot - screenshot with ellipsized text no masking`() {
430+
fixture.activity = buildActivity(EllipsizedTextActivity::class.java, null).setup().get()
431+
val bytes =
432+
processEventForSnapshots(
433+
"screenshot_mask_ellipsized_view_unmasked",
434+
isReplayAvailable = false,
435+
)
436+
assertNotNull(bytes)
437+
}
438+
439+
@Test
440+
fun `snapshot - screenshot with ellipsized text masking`() {
441+
fixture.activity = buildActivity(EllipsizedTextActivity::class.java, null).setup().get()
442+
val bytes =
443+
processEventForSnapshots("screenshot_mask_ellipsized_view_masked") {
444+
it.screenshot.setMaskAllText(true)
445+
}
446+
assertNotNull(bytes)
447+
}
448+
449+
@Test
450+
fun `snapshot - compose text no masking`() {
451+
fixture.activity = buildActivity(ComposeTextActivity::class.java, null).setup().get()
452+
val bytes =
453+
processEventForSnapshots(
454+
"screenshot_mask_ellipsized_compose_unmasked",
455+
isReplayAvailable = false,
456+
)
457+
assertNotNull(bytes)
458+
}
459+
460+
@Test
461+
fun `snapshot - compose text with masking`() {
462+
fixture.activity = buildActivity(ComposeTextActivity::class.java, null).setup().get()
463+
val bytes =
464+
processEventForSnapshots("screenshot_mask_ellipsized_compose_masked") {
465+
it.screenshot.setMaskAllText(true)
466+
}
467+
assertNotNull(bytes)
468+
}
469+
413470
// endregion
414471

415472
private fun getEvent(): SentryEvent = SentryEvent(Throwable("Throwable"))
@@ -484,6 +541,189 @@ private class CustomView(context: Context) : View(context) {
484541
}
485542
}
486543

544+
private class EllipsizedTextActivity : Activity() {
545+
546+
override fun onCreate(savedInstanceState: Bundle?) {
547+
super.onCreate(savedInstanceState)
548+
val longText = "This is a very long text that should be ellipsized when it does not fit"
549+
550+
val linearLayout =
551+
LinearLayout(this).apply {
552+
setBackgroundColor(Color.WHITE)
553+
orientation = LinearLayout.VERTICAL
554+
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
555+
setPadding(10, 10, 10, 10)
556+
}
557+
558+
// Ellipsize end
559+
linearLayout.addView(
560+
TextView(this).apply {
561+
text = longText
562+
setTextColor(Color.BLACK)
563+
textSize = 16f
564+
maxLines = 1
565+
ellipsize = TextUtils.TruncateAt.END
566+
setBackgroundColor(Color.LTGRAY)
567+
layoutParams =
568+
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
569+
setMargins(0, 8, 0, 0)
570+
}
571+
}
572+
)
573+
574+
// Ellipsize middle
575+
linearLayout.addView(
576+
TextView(this).apply {
577+
text = longText
578+
setTextColor(Color.BLACK)
579+
textSize = 16f
580+
maxLines = 1
581+
ellipsize = TextUtils.TruncateAt.MIDDLE
582+
setBackgroundColor(Color.LTGRAY)
583+
layoutParams =
584+
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
585+
setMargins(0, 8, 0, 0)
586+
}
587+
}
588+
)
589+
590+
// Ellipsize start
591+
linearLayout.addView(
592+
TextView(this).apply {
593+
text = longText
594+
setTextColor(Color.BLACK)
595+
textSize = 16f
596+
maxLines = 1
597+
ellipsize = TextUtils.TruncateAt.START
598+
setBackgroundColor(Color.LTGRAY)
599+
layoutParams =
600+
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
601+
setMargins(0, 8, 0, 0)
602+
}
603+
}
604+
)
605+
606+
// Non-ellipsized text for comparison
607+
linearLayout.addView(
608+
TextView(this).apply {
609+
text = "Short text"
610+
setTextColor(Color.BLACK)
611+
textSize = 16f
612+
setBackgroundColor(Color.LTGRAY)
613+
layoutParams =
614+
LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
615+
setMargins(0, 8, 0, 0)
616+
}
617+
}
618+
)
619+
620+
setContentView(linearLayout)
621+
}
622+
}
623+
624+
private class ComposeTextActivity : ComponentActivity() {
625+
626+
override fun onCreate(savedInstanceState: Bundle?) {
627+
super.onCreate(savedInstanceState)
628+
val longText = "This is a very long text that should be ellipsized when it does not fit in view"
629+
630+
setContent {
631+
Column(
632+
modifier =
633+
Modifier.fillMaxWidth()
634+
.background(androidx.compose.ui.graphics.Color.White)
635+
.padding(10.dp),
636+
verticalArrangement = Arrangement.spacedBy(8.dp),
637+
) {
638+
// Ellipsis overflow
639+
Text(
640+
longText,
641+
maxLines = 1,
642+
overflow = TextOverflow.Ellipsis,
643+
fontSize = 16.sp,
644+
modifier =
645+
Modifier.fillMaxWidth().background(androidx.compose.ui.graphics.Color.LightGray),
646+
)
647+
648+
// Text with textAlign center
649+
Text(
650+
"Centered text",
651+
textAlign = TextAlign.Center,
652+
fontSize = 16.sp,
653+
modifier =
654+
Modifier.fillMaxWidth().background(androidx.compose.ui.graphics.Color.LightGray),
655+
)
656+
657+
// Text with textAlign end
658+
Text(
659+
"End-aligned text",
660+
textAlign = TextAlign.End,
661+
fontSize = 16.sp,
662+
modifier =
663+
Modifier.fillMaxWidth().background(androidx.compose.ui.graphics.Color.LightGray),
664+
)
665+
666+
// Ellipsis with textAlign center
667+
Text(
668+
longText,
669+
maxLines = 1,
670+
overflow = TextOverflow.Ellipsis,
671+
textAlign = TextAlign.Center,
672+
fontSize = 16.sp,
673+
modifier =
674+
Modifier.fillMaxWidth().background(androidx.compose.ui.graphics.Color.LightGray),
675+
)
676+
677+
// Weighted row with text
678+
Row(
679+
modifier = Modifier.fillMaxWidth(),
680+
horizontalArrangement = Arrangement.spacedBy(8.dp),
681+
) {
682+
Text(
683+
"Weight 1",
684+
fontSize = 16.sp,
685+
modifier = Modifier.weight(1f).background(androidx.compose.ui.graphics.Color.LightGray),
686+
)
687+
Text(
688+
"Weight 1",
689+
fontSize = 16.sp,
690+
modifier = Modifier.weight(1f).background(androidx.compose.ui.graphics.Color.LightGray),
691+
)
692+
}
693+
694+
// Weighted row with ellipsized text
695+
Row(
696+
modifier = Modifier.fillMaxWidth(),
697+
horizontalArrangement = Arrangement.spacedBy(8.dp),
698+
) {
699+
Text(
700+
longText,
701+
maxLines = 1,
702+
overflow = TextOverflow.Ellipsis,
703+
fontSize = 16.sp,
704+
modifier = Modifier.weight(1f).background(androidx.compose.ui.graphics.Color.LightGray),
705+
)
706+
Text(
707+
longText,
708+
maxLines = 1,
709+
overflow = TextOverflow.Ellipsis,
710+
textAlign = TextAlign.End,
711+
fontSize = 16.sp,
712+
modifier = Modifier.weight(1f).background(androidx.compose.ui.graphics.Color.LightGray),
713+
)
714+
}
715+
716+
// Short text (for comparison)
717+
Text(
718+
"Short text",
719+
fontSize = 16.sp,
720+
modifier = Modifier.background(androidx.compose.ui.graphics.Color.LightGray),
721+
)
722+
}
723+
}
724+
}
725+
}
726+
487727
private class MaskingActivity : Activity() {
488728

489729
override fun onCreate(savedInstanceState: Bundle?) {
-65 Bytes
Loading
2.85 KB
Loading
19.9 KB
Loading
2.28 KB
Loading
16.4 KB
Loading
-62 Bytes
Loading

0 commit comments

Comments
 (0)