From 426407a812d224bd9105ca4201deddede49055e6 Mon Sep 17 00:00:00 2001 From: James Teh Date: Wed, 22 May 2024 22:14:01 +0000 Subject: [PATCH] Bug 1810596: When computing the text for a live region on Android, always include the text from the subtree. r=eeejay,geckoview-reviewers,ohall Previously, we only included the subtree for roles which are allowed to be traversed during recursive name computation. This meant that no text would be produced for live regions with roles such as status, where name computation traversal is not allowed. Now, we first get the name to handle cases where the name is explicitly specified; e.g. images with alt text. We then add the subtree text if the name wasn't already computed from it. Differential Revision: https://phabricator.services.mozilla.com/D210628 --- accessible/android/AccessibleWrap.cpp | 20 +++++++++++++------ .../test-live-region-status.html | 9 +++++++++ .../geckoview/test/AccessibilityTest.kt | 13 ++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-status.html diff --git a/accessible/android/AccessibleWrap.cpp b/accessible/android/AccessibleWrap.cpp index 5b69866c0503..0d38eb4d7d1b 100644 --- a/accessible/android/AccessibleWrap.cpp +++ b/accessible/android/AccessibleWrap.cpp @@ -403,12 +403,20 @@ int32_t AccessibleWrap::GetInputType(const nsString& aInputTypeAttr) { } void AccessibleWrap::GetTextEquiv(nsString& aText) { - if (nsTextEquivUtils::HasNameRule(this, eNameFromSubtreeIfReqRule)) { - // This is an accessible that normally doesn't get its name from its - // subtree, so we collect the text equivalent explicitly. - nsTextEquivUtils::GetTextEquivFromSubtree(this, aText); - } else { - Name(aText); + // 1. Start with the name, since it might have been explicitly specified. + if (Name(aText) != eNameFromSubtree) { + // 2. If the name didn't come from the subtree, add the text from the + // subtree. + if (aText.IsEmpty()) { + nsTextEquivUtils::GetTextEquivFromSubtree(this, aText); + } else { + nsAutoString subtree; + nsTextEquivUtils::GetTextEquivFromSubtree(this, subtree); + if (!subtree.IsEmpty()) { + aText.Append(' '); + aText.Append(subtree); + } + } } } diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-status.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-status.html new file mode 100644 index 000000000000..dbba55c6b4cb --- /dev/null +++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-status.html @@ -0,0 +1,9 @@ + + + + + + +
+ + diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt index 8e87c1d4787f..63c594466694 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/AccessibilityTest.kt @@ -1202,6 +1202,19 @@ class AccessibilityTest : BaseSessionTest() { }) } + @Test fun testLiveRegionStatus() { + loadTestPage("test-live-region-status") + waitForInitialFocus() + + mainSession.evaluateJS("document.querySelector('#status').textContent = 'hello';") + sessionRule.waitUntilCalled(object : EventDelegate { + @AssertCalled(count = 1) + override fun onAnnouncement(event: AccessibilityEvent) { + assertThat("Announcement is correct", event.text[0].toString(), equalTo("hello")) + } + }) + } + private fun screenContainsNode(nodeId: Int): Boolean { var node = createNodeInfo(nodeId) var nodeBounds = Rect()