From bd4eee442690798cead065cae2274467c2a2376f Mon Sep 17 00:00:00 2001 From: manas-yu Date: Wed, 18 Dec 2024 11:10:01 +0530 Subject: [PATCH 01/18] initial --- .../android/util/parser/html/CustomHtmlContentHandler.kt | 2 +- .../android/util/parser/html/CustomHtmlContentHandlerTest.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index f07310b7a9e..9c16e654ae4 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -11,7 +11,7 @@ import org.xml.sax.Attributes import org.xml.sax.ContentHandler import org.xml.sax.Locator import org.xml.sax.XMLReader - +// https://chatgpt.com/c/6761e49f-6824-8003-b645-7913e8c73bbc /** * A custom [ContentHandler] and [Html.TagHandler] for processing custom HTML tags. This class must * be used if a custom tag attribute must be parsed. diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index 2042ef72ec8..c5d9dd93e4d 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -316,7 +316,7 @@ class CustomHtmlContentHandlerTest { return DisplayLocaleImpl(context, formattingLocale, machineLocale, formatterFactory) } - private class FakeTagHandler : CustomHtmlContentHandler.CustomTagHandler { + private class FakeTagHandler : CustomTagHandler { var handleTagCalled = false var handleTagCallIndex = -1 var handleOpeningTagCalled = false @@ -358,7 +358,7 @@ class CustomHtmlContentHandlerTest { private class ReplacingTagHandler( private val attributeTextToReplaceWith: String - ) : CustomHtmlContentHandler.CustomTagHandler { + ) : CustomTagHandler { override fun handleTag( attributes: Attributes, openIndex: Int, From 49b199c22d812c8070deee1b2eb890b830aa8da1 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Thu, 19 Dec 2024 02:11:55 +0530 Subject: [PATCH 02/18] content builder --- .../parser/html/CustomHtmlContentHandler.kt | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index 9c16e654ae4..1e2c0b1d93e 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -11,7 +11,7 @@ import org.xml.sax.Attributes import org.xml.sax.ContentHandler import org.xml.sax.Locator import org.xml.sax.XMLReader -// https://chatgpt.com/c/6761e49f-6824-8003-b645-7913e8c73bbc + /** * A custom [ContentHandler] and [Html.TagHandler] for processing custom HTML tags. This class must * be used if a custom tag attribute must be parsed. @@ -20,11 +20,13 @@ import org.xml.sax.XMLReader */ class CustomHtmlContentHandler private constructor( private val customTagHandlers: Map, - private val imageRetriever: ImageRetriever? + private val imageRetriever: ImageRetriever?, + private val onContentDescriptionGenerated: ((String) -> Unit)? = null ) : ContentHandler, Html.TagHandler { private var originalContentHandler: ContentHandler? = null private var currentTrackedTag: TrackedTag? = null private val currentTrackedCustomTags = ArrayDeque() + private val contentDescriptionBuilder = StringBuilder() override fun endElement(uri: String?, localName: String?, qName: String?) { originalContentHandler?.endElement(uri, localName, qName) @@ -50,6 +52,7 @@ class CustomHtmlContentHandler private constructor( override fun endDocument() { originalContentHandler?.endDocument() originalContentHandler = null // There's nothing left to read. + onContentDescriptionGenerated?.invoke(contentDescriptionBuilder.toString().trim()) } override fun startElement(uri: String?, localName: String?, qName: String?, atts: Attributes?) { @@ -95,6 +98,8 @@ class CustomHtmlContentHandler private constructor( check(localCurrentTrackedTag.tag == tag) { "Expected tracked tag $currentTrackedTag to match custom tag: $tag" } + val description = customTagHandlers[tag]?.extractContentDescription(localCurrentTrackedTag.attributes) + description?.let { contentDescriptionBuilder.append(it).append(" ") } currentTrackedCustomTags += TrackedCustomTag( localCurrentTrackedTag.tag, localCurrentTrackedTag.attributes, output.length ) @@ -144,6 +149,22 @@ class CustomHtmlContentHandler private constructor( ) { } + fun extractContentDescription(attributes: Attributes): String? { + val attributeValues = mutableListOf() + + for (i in 0 until attributes.length) { + val value = attributes.getValue(i) + if (value != null) { + attributeValues.add(value) + } + } + + return if (attributeValues.isNotEmpty()) { + attributeValues.joinToString(" ") + } else { + null + } + } /** * Called when the opening of a custom tag is encountered. This does not support processing * attributes of the tag--[handleTag] should be used, instead. From de8ac643418c7d71385d75f85c4f18eb1ca83e55 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sat, 21 Dec 2024 18:25:21 +0530 Subject: [PATCH 03/18] revert --- .../parser/html/CustomHtmlContentHandler.kt | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index 1e2c0b1d93e..f07310b7a9e 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -20,13 +20,11 @@ import org.xml.sax.XMLReader */ class CustomHtmlContentHandler private constructor( private val customTagHandlers: Map, - private val imageRetriever: ImageRetriever?, - private val onContentDescriptionGenerated: ((String) -> Unit)? = null + private val imageRetriever: ImageRetriever? ) : ContentHandler, Html.TagHandler { private var originalContentHandler: ContentHandler? = null private var currentTrackedTag: TrackedTag? = null private val currentTrackedCustomTags = ArrayDeque() - private val contentDescriptionBuilder = StringBuilder() override fun endElement(uri: String?, localName: String?, qName: String?) { originalContentHandler?.endElement(uri, localName, qName) @@ -52,7 +50,6 @@ class CustomHtmlContentHandler private constructor( override fun endDocument() { originalContentHandler?.endDocument() originalContentHandler = null // There's nothing left to read. - onContentDescriptionGenerated?.invoke(contentDescriptionBuilder.toString().trim()) } override fun startElement(uri: String?, localName: String?, qName: String?, atts: Attributes?) { @@ -98,8 +95,6 @@ class CustomHtmlContentHandler private constructor( check(localCurrentTrackedTag.tag == tag) { "Expected tracked tag $currentTrackedTag to match custom tag: $tag" } - val description = customTagHandlers[tag]?.extractContentDescription(localCurrentTrackedTag.attributes) - description?.let { contentDescriptionBuilder.append(it).append(" ") } currentTrackedCustomTags += TrackedCustomTag( localCurrentTrackedTag.tag, localCurrentTrackedTag.attributes, output.length ) @@ -149,22 +144,6 @@ class CustomHtmlContentHandler private constructor( ) { } - fun extractContentDescription(attributes: Attributes): String? { - val attributeValues = mutableListOf() - - for (i in 0 until attributes.length) { - val value = attributes.getValue(i) - if (value != null) { - attributeValues.add(value) - } - } - - return if (attributeValues.isNotEmpty()) { - attributeValues.joinToString(" ") - } else { - null - } - } /** * Called when the opening of a custom tag is encountered. This does not support processing * attributes of the tag--[handleTag] should be used, instead. From 3ee8154f687a496b941a2398d8739017a760809c Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 01:46:44 +0530 Subject: [PATCH 04/18] adding description for concept-card --- .../util/parser/html/ConceptCardTagHandler.kt | 10 +++- .../parser/html/CustomHtmlContentHandler.kt | 57 ++++++++++++++++++- .../parser/html/ConceptCardTagHandlerTest.kt | 10 ++++ .../html/CustomHtmlContentHandlerTest.kt | 32 +++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt index e9dbd1dac86..2be3a032e66 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt @@ -15,7 +15,7 @@ const val CUSTOM_CONCEPT_CARD_TAG = "oppia-noninteractive-skillreview" class ConceptCardTagHandler( private val listener: ConceptCardLinkClickListener, private val consoleLogger: ConsoleLogger -) : CustomHtmlContentHandler.CustomTagHandler { +) : CustomHtmlContentHandler.CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { override fun handleTag( attributes: Attributes, openIndex: Int, @@ -48,4 +48,12 @@ class ConceptCardTagHandler( */ fun onConceptCardLinkClicked(view: View, skillId: String) } + + override fun getContentDescription(attributes: Attributes): String? { + val skillId = attributes.getJsonStringValue("skill_id-with-value") + val text = attributes.getJsonStringValue("text-with-value") + return if (skillId != null && text != null) { + "$text concept card" + } else null + } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index f07310b7a9e..d5a0287e664 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -25,6 +25,8 @@ class CustomHtmlContentHandler private constructor( private var originalContentHandler: ContentHandler? = null private var currentTrackedTag: TrackedTag? = null private val currentTrackedCustomTags = ArrayDeque() + private val contentDescriptionBuilder = StringBuilder() + private val tagContentDescriptions = mutableMapOf() override fun endElement(uri: String?, localName: String?, qName: String?) { originalContentHandler?.endElement(uri, localName, qName) @@ -45,6 +47,7 @@ class CustomHtmlContentHandler private constructor( override fun characters(ch: CharArray?, start: Int, length: Int) { originalContentHandler?.characters(ch, start, length) + ch?.let { contentDescriptionBuilder.append(String(it, start, length)) } } override fun endDocument() { @@ -110,6 +113,14 @@ class CustomHtmlContentHandler private constructor( "Expected tracked tag $currentTrackedTag to match custom tag: $tag" } val (_, attributes, openTagIndex) = currentTrackedCustomTag + + val handler = customTagHandlers.getValue(tag) + if (handler is ContentDescriptionProvider) { + val contentDesc = handler.getContentDescription(attributes) + if (contentDesc != null) { + tagContentDescriptions[openTagIndex] = contentDesc + } + } customTagHandlers.getValue(tag).handleClosingTag(output, indentation = 0, tag) customTagHandlers.getValue(tag) .handleTag(attributes, openTagIndex, output.length, output, imageRetriever) @@ -123,7 +134,25 @@ class CustomHtmlContentHandler private constructor( val attributes: Attributes, val openTagIndex: Int ) - + /** + * Returns the complete content description for the processed HTML, including descriptions + * from all custom tags. + */ + private fun getContentDescription(): String { + return buildString { + var lastIndex = 0 + tagContentDescriptions.entries.sortedBy { it.key }.forEach { (index, description) -> + if (index > lastIndex) { + append(contentDescriptionBuilder.substring(lastIndex, index)) + } + append(description) + lastIndex = index + } + if (lastIndex < contentDescriptionBuilder.length) { + append(contentDescriptionBuilder.substring(lastIndex)) + } + }.trim() + } /** Handler interface for a custom tag and its attributes. */ interface CustomTagHandler { /** @@ -165,7 +194,13 @@ class CustomHtmlContentHandler private constructor( */ fun handleClosingTag(output: Editable, indentation: Int, tag: String) {} } - + interface ContentDescriptionProvider { + /** + * Returns a content description string for this tag based on its attributes, + * or null if no description is available. + */ + fun getContentDescription(attributes: Attributes): String? + } /** * Retriever of images for custom tag handlers. The built-in Android analog for this class is * Html's ImageGetter. @@ -196,6 +231,24 @@ class CustomHtmlContentHandler private constructor( } companion object { + /** + * Returns the content description for the HTML content, processing all custom tags that implement + * [ContentDescriptionProvider]. + */ + fun getContentDescription( + html: String, + imageRetriever: T?, + customTagHandlers: Map + ): String where T : Html.ImageGetter, T : ImageRetriever { + val handler = CustomHtmlContentHandler(customTagHandlers, imageRetriever) + HtmlCompat.fromHtml( + "$html", + HtmlCompat.FROM_HTML_MODE_LEGACY, + imageRetriever, + handler + ) + return handler.getContentDescription() + } /** * Returns a new [Spannable] with HTML parsed from [html] using the specified [imageRetriever] * for handling image retrieval, and map of tags to [CustomTagHandler]s for handling custom diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 4d70a5d1b4f..503866c3f53 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -116,6 +116,16 @@ class ConceptCardTagHandlerTest { val clickableSpans = parsedHtml.getSpansFromWholeString(ClickableSpan::class) assertThat(clickableSpans).hasLength(1) } + @Test + fun testParseHtml_contentDescription() { + val parsedHtml = + CustomHtmlContentHandler.getContentDescription( + html = CONCEPT_CARD_LINK_MARKUP_1, + imageRetriever = mockImageRetriever, + customTagHandlers = tagHandlersWithConceptCardSupport + ) + assertThat(parsedHtml).isEqualTo("refresher lesson concept card") + } @Test fun testParseHtml_withConceptCardMarkup_addsLinkText() { diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index c5d9dd93e4d..edea61794c4 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -298,6 +298,23 @@ class CustomHtmlContentHandlerTest { assertThat(jsonObject?.getString("key")).isEqualTo("value with \\frac{1}{2}") } + @Test + fun testGetContentDescription_withNestedTags_handlesNestingCorrectly() { + val outerHandler = FakeContentDescriptionTagHandler("Outer Tag ") + val innerHandler = FakeContentDescriptionTagHandler("Inner Tag ") + + val contentDescription = CustomHtmlContentHandler.getContentDescription( + html = "before nested after", + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf( + "outer-tag" to outerHandler, + "inner-tag" to innerHandler + ) + ) + + assertThat(contentDescription).isEqualTo("Outer Tag before Inner Tag nested after") + } + private fun Spannable.getSpansFromWholeString(spanClass: KClass): Array = getSpans(/* start= */ 0, /* end= */ length, spanClass.javaObjectType) @@ -315,7 +332,22 @@ class CustomHtmlContentHandlerTest { val formattingLocale = androidLocaleFactory.createOneOffAndroidLocale(context) return DisplayLocaleImpl(context, formattingLocale, machineLocale, formatterFactory) } + private class FakeContentDescriptionTagHandler( + private val contentDesc: String + ) : CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { + override fun handleTag( + attributes: Attributes, + openIndex: Int, + closeIndex: Int, + output: Editable, + imageRetriever: CustomHtmlContentHandler.ImageRetriever? + ) { + } + override fun getContentDescription(attributes: Attributes): String { + return contentDesc + } + } private class FakeTagHandler : CustomTagHandler { var handleTagCalled = false var handleTagCallIndex = -1 From af0a6ecc46d9c580cde51c20c2532a3a76aed9a9 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 01:49:12 +0530 Subject: [PATCH 05/18] ktlint issue --- .../oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 503866c3f53..8d579e9391b 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -124,7 +124,7 @@ class ConceptCardTagHandlerTest { imageRetriever = mockImageRetriever, customTagHandlers = tagHandlersWithConceptCardSupport ) - assertThat(parsedHtml).isEqualTo("refresher lesson concept card") + assertThat(parsedHtml).isEqualTo("refresher lesson concept card") } @Test From f8fc2702ff9668815e23d6ceec762a8b7d7126ed Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 02:08:40 +0530 Subject: [PATCH 06/18] adding kdoc --- .../oppia/android/util/parser/html/CustomHtmlContentHandler.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index d5a0287e664..fc6ba9a338f 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -194,6 +194,8 @@ class CustomHtmlContentHandler private constructor( */ fun handleClosingTag(output: Editable, indentation: Int, tag: String) {} } + + /** Handler Interface for tag handlers that provide content descriptions */ interface ContentDescriptionProvider { /** * Returns a content description string for this tag based on its attributes, @@ -201,6 +203,7 @@ class CustomHtmlContentHandler private constructor( */ fun getContentDescription(attributes: Attributes): String? } + /** * Retriever of images for custom tag handlers. The built-in Android analog for this class is * Html's ImageGetter. From 763364a176a30774010351be91d4e171db69e53d Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 02:18:04 +0530 Subject: [PATCH 07/18] kdoc issue --- .../oppia/android/util/parser/html/CustomHtmlContentHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index fc6ba9a338f..c00f34bfa74 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -195,7 +195,7 @@ class CustomHtmlContentHandler private constructor( fun handleClosingTag(output: Editable, indentation: Int, tag: String) {} } - /** Handler Interface for tag handlers that provide content descriptions */ + /** Handler Interface for tag handlers that provide content descriptions. */ interface ContentDescriptionProvider { /** * Returns a content description string for this tag based on its attributes, From 20e3971d953b06eeb2b05aca767baccaa1f46a10 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 03:09:40 +0530 Subject: [PATCH 08/18] implementing getContentDescription for tagHandlers --- .../util/parser/html/ConceptCardTagHandler.kt | 2 +- .../android/util/parser/html/ImageTagHandler.kt | 9 ++++++++- .../android/util/parser/html/MathTagHandler.kt | 9 ++++++++- .../parser/html/ConceptCardTagHandlerTest.kt | 4 ++-- .../parser/html/CustomHtmlContentHandlerTest.kt | 16 ++++++++++++++++ .../util/parser/html/ImageTagHandlerTest.kt | 11 +++++++++++ .../util/parser/html/MathTagHandlerTest.kt | 15 +++++++++++++++ 7 files changed, 61 insertions(+), 5 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt index 2be3a032e66..376e136d275 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt @@ -53,7 +53,7 @@ class ConceptCardTagHandler( val skillId = attributes.getJsonStringValue("skill_id-with-value") val text = attributes.getJsonStringValue("text-with-value") return if (skillId != null && text != null) { - "$text concept card" + "$text concept card $skillId" } else null } } 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 499b89fa54d..de01609487f 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 @@ -22,7 +22,7 @@ private const val CUSTOM_IMG_CAPTION_ATTRIBUTE = "caption-with-value" */ class ImageTagHandler( private val consoleLogger: ConsoleLogger -) : CustomHtmlContentHandler.CustomTagHandler { +) : CustomHtmlContentHandler.CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { override fun handleTag( attributes: Attributes, openIndex: Int, @@ -101,4 +101,11 @@ class ImageTagHandler( "Failed to parse $CUSTOM_IMG_CAPTION_ATTRIBUTE" ) } + + override fun getContentDescription(attributes: Attributes): String? { + val altValue = attributes.getJsonStringValue("alt-with-value") + return if (altValue != null) { + "Image illustrating $altValue" + } else null + } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt index 42ce1a0676e..dae63e2b0b8 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt @@ -29,7 +29,7 @@ class MathTagHandler( private val lineHeight: Float, private val cacheLatexRendering: Boolean, private val application: Application -) : CustomHtmlContentHandler.CustomTagHandler { +) : CustomHtmlContentHandler.CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { override fun handleTag( attributes: Attributes, openIndex: Int, @@ -138,4 +138,11 @@ class MathTagHandler( } } } + + override fun getContentDescription(attributes: Attributes): String? { + val mathVal = attributes.getJsonObjectValue(CUSTOM_MATH_MATH_CONTENT_ATTRIBUTE) + return if (mathVal != null) { + "Math content $mathVal" + } else null + } } diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 8d579e9391b..54ce1e9d30f 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -118,13 +118,13 @@ class ConceptCardTagHandlerTest { } @Test fun testParseHtml_contentDescription() { - val parsedHtml = + val contentDescription = CustomHtmlContentHandler.getContentDescription( html = CONCEPT_CARD_LINK_MARKUP_1, imageRetriever = mockImageRetriever, customTagHandlers = tagHandlersWithConceptCardSupport ) - assertThat(parsedHtml).isEqualTo("refresher lesson concept card") + assertThat(contentDescription).isEqualTo("refresher lesson concept card") } @Test diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index edea61794c4..b59258da3ab 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -315,6 +315,22 @@ class CustomHtmlContentHandlerTest { assertThat(contentDescription).isEqualTo("Outer Tag before Inner Tag nested after") } + @Test + fun testGetContentDescription_withMultipleTags_preservesOrder() { + val firstHandler = FakeContentDescriptionTagHandler("First ") + val secondHandler = FakeContentDescriptionTagHandler("Second ") + val contentDescription = CustomHtmlContentHandler.getContentDescription( + html = "Start one middle two end", + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf( + "first-tag" to firstHandler, + "second-tag" to secondHandler + ) + ) + + assertThat(contentDescription).isEqualTo("Start First one middle Second two end") + } + private fun Spannable.getSpansFromWholeString(spanClass: KClass): Array = getSpans(/* start= */ 0, /* end= */ length, spanClass.javaObjectType) 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 e1bd9e22a2e..c6ff748a701 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 @@ -325,6 +325,17 @@ class ImageTagHandlerTest { .inOrder() } + @Test + fun testParseHtml_contentDescription() { + val contentDescription = + CustomHtmlContentHandler.getContentDescription( + html = IMAGE_TAG_MARKUP_1, + imageRetriever = mockImageRetriever, + customTagHandlers = tagHandlersWithImageTagSupport + ) + assertThat(contentDescription).isEqualTo("Image illustrating alt text 1") + } + private fun Spannable.getSpansFromWholeString(spanClass: KClass): Array = getSpans(/* start= */ 0, /* end= */ length, spanClass.javaObjectType) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt index 535d5c90e58..26793c27e66 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt @@ -301,6 +301,21 @@ class MathTagHandlerTest { assertThat(imageSpans).hasLength(2) } + @Test + fun testParseHtml_contentDescription() { + val contentDescription = + CustomHtmlContentHandler.getContentDescription( + html = MATH_MARKUP_1, + imageRetriever = mockImageRetriever, + customTagHandlers = tagHandlersWithCachedMathSupport + ) + + assertThat(contentDescription).isEqualTo( + "Math content" + + " {\"raw_latex\":\"\\\\frac{2}{5}\",\"svg_filename\":\"math_image1.svg\"}" + ) + } + @Test fun testParseHtml_withMathMarkup_loadsInlineImageForFilename() { CustomHtmlContentHandler.fromHtml( From 7d39cec210061bb7aab570649207411f7d39dcbf Mon Sep 17 00:00:00 2001 From: manas-yu Date: Sun, 22 Dec 2024 14:31:31 +0530 Subject: [PATCH 09/18] test fix --- .../oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 54ce1e9d30f..518492ef78f 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -124,7 +124,7 @@ class ConceptCardTagHandlerTest { imageRetriever = mockImageRetriever, customTagHandlers = tagHandlersWithConceptCardSupport ) - assertThat(contentDescription).isEqualTo("refresher lesson concept card") + assertThat(contentDescription).isEqualTo("refresher lesson concept card skill_id_1") } @Test From d7802c8ddf4f6fd39c2e1e989597626aaa876047 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Mon, 23 Dec 2024 22:45:52 +0530 Subject: [PATCH 10/18] li-tag-handler --- .../parser/html/CustomHtmlContentHandler.kt | 19 ++++++++++++-- .../android/util/parser/html/LiTagHandler.kt | 12 ++++++--- .../util/parser/html/PolicyPageTagHandler.kt | 14 +++++++++- .../util/parser/html/LiTagHandlerTest.kt | 26 +++++++++++++++++++ .../parser/html/PolicyPageTagHandlerTest.kt | 12 +++++++++ 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index c00f34bfa74..6a2ac632490 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -27,9 +27,15 @@ class CustomHtmlContentHandler private constructor( private val currentTrackedCustomTags = ArrayDeque() private val contentDescriptionBuilder = StringBuilder() private val tagContentDescriptions = mutableMapOf() + private var isInListItem = false + private var pendingNewline = false + private val blockTags = setOf("p", "ol", "ul", "li", "oppia-ul", "oppia-ol", "oppia-li", "div") override fun endElement(uri: String?, localName: String?, qName: String?) { originalContentHandler?.endElement(uri, localName, qName) + if (localName in blockTags) { + isInListItem = false + } currentTrackedTag = null } @@ -47,6 +53,10 @@ class CustomHtmlContentHandler private constructor( override fun characters(ch: CharArray?, start: Int, length: Int) { originalContentHandler?.characters(ch, start, length) + if (pendingNewline) { + contentDescriptionBuilder.append('\n') + pendingNewline = false + } ch?.let { contentDescriptionBuilder.append(String(it, start, length)) } } @@ -59,6 +69,10 @@ class CustomHtmlContentHandler private constructor( // Defer custom tag management to the tag handler so that Android's element parsing takes // precedence. currentTrackedTag = TrackedTag(checkNotNull(localName), checkNotNull(atts)) + if (localName in blockTags) { + pendingNewline = true + isInListItem = true + } originalContentHandler?.startElement(uri, localName, qName, atts) } @@ -139,7 +153,7 @@ class CustomHtmlContentHandler private constructor( * from all custom tags. */ private fun getContentDescription(): String { - return buildString { + val rawDesc = buildString { var lastIndex = 0 tagContentDescriptions.entries.sortedBy { it.key }.forEach { (index, description) -> if (index > lastIndex) { @@ -151,7 +165,8 @@ class CustomHtmlContentHandler private constructor( if (lastIndex < contentDescriptionBuilder.length) { append(contentDescriptionBuilder.substring(lastIndex)) } - }.trim() + } + return rawDesc.replace(Regex("\n+"), "\n") } /** Handler interface for a custom tag and its attributes. */ interface CustomTagHandler { diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt index d0562b474a1..71939ee4769 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt @@ -6,6 +6,7 @@ import android.text.Spannable import android.text.Spanned import org.oppia.android.util.locale.OppiaLocale import java.util.Stack +import org.xml.sax.Attributes /** The custom
  • tag corresponding to [LiTagHandler]. */ const val CUSTOM_LIST_LI_TAG = "oppia-li" @@ -23,7 +24,7 @@ const val CUSTOM_LIST_OL_TAG = "oppia-ol" class LiTagHandler( private val context: Context, private val displayLocale: OppiaLocale.DisplayLocale -) : CustomHtmlContentHandler.CustomTagHandler { +) : CustomHtmlContentHandler.CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { private val pendingLists = Stack>() private val latestPendingList: ListTag<*, *>? get() = pendingLists.lastOrNull() @@ -72,7 +73,7 @@ class LiTagHandler( * this list. */ var pendingStartMark: M? = null - private var itemCount = 0 + var itemCount = 0 /** * Called when an opening
  • tag is encountered. @@ -159,7 +160,7 @@ class LiTagHandler( class Ul( parentList: ListTag<*, *>?, parentMark: Mark<*>?, - private val indentationLevel: Int + val indentationLevel: Int ) : ListTag( parentList, parentMark, ::getLast ) { @@ -291,4 +292,9 @@ class LiTagHandler( private fun > Spannable.addMark(mark: T) = setSpan(mark, length, length, Spanned.SPAN_MARK_MARK) } + + override fun getContentDescription(attributes: Attributes): String? { + return null + } + } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt index ec9f494e73e..ebb48dc07e0 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt @@ -22,7 +22,7 @@ private const val TERMS_OF_SERVICE = "Terms of Service" class PolicyPageTagHandler( private val listener: PolicyPageLinkClickListener, private val consoleLogger: ConsoleLogger -) : CustomHtmlContentHandler.CustomTagHandler { +) : CustomHtmlContentHandler.CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { override fun handleTag( attributes: Attributes, openIndex: Int, @@ -83,4 +83,16 @@ class PolicyPageTagHandler( */ fun onPolicyPageLinkClicked(policyType: PolicyType) } + + override fun getContentDescription(attributes: Attributes): String? { + // Get the type of policy link from the attributes + val linkType = attributes.getJsonStringValue("link") ?: return null + + // Return an accessibility-friendly description based on the link type + return when (linkType) { + TERMS_OF_SERVICE_PAGE -> "Link to " + PRIVACY_POLICY_PAGE -> "Link to " + else -> null // Return null for unknown link types + } + } } diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt index 1341bc68776..65f599a0d7b 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt @@ -136,6 +136,32 @@ class LiTagHandlerTest { assertThat(parsedHtml.getSpansFromWholeString(ListItemLeadingMarginSpan.OlSpan::class)) .hasLength(4) } + @Test + fun testCustomListElement_contentDescription() { + val displayLocale = createDisplayLocaleImpl(US_ENGLISH_CONTEXT) + val htmlString = "

    You should know the following before going on:

    " + + "The counting numbers (1, 2, 3, 4, 5 ….)" + + "How to tell whether one counting number is bigger or " + + "smaller than another Item 1 Item 2" + + "" + val liTaghandler = LiTagHandler(context, displayLocale) + val contentDescription = + CustomHtmlContentHandler.getContentDescription( + html = htmlString, + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf( + CUSTOM_LIST_LI_TAG to liTaghandler, + CUSTOM_LIST_OL_TAG to liTaghandler + ) + ) + assertThat(contentDescription).isEqualTo( + "\nYou should know the following before going on:\n" + + "The counting numbers (1, 2, 3, 4, 5 ….)\n" + + "How to tell whether one counting number is bigger or smaller than another \n" + + "Item 1 \n" + + "Item 2" + ) + } private fun createDisplayLocaleImpl(context: OppiaLocaleContext): DisplayLocaleImpl { val formattingLocale = androidLocaleFactory.createOneOffAndroidLocale(context) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt index f258cfe1ef0..def7c1a0276 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt @@ -120,6 +120,18 @@ class PolicyPageTagHandlerTest { assertThat(policyTypeCaptor.value).isEqualTo(PolicyType.PRIVACY_POLICY) } + @Test + fun testParseHtml_contentDescription() { + val contentDescription = + CustomHtmlContentHandler.getContentDescription( + html = POLICY_PAGE_LINK_MARKUP_1, + imageRetriever = null, + customTagHandlers = tagHandlersWithPolicyPageSupport + ) + + assertThat(contentDescription).isEqualTo("By using %s, you agree to our " + + " Link to Terms of Service and Link to Privacy Policy.") + } @Test fun testParseHtml_withPolicyPageMarkup_clickSpan_callsClickListenerForTermsOfService() { From 4109e3f7ff5e3da591612819c3f686d13d9f4103 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Mon, 23 Dec 2024 22:46:52 +0530 Subject: [PATCH 11/18] formmating --- .../oppia/android/util/parser/html/LiTagHandler.kt | 3 +-- .../android/util/parser/html/LiTagHandlerTest.kt | 14 +++++++------- .../util/parser/html/PolicyPageTagHandlerTest.kt | 6 ++++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt index 71939ee4769..e0534187c6c 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt @@ -5,8 +5,8 @@ import android.text.Editable import android.text.Spannable import android.text.Spanned import org.oppia.android.util.locale.OppiaLocale -import java.util.Stack import org.xml.sax.Attributes +import java.util.Stack /** The custom
  • tag corresponding to [LiTagHandler]. */ const val CUSTOM_LIST_LI_TAG = "oppia-li" @@ -296,5 +296,4 @@ class LiTagHandler( override fun getContentDescription(attributes: Attributes): String? { return null } - } diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt index 65f599a0d7b..e1cfd89ce72 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt @@ -154,13 +154,13 @@ class LiTagHandlerTest { CUSTOM_LIST_OL_TAG to liTaghandler ) ) - assertThat(contentDescription).isEqualTo( - "\nYou should know the following before going on:\n" + - "The counting numbers (1, 2, 3, 4, 5 ….)\n" + - "How to tell whether one counting number is bigger or smaller than another \n" + - "Item 1 \n" + - "Item 2" - ) + assertThat(contentDescription).isEqualTo( + "\nYou should know the following before going on:\n" + + "The counting numbers (1, 2, 3, 4, 5 ….)\n" + + "How to tell whether one counting number is bigger or smaller than another \n" + + "Item 1 \n" + + "Item 2" + ) } private fun createDisplayLocaleImpl(context: OppiaLocaleContext): DisplayLocaleImpl { diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt index def7c1a0276..3b306875719 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt @@ -129,8 +129,10 @@ class PolicyPageTagHandlerTest { customTagHandlers = tagHandlersWithPolicyPageSupport ) - assertThat(contentDescription).isEqualTo("By using %s, you agree to our " + - " Link to Terms of Service and Link to Privacy Policy.") + assertThat(contentDescription).isEqualTo( + "By using %s, you agree to our " + + " Link to Terms of Service and Link to Privacy Policy." + ) } @Test From 36595bee56915c0e116f4447cd78dab06257e800 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Mon, 23 Dec 2024 23:23:34 +0530 Subject: [PATCH 12/18] adding tests --- .../parser/html/CustomHtmlContentHandler.kt | 2 +- .../util/parser/html/PolicyPageTagHandler.kt | 4 +- .../parser/html/ConceptCardTagHandlerTest.kt | 2 +- .../html/CustomHtmlContentHandlerTest.kt | 68 +++++++++++++++++++ .../util/parser/html/ImageTagHandlerTest.kt | 2 +- .../util/parser/html/LiTagHandlerTest.kt | 29 +++++++- .../util/parser/html/MathTagHandlerTest.kt | 2 +- .../parser/html/PolicyPageTagHandlerTest.kt | 2 +- 8 files changed, 101 insertions(+), 10 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt index 6a2ac632490..bca56be075e 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/CustomHtmlContentHandler.kt @@ -166,7 +166,7 @@ class CustomHtmlContentHandler private constructor( append(contentDescriptionBuilder.substring(lastIndex)) } } - return rawDesc.replace(Regex("\n+"), "\n") + return rawDesc.replace(Regex("\n+"), "\n").trim() } /** Handler interface for a custom tag and its attributes. */ interface CustomTagHandler { diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt index ebb48dc07e0..b10a486e841 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt @@ -85,14 +85,12 @@ class PolicyPageTagHandler( } override fun getContentDescription(attributes: Attributes): String? { - // Get the type of policy link from the attributes val linkType = attributes.getJsonStringValue("link") ?: return null - // Return an accessibility-friendly description based on the link type return when (linkType) { TERMS_OF_SERVICE_PAGE -> "Link to " PRIVACY_POLICY_PAGE -> "Link to " - else -> null // Return null for unknown link types + else -> null } } } diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 518492ef78f..72f3e47f9c1 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -117,7 +117,7 @@ class ConceptCardTagHandlerTest { assertThat(clickableSpans).hasLength(1) } @Test - fun testParseHtml_contentDescription() { + fun testGetContentDescription_withConceptCardTag() { val contentDescription = CustomHtmlContentHandler.getContentDescription( html = CONCEPT_CARD_LINK_MARKUP_1, diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index b59258da3ab..ae6926dd7c7 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -330,6 +330,74 @@ class CustomHtmlContentHandlerTest { assertThat(contentDescription).isEqualTo("Start First one middle Second two end") } + @Test + fun testGetContentDescription_whitespaceHandling_normalizedCorrectly() { + val contentDescription = CustomHtmlContentHandler.getContentDescription( + html = + """ +

    First paragraph

    + +

    Second paragraph

    + +

    Third paragraph

    + """.trimIndent(), + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf() + ) + + assertThat(contentDescription).isEqualTo( + "First paragraph\n" + + "Second paragraph\n" + + "Third paragraph" + ) + } + @Test + fun testGetContentDescription_blockElements_preserveStructure() { + val contentDescription = CustomHtmlContentHandler.getContentDescription( + html = + """ +
    Header text
    +
    Article content
    +
    Section text
    + +
    Footer text
    + """.trimIndent(), + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf() + ) + + assertThat(contentDescription).isEqualTo( + "Header text\n" + + "Article content\n" + + "Section text\n" + + "Aside content\n" + + "Footer text" + ) + } + @Test + fun testGetContentDescription_mixedContentTypes_handlesCorrectly() { + val contentDescription = CustomHtmlContentHandler.getContentDescription( + html = + """ +

    Regular paragraph

    + Custom content +
    • List item 1
    • List item 2
    + More custom +

    Final paragraph

    + """.trimIndent(), + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf() + ) + + assertThat(contentDescription).isEqualTo( + "Regular paragraph\n" + + "Custom content\n" + + "List item 1\n" + + "List item 2\n" + + "More custom\n" + + "Final paragraph" + ) + } private fun Spannable.getSpansFromWholeString(spanClass: KClass): Array = getSpans(/* start= */ 0, /* end= */ length, spanClass.javaObjectType) 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 c6ff748a701..894de4bc062 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 @@ -326,7 +326,7 @@ class ImageTagHandlerTest { } @Test - fun testParseHtml_contentDescription() { + fun testGetContentDescription_withImageTag() { val contentDescription = CustomHtmlContentHandler.getContentDescription( html = IMAGE_TAG_MARKUP_1, diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt index e1cfd89ce72..487cda78b52 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/LiTagHandlerTest.kt @@ -136,8 +136,9 @@ class LiTagHandlerTest { assertThat(parsedHtml.getSpansFromWholeString(ListItemLeadingMarginSpan.OlSpan::class)) .hasLength(4) } + @Test - fun testCustomListElement_contentDescription() { + fun testGetContentDescription_handlesNestedOrderedList() { val displayLocale = createDisplayLocaleImpl(US_ENGLISH_CONTEXT) val htmlString = "

    You should know the following before going on:

    " + "The counting numbers (1, 2, 3, 4, 5 ….)" + @@ -155,7 +156,7 @@ class LiTagHandlerTest { ) ) assertThat(contentDescription).isEqualTo( - "\nYou should know the following before going on:\n" + + "You should know the following before going on:\n" + "The counting numbers (1, 2, 3, 4, 5 ….)\n" + "How to tell whether one counting number is bigger or smaller than another \n" + "Item 1 \n" + @@ -163,6 +164,30 @@ class LiTagHandlerTest { ) } + @Test + fun testGetContentDescription_handlesSimpleUnorderedList() { + val displayLocale = createDisplayLocaleImpl(US_ENGLISH_CONTEXT) + val htmlString = "

    You should know the following before going on:
    " + + "The counting numbers (1, 2, 3, 4, 5 ….)" + + "How to tell whether one counting number is bigger or " + + "smaller than another

    " + val liTaghandler = LiTagHandler(context, displayLocale) + val contentDescription = + CustomHtmlContentHandler.getContentDescription( + html = htmlString, + imageRetriever = mockImageRetriever, + customTagHandlers = mapOf( + CUSTOM_LIST_LI_TAG to liTaghandler, + CUSTOM_LIST_OL_TAG to liTaghandler + ) + ) + assertThat(contentDescription).isEqualTo( + "You should know the following before going on:\n" + + "The counting numbers (1, 2, 3, 4, 5 ….)\n" + + "How to tell whether one counting number is bigger or smaller than another" + ) + } + private fun createDisplayLocaleImpl(context: OppiaLocaleContext): DisplayLocaleImpl { val formattingLocale = androidLocaleFactory.createOneOffAndroidLocale(context) return DisplayLocaleImpl(context, formattingLocale, machineLocale, formatterFactory) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt index 26793c27e66..d2c15cf1c27 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/MathTagHandlerTest.kt @@ -302,7 +302,7 @@ class MathTagHandlerTest { } @Test - fun testParseHtml_contentDescription() { + fun testGetContentDescription_withMathTag() { val contentDescription = CustomHtmlContentHandler.getContentDescription( html = MATH_MARKUP_1, diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt index 3b306875719..68a4ee1c250 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt @@ -121,7 +121,7 @@ class PolicyPageTagHandlerTest { assertThat(policyTypeCaptor.value).isEqualTo(PolicyType.PRIVACY_POLICY) } @Test - fun testParseHtml_contentDescription() { + fun testGetContentDescription_withPolicyPageTag() { val contentDescription = CustomHtmlContentHandler.getContentDescription( html = POLICY_PAGE_LINK_MARKUP_1, From 16037761682513daa2242b0d5a0b24d470db8ded Mon Sep 17 00:00:00 2001 From: manas-yu Date: Mon, 23 Dec 2024 23:36:45 +0530 Subject: [PATCH 13/18] revert --- .../java/org/oppia/android/util/parser/html/LiTagHandler.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt index e0534187c6c..9215348b04c 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt @@ -5,8 +5,8 @@ import android.text.Editable import android.text.Spannable import android.text.Spanned import org.oppia.android.util.locale.OppiaLocale -import org.xml.sax.Attributes import java.util.Stack +import org.xml.sax.Attributes /** The custom
  • tag corresponding to [LiTagHandler]. */ const val CUSTOM_LIST_LI_TAG = "oppia-li" @@ -73,7 +73,7 @@ class LiTagHandler( * this list. */ var pendingStartMark: M? = null - var itemCount = 0 + private var itemCount = 0 /** * Called when an opening
  • tag is encountered. @@ -160,7 +160,7 @@ class LiTagHandler( class Ul( parentList: ListTag<*, *>?, parentMark: Mark<*>?, - val indentationLevel: Int + private val indentationLevel: Int ) : ListTag( parentList, parentMark, ::getLast ) { From ef6c298751ebf149084a2cc7aa2a1955091b4d79 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Mon, 23 Dec 2024 23:37:31 +0530 Subject: [PATCH 14/18] ktlit/kdoc --- .../java/org/oppia/android/util/parser/html/LiTagHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt index 9215348b04c..21e6db41939 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt @@ -5,8 +5,8 @@ import android.text.Editable import android.text.Spannable import android.text.Spanned import org.oppia.android.util.locale.OppiaLocale -import java.util.Stack import org.xml.sax.Attributes +import java.util.Stack /** The custom
  • tag corresponding to [LiTagHandler]. */ const val CUSTOM_LIST_LI_TAG = "oppia-li" From 2b9eef8733e3c9109af3e8b49cc1281f8ea65551 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Fri, 10 Jan 2025 18:55:00 +0530 Subject: [PATCH 15/18] formatting and removing null --- .../android/util/parser/html/ConceptCardTagHandler.kt | 2 +- .../oppia/android/util/parser/html/ImageTagHandler.kt | 6 +++--- .../org/oppia/android/util/parser/html/LiTagHandler.kt | 4 ++-- .../org/oppia/android/util/parser/html/MathTagHandler.kt | 2 +- .../android/util/parser/html/PolicyPageTagHandler.kt | 9 +++------ .../util/parser/html/ConceptCardTagHandlerTest.kt | 1 + .../util/parser/html/CustomHtmlContentHandlerTest.kt | 1 + .../android/util/parser/html/PolicyPageTagHandlerTest.kt | 1 + 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt index 376e136d275..d1ea64ba378 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt @@ -54,6 +54,6 @@ class ConceptCardTagHandler( val text = attributes.getJsonStringValue("text-with-value") return if (skillId != null && text != null) { "$text concept card $skillId" - } else null + } else "" } } 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 de01609487f..90aa893bfdf 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 @@ -103,9 +103,9 @@ class ImageTagHandler( } override fun getContentDescription(attributes: Attributes): String? { - val altValue = attributes.getJsonStringValue("alt-with-value") - return if (altValue != null) { + val altValue = attributes.getJsonStringValue(CUSTOM_IMG_ALT_TEXT_ATTRIBUTE) + return if (!altValue.isNullOrBlank()) { "Image illustrating $altValue" - } else null + } else "" } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt index 21e6db41939..849f2e226be 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/LiTagHandler.kt @@ -293,7 +293,7 @@ class LiTagHandler( setSpan(mark, length, length, Spanned.SPAN_MARK_MARK) } - override fun getContentDescription(attributes: Attributes): String? { - return null + override fun getContentDescription(attributes: Attributes): String { + return "" } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt index dae63e2b0b8..e3ae5fa4ae8 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt @@ -143,6 +143,6 @@ class MathTagHandler( val mathVal = attributes.getJsonObjectValue(CUSTOM_MATH_MATH_CONTENT_ATTRIBUTE) return if (mathVal != null) { "Math content $mathVal" - } else null + } else "" } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt index b10a486e841..ce4ec561d7f 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt @@ -85,12 +85,9 @@ class PolicyPageTagHandler( } override fun getContentDescription(attributes: Attributes): String? { - val linkType = attributes.getJsonStringValue("link") ?: return null - - return when (linkType) { - TERMS_OF_SERVICE_PAGE -> "Link to " - PRIVACY_POLICY_PAGE -> "Link to " - else -> null + return when (attributes.getJsonStringValue("link")) { + TERMS_OF_SERVICE_PAGE, PRIVACY_POLICY_PAGE -> "Link to " + else -> "" } } } diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt index 72f3e47f9c1..53dfd421cc6 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/ConceptCardTagHandlerTest.kt @@ -116,6 +116,7 @@ class ConceptCardTagHandlerTest { val clickableSpans = parsedHtml.getSpansFromWholeString(ClickableSpan::class) assertThat(clickableSpans).hasLength(1) } + @Test fun testGetContentDescription_withConceptCardTag() { val contentDescription = diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index ae6926dd7c7..9f9e880ee2a 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -351,6 +351,7 @@ class CustomHtmlContentHandlerTest { "Third paragraph" ) } + @Test fun testGetContentDescription_blockElements_preserveStructure() { val contentDescription = CustomHtmlContentHandler.getContentDescription( diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt index 68a4ee1c250..2e6976aab3e 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/PolicyPageTagHandlerTest.kt @@ -120,6 +120,7 @@ class PolicyPageTagHandlerTest { assertThat(policyTypeCaptor.value).isEqualTo(PolicyType.PRIVACY_POLICY) } + @Test fun testGetContentDescription_withPolicyPageTag() { val contentDescription = From f86bcde10cc13e5b4e8613ff3f1aa1f433e2c3e7 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Fri, 10 Jan 2025 21:57:46 +0530 Subject: [PATCH 16/18] isNullOrBlank --- .../util/parser/html/ConceptCardTagHandler.kt | 12 +++++++----- .../android/util/parser/html/ImageTagHandler.kt | 2 +- .../oppia/android/util/parser/html/MathTagHandler.kt | 7 +++---- .../android/util/parser/html/PolicyPageTagHandler.kt | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt index d1ea64ba378..3f21868adc9 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt @@ -10,6 +10,8 @@ import org.xml.sax.Attributes /** The custom tag corresponding to [ConceptCardTagHandler]. */ const val CUSTOM_CONCEPT_CARD_TAG = "oppia-noninteractive-skillreview" +const val CUSTOM_CONCEPT_CARD_SKILL_ID="skill_id-with-value" +const val CUSTOM_CONCEPT_CARD_TEXT_VALUE="text-with-value" // https://mohammedlakkadshaw.com/blog/handling-custom-tags-in-android-using-html-taghandler.html/ class ConceptCardTagHandler( @@ -24,8 +26,8 @@ class ConceptCardTagHandler( imageRetriever: CustomHtmlContentHandler.ImageRetriever? ) { // Replace the custom tag with a clickable piece of text based on the tag's customizations. - val skillId = attributes.getJsonStringValue("skill_id-with-value") - val text = attributes.getJsonStringValue("text-with-value") + val skillId = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_SKILL_ID) + val text = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_TEXT_VALUE) if (skillId != null && text != null) { val spannableBuilder = SpannableStringBuilder(text) spannableBuilder.setSpan( @@ -50,9 +52,9 @@ class ConceptCardTagHandler( } override fun getContentDescription(attributes: Attributes): String? { - val skillId = attributes.getJsonStringValue("skill_id-with-value") - val text = attributes.getJsonStringValue("text-with-value") - return if (skillId != null && text != null) { + val skillId = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_SKILL_ID) + val text = attributes.getJsonStringValue(CUSTOM_CONCEPT_CARD_TEXT_VALUE) + return if (!skillId.isNullOrBlank() && !text.isNullOrBlank()) { "$text concept card $skillId" } else "" } 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 90aa893bfdf..b86a5995b17 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 @@ -102,7 +102,7 @@ class ImageTagHandler( ) } - override fun getContentDescription(attributes: Attributes): String? { + override fun getContentDescription(attributes: Attributes): String { val altValue = attributes.getJsonStringValue(CUSTOM_IMG_ALT_TEXT_ATTRIBUTE) return if (!altValue.isNullOrBlank()) { "Image illustrating $altValue" diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt index e3ae5fa4ae8..ee5e818ed89 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt @@ -139,10 +139,9 @@ class MathTagHandler( } } - override fun getContentDescription(attributes: Attributes): String? { + override fun getContentDescription(attributes: Attributes): String { val mathVal = attributes.getJsonObjectValue(CUSTOM_MATH_MATH_CONTENT_ATTRIBUTE) - return if (mathVal != null) { - "Math content $mathVal" - } else "" + return mathVal?.let { "Math content $it" } ?: "" + } } diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt index ce4ec561d7f..462a468b7b1 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/PolicyPageTagHandler.kt @@ -84,7 +84,7 @@ class PolicyPageTagHandler( fun onPolicyPageLinkClicked(policyType: PolicyType) } - override fun getContentDescription(attributes: Attributes): String? { + override fun getContentDescription(attributes: Attributes): String { return when (attributes.getJsonStringValue("link")) { TERMS_OF_SERVICE_PAGE, PRIVACY_POLICY_PAGE -> "Link to " else -> "" From 51dc10d76db50e62680adf0f0a3593a707009956 Mon Sep 17 00:00:00 2001 From: manas-yu Date: Fri, 10 Jan 2025 21:58:33 +0530 Subject: [PATCH 17/18] lint fix --- .../oppia/android/util/parser/html/ConceptCardTagHandler.kt | 4 ++-- .../java/org/oppia/android/util/parser/html/MathTagHandler.kt | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt index 3f21868adc9..83625743d87 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/ConceptCardTagHandler.kt @@ -10,8 +10,8 @@ import org.xml.sax.Attributes /** The custom tag corresponding to [ConceptCardTagHandler]. */ const val CUSTOM_CONCEPT_CARD_TAG = "oppia-noninteractive-skillreview" -const val CUSTOM_CONCEPT_CARD_SKILL_ID="skill_id-with-value" -const val CUSTOM_CONCEPT_CARD_TEXT_VALUE="text-with-value" +const val CUSTOM_CONCEPT_CARD_SKILL_ID = "skill_id-with-value" +const val CUSTOM_CONCEPT_CARD_TEXT_VALUE = "text-with-value" // https://mohammedlakkadshaw.com/blog/handling-custom-tags-in-android-using-html-taghandler.html/ class ConceptCardTagHandler( diff --git a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt index ee5e818ed89..eabfa3836d7 100644 --- a/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt +++ b/utility/src/main/java/org/oppia/android/util/parser/html/MathTagHandler.kt @@ -142,6 +142,5 @@ class MathTagHandler( override fun getContentDescription(attributes: Attributes): String { val mathVal = attributes.getJsonObjectValue(CUSTOM_MATH_MATH_CONTENT_ATTRIBUTE) return mathVal?.let { "Math content $it" } ?: "" - } } From 1fa6263ddbe7b5adbb0dc6b51578cd1fa3b0867d Mon Sep 17 00:00:00 2001 From: manas-yu Date: Fri, 10 Jan 2025 22:02:46 +0530 Subject: [PATCH 18/18] spacing --- .../util/parser/html/CustomHtmlContentHandlerTest.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt index 9f9e880ee2a..8b11dcba7f0 100644 --- a/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt +++ b/utility/src/test/java/org/oppia/android/util/parser/html/CustomHtmlContentHandlerTest.kt @@ -330,6 +330,7 @@ class CustomHtmlContentHandlerTest { assertThat(contentDescription).isEqualTo("Start First one middle Second two end") } + @Test fun testGetContentDescription_whitespaceHandling_normalizedCorrectly() { val contentDescription = CustomHtmlContentHandler.getContentDescription( @@ -375,6 +376,7 @@ class CustomHtmlContentHandlerTest { "Footer text" ) } + @Test fun testGetContentDescription_mixedContentTypes_handlesCorrectly() { val contentDescription = CustomHtmlContentHandler.getContentDescription( @@ -417,6 +419,7 @@ class CustomHtmlContentHandlerTest { val formattingLocale = androidLocaleFactory.createOneOffAndroidLocale(context) return DisplayLocaleImpl(context, formattingLocale, machineLocale, formatterFactory) } + private class FakeContentDescriptionTagHandler( private val contentDesc: String ) : CustomTagHandler, CustomHtmlContentHandler.ContentDescriptionProvider { @@ -426,8 +429,7 @@ class CustomHtmlContentHandlerTest { closeIndex: Int, output: Editable, imageRetriever: CustomHtmlContentHandler.ImageRetriever? - ) { - } + ) {} override fun getContentDescription(attributes: Attributes): String { return contentDesc