diff --git a/WORKSPACE b/WORKSPACE
index 7b21505c587..0c20dcd36a1 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -125,9 +125,9 @@ git_repository(
# to correctly size in-line SVGs (such as those needed for LaTeX-based math expressions).
git_repository(
name = "androidsvg",
- commit = "4bc1d26412f0fb9fd4ef263fa93f6a64f4d4dbcf",
+ commit = "1265eb1087056cf3fc2e10442e5545bc65c109ce",
remote = "https://github.com/oppia/androidsvg",
- shallow_since = "1647295507 -0700",
+ shallow_since = "1686302944 -0700",
)
git_repository(
diff --git a/app/src/test/java/org/oppia/android/app/parser/ListItemLeadingMarginSpanTest.kt b/app/src/test/java/org/oppia/android/app/parser/ListItemLeadingMarginSpanTest.kt
index b7515853e05..91339129701 100644
--- a/app/src/test/java/org/oppia/android/app/parser/ListItemLeadingMarginSpanTest.kt
+++ b/app/src/test/java/org/oppia/android/app/parser/ListItemLeadingMarginSpanTest.kt
@@ -562,16 +562,16 @@ class ListItemLeadingMarginSpanTest {
textView.layout
)
- assertThat(shadowCanvas.getDrawnCircle(0).centerX).isWithin(1e-5f).of(944.0f)
+ assertThat(shadowCanvas.getDrawnCircle(0).centerX).isWithin(1e-5f).of(926.0f)
assertThat(shadowCanvas.getDrawnCircle(0).centerY).isWithin(1e-5f).of(48.0f)
- assertThat(shadowCanvas.getDrawnCircle(1).centerX).isWithin(1e-5f).of(878.0f)
+ assertThat(shadowCanvas.getDrawnCircle(1).centerX).isWithin(1e-5f).of(860.0f)
assertThat(shadowCanvas.getDrawnCircle(1).centerY).isWithin(1e-5f).of(139.0f)
- assertThat(shadowCanvas.getDrawnCircle(2).centerX).isWithin(1e-5f).of(878.0f)
+ assertThat(shadowCanvas.getDrawnCircle(2).centerX).isWithin(1e-5f).of(860.0f)
assertThat(shadowCanvas.getDrawnCircle(2).centerY).isWithin(1e-5f).of(225.0f)
- assertThat(shadowCanvas.getDrawnCircle(3).centerX).isWithin(1e-5f).of(944.0f)
+ assertThat(shadowCanvas.getDrawnCircle(3).centerX).isWithin(1e-5f).of(926.0f)
assertThat(shadowCanvas.getDrawnCircle(3).centerY).isWithin(1e-5f).of(397.0f)
}
diff --git a/utility/build.gradle b/utility/build.gradle
index 568eac1841b..52164f42b34 100644
--- a/utility/build.gradle
+++ b/utility/build.gradle
@@ -82,7 +82,7 @@ dependencies {
'androidx.appcompat:appcompat:1.0.2',
'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha03',
'androidx.work:work-runtime-ktx:2.4.0',
- 'com.github.oppia:androidsvg:4bc1d26412f0fb9fd4ef263fa93f6a64f4d4dbcf',
+ 'com.github.oppia:androidsvg:1265eb1087056cf3fc2e10442e5545bc65c109ce',
'com.github.oppia:kotlitex:43139c140833c7120f351d63d74b42c253d2b213',
'com.github.bumptech.glide:glide:4.11.0',
'com.google.dagger:dagger:2.24',
diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ImageTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ImageTagHandler.kt
index 39ccbe5e9e4..27bdc52cb37 100644
--- a/utility/src/main/java/org/oppia/android/util/parser/html/ImageTagHandler.kt
+++ b/utility/src/main/java/org/oppia/android/util/parser/html/ImageTagHandler.kt
@@ -48,12 +48,12 @@ class ImageTagHandler(
)
}
} else consoleLogger.e("ImageTagHandler", "Failed to parse image tag")
- if (contentDescription != null) {
+ if (!contentDescription.isNullOrBlank()) {
val spannableBuilder = SpannableStringBuilder(contentDescription)
spannableBuilder.setSpan(
contentDescription,
- /* start= */ 0,
- /* end= */ contentDescription.length,
+ /* start = */ 0,
+ /* end = */ contentDescription.length,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
output.replace(openIndex, output.length, spannableBuilder)
diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ListItemLeadingMarginSpan.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ListItemLeadingMarginSpan.kt
index 36bce0e79df..de1c028aed2 100644
--- a/utility/src/main/java/org/oppia/android/util/parser/html/ListItemLeadingMarginSpan.kt
+++ b/utility/src/main/java/org/oppia/android/util/parser/html/ListItemLeadingMarginSpan.kt
@@ -46,6 +46,7 @@ sealed class ListItemLeadingMarginSpan : LeadingMarginSpan {
private val isRtl by lazy {
displayLocale.getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL
}
+ private val clipBounds by lazy { Rect() }
override fun drawLeadingMargin(
canvas: Canvas,
@@ -69,8 +70,14 @@ sealed class ListItemLeadingMarginSpan : LeadingMarginSpan {
val bulletDrawRadius = bulletRadius.toFloat()
val indentedX = parentAbsoluteLeadingMargin + spacingBeforeBullet
- val bulletStartX = (if (isRtl) canvas.width - indentedX - 1 else indentedX).toFloat()
- val bulletCenterX = bulletStartX + bulletDrawRadius
+ val bulletCenterLtrX = indentedX + bulletDrawRadius
+ val bulletCenterX = if (isRtl) {
+ // See https://stackoverflow.com/a/21845993/3689782 for 'right' property exclusivity.
+ val maxDrawX = if (canvas.getClipBounds(clipBounds)) {
+ clipBounds.right - 1
+ } else canvas.width - 1
+ maxDrawX - bulletCenterLtrX
+ } else bulletCenterLtrX
val bulletCenterY = (top + bottom) / 2f
when (indentationLevel) {
0 -> {
@@ -90,7 +97,7 @@ sealed class ListItemLeadingMarginSpan : LeadingMarginSpan {
val rectSize = bulletDiameter.toFloat()
canvas.drawRect(
RectF().apply {
- left = bulletStartX
+ left = bulletCenterX
right = left + rectSize
this.top = bulletCenterY - bulletDrawRadius
this.bottom = this.top + rectSize
diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ImageTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ImageTagHandlerTest.kt
index f13ca551998..17219b230f7 100644
--- a/utility/src/test/java/org/oppia/android/util/parser/html/ImageTagHandlerTest.kt
+++ b/utility/src/test/java/org/oppia/android/util/parser/html/ImageTagHandlerTest.kt
@@ -55,6 +55,21 @@ private const val IMAGE_TAG_WITHOUT_ALT_VALUE_MARKUP =
""
+private const val IMAGE_TAG_WITH_EMPTY_ALT_VALUE_MARKUP =
+ ""
+
+private const val IMAGE_TAG_WITH_EMPTY_STRING_ALT_VALUE_MARKUP =
+ ""
+
+private const val IMAGE_TAG_WITH_SPACE_ONLY_ALT_VALUE_MARKUP =
+ ""
+
/** Tests for [ImageTagHandler]. */
@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
@@ -138,6 +153,51 @@ class ImageTagHandlerTest {
assertThat(parsedHtml.first().isObjectReplacementCharacter()).isFalse()
}
+ @Test
+ fun testParseHtml_withEmptyImageCardMarkup_hasNoReadableText() {
+ val parsedHtml =
+ CustomHtmlContentHandler.fromHtml(
+ html = IMAGE_TAG_WITH_EMPTY_ALT_VALUE_MARKUP,
+ imageRetriever = mockImageRetriever,
+ customTagHandlers = tagHandlersWithImageTagSupport
+ )
+
+ // If the alt text is present but empty, then only the image control character should show.
+ val parsedHtmlStr = parsedHtml.toString()
+ assertThat(parsedHtmlStr).hasLength(1)
+ assertThat(parsedHtmlStr.first().isObjectReplacementCharacter()).isTrue()
+ }
+
+ @Test
+ fun testParseHtml_withEmptyImageCardMarkupString_hasNoReadableText() {
+ val parsedHtml =
+ CustomHtmlContentHandler.fromHtml(
+ html = IMAGE_TAG_WITH_EMPTY_STRING_ALT_VALUE_MARKUP,
+ imageRetriever = mockImageRetriever,
+ customTagHandlers = tagHandlersWithImageTagSupport
+ )
+
+ // If the alt text is present but empty, then only the image control character should show.
+ val parsedHtmlStr = parsedHtml.toString()
+ assertThat(parsedHtmlStr).hasLength(1)
+ assertThat(parsedHtmlStr.first().isObjectReplacementCharacter()).isTrue()
+ }
+
+ @Test
+ fun testParseHtml_withSpaceOnlyImageCardMarkup_hasNoReadableText() {
+ val parsedHtml =
+ CustomHtmlContentHandler.fromHtml(
+ html = IMAGE_TAG_WITH_SPACE_ONLY_ALT_VALUE_MARKUP,
+ imageRetriever = mockImageRetriever,
+ customTagHandlers = tagHandlersWithImageTagSupport
+ )
+
+ // If the alt text is present but only spaces, then the image control character should show.
+ val parsedHtmlStr = parsedHtml.toString()
+ assertThat(parsedHtmlStr).hasLength(1)
+ assertThat(parsedHtmlStr.first().isObjectReplacementCharacter()).isTrue()
+ }
+
@Test
fun testParseHtml_withImageCardMarkup_missingFilename_doesNotIncludeImageSpan() {
val parsedHtml =