mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Make screen reader announcement append a non-breaking space every other message. (flutter/engine#50151)
This fixes an issue when the same message was sent to the screen reader again and was not subsequently announced by VoiceOver despite the prior message having long been removed from the DOM. Fixes https://github.com/flutter/flutter/issues/142250
This commit is contained in:
parent
2869030de1
commit
1ee98ba880
@ -51,6 +51,15 @@ class AccessibilityAnnouncements {
|
||||
/// accouncements assertively.
|
||||
final DomHTMLElement _assertiveElement;
|
||||
|
||||
/// Whether to append a non-breaking space to the end of the message
|
||||
/// before outputting it.
|
||||
///
|
||||
/// It's used to work around a VoiceOver bug where announcing the same message
|
||||
/// repeatedly results in subsequent messages not being announced despite the
|
||||
/// fact that the previous announcement was already removed from the DOM a
|
||||
/// long while back. See https://github.com/flutter/flutter/issues/142250.
|
||||
bool _appendSpace = false;
|
||||
|
||||
/// Looks up the element used to announce messages of the given [assertiveness].
|
||||
DomHTMLElement ariaLiveElementFor(Assertiveness assertiveness) {
|
||||
switch (assertiveness) {
|
||||
@ -84,7 +93,9 @@ class AccessibilityAnnouncements {
|
||||
final DomHTMLElement ariaLiveElement = ariaLiveElementFor(assertiveness);
|
||||
|
||||
final DomHTMLDivElement messageElement = createDomHTMLDivElement();
|
||||
messageElement.text = message;
|
||||
// See the doc-comment for [_appendSpace] for the rationale.
|
||||
messageElement.text = _appendSpace ? '$message\u00A0' : message;
|
||||
_appendSpace = !_appendSpace;
|
||||
ariaLiveElement.append(messageElement);
|
||||
Timer(liveMessageDuration, () => messageElement.remove());
|
||||
}
|
||||
|
||||
@ -91,21 +91,38 @@ void testMain() {
|
||||
expectNoMessages();
|
||||
});
|
||||
|
||||
test('Rapid-fire messages are each announced.', () async {
|
||||
test('Rapid-fire messages are each announced', () async {
|
||||
sendAnnouncementMessage(message: 'Hello');
|
||||
expectMessages(polite: 'Hello');
|
||||
|
||||
await Future<void>.delayed(liveMessageDuration * 0.5);
|
||||
sendAnnouncementMessage(message: 'There');
|
||||
expectMessages(polite: 'HelloThere');
|
||||
expectMessages(polite: 'HelloThere\u00A0');
|
||||
|
||||
await Future<void>.delayed(liveMessageDuration * 0.6);
|
||||
expectMessages(polite: 'There');
|
||||
expectMessages(polite: 'There\u00A0');
|
||||
|
||||
await Future<void>.delayed(liveMessageDuration * 0.5);
|
||||
expectNoMessages();
|
||||
});
|
||||
|
||||
test('Repeated announcements are modified to ensure screen readers announce them', () async {
|
||||
sendAnnouncementMessage(message: 'Hello');
|
||||
expectMessages(polite: 'Hello');
|
||||
await Future<void>.delayed(liveMessageDuration);
|
||||
expectNoMessages();
|
||||
|
||||
sendAnnouncementMessage(message: 'Hello');
|
||||
expectMessages(polite: 'Hello\u00A0');
|
||||
await Future<void>.delayed(liveMessageDuration);
|
||||
expectNoMessages();
|
||||
|
||||
sendAnnouncementMessage(message: 'Hello');
|
||||
expectMessages(polite: 'Hello');
|
||||
await Future<void>.delayed(liveMessageDuration);
|
||||
expectNoMessages();
|
||||
});
|
||||
|
||||
test('announce() polite', () async {
|
||||
accessibilityAnnouncements.announce('polite message', Assertiveness.polite);
|
||||
expectMessages(polite: 'polite message');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user