Commit eba5d802 authored by Akihiro Ota's avatar Akihiro Ota Committed by Commit Bot

ChromeVox: Announce when user executes a command when no focus is set.

Bug: 981964
Change-Id: I7953289c8aa2aacb5e7886990de243a2b29e131e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1951975
Commit-Queue: Akihiro Ota <akihiroota@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747045}
parent ae3270a7
...@@ -139,6 +139,9 @@ Background = class extends ChromeVoxState { ...@@ -139,6 +139,9 @@ Background = class extends ChromeVoxState {
/** @private {cursors.Range} */ /** @private {cursors.Range} */
this.pageSel_; this.pageSel_;
/** @type {boolean} */
this.talkBackEnabled = false;
CommandHandler.init(); CommandHandler.init();
FindHandler.init(); FindHandler.init();
DownloadHandler.init(); DownloadHandler.init();
...@@ -152,6 +155,10 @@ Background = class extends ChromeVoxState { ...@@ -152,6 +155,10 @@ Background = class extends ChromeVoxState {
(announceText) => { (announceText) => {
ChromeVox.tts.speak(announceText.join(' '), QueueMode.FLUSH); ChromeVox.tts.speak(announceText.join(' '), QueueMode.FLUSH);
}); });
chrome.accessibilityPrivate.onCustomSpokenFeedbackToggled.addListener(
(enabled) => {
this.talkBackEnabled = enabled;
});
// Set the darkScreen state to false, since the display will be on whenever // Set the darkScreen state to false, since the display will be on whenever
// ChromeVox starts. // ChromeVox starts.
......
...@@ -4,13 +4,10 @@ ...@@ -4,13 +4,10 @@
// Include test fixture. // Include test fixture.
GEN_INCLUDE([ GEN_INCLUDE([
'//chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js', '../testing/chromevox_next_e2e_test_base.js', '../testing/assert_additions.js'
'//chrome/browser/resources/chromeos/accessibility/chromevox/testing/assert_additions.js'
]); ]);
GEN_INCLUDE([ GEN_INCLUDE(['../testing/mock_feedback.js', '../testing/fake_objects.js']);
'//chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback.js'
]);
/** /**
* Test fixture for Background. * Test fixture for Background.
...@@ -137,6 +134,15 @@ ChromeVoxBackgroundTest = class extends ChromeVoxNextE2ETest { ...@@ -137,6 +134,15 @@ ChromeVoxBackgroundTest = class extends ChromeVoxNextE2ETest {
</div> </div>
`; `;
} }
/**
* Fires an onCustomSpokenFeedbackToggled event with enabled state of
* |enabled|.
* @param {boolean} enabled TalkBack-enabled state.
*/
dispatchOnCustomSpokenFeedbackToggledEvent(enabled) {
chrome.accessibilityPrivate.onCustomSpokenFeedbackToggled.dispatch(enabled);
}
}; };
...@@ -1818,7 +1824,9 @@ TEST_F('ChromeVoxBackgroundTest', 'ListName', function() { ...@@ -1818,7 +1824,9 @@ TEST_F('ChromeVoxBackgroundTest', 'ListName', function() {
const mockFeedback = this.createMockFeedback(); const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree( this.runWithLoadedTree(
` `
<div id="_md-chips-wrapper-76" tabindex="-1" class="md-chips md-readonly" aria-setsize="4" aria-label="Favorite Sports" role="list" aria-describedby="chipsNote"> <div id="_md-chips-wrapper-76" tabindex="-1" class="md-chips md-readonly"
aria-setsize="4" aria-label="Favorite Sports" role="list"
aria-describedby="chipsNote">
<div role="listitem">Baseball</div> <div role="listitem">Baseball</div>
<div role="listitem">Hockey</div> <div role="listitem">Hockey</div>
<div role="listitem">Lacrosse</div> <div role="listitem">Lacrosse</div>
...@@ -2362,3 +2370,44 @@ TEST_F('ChromeVoxBackgroundTest', 'ToggleDarkScreen', function() { ...@@ -2362,3 +2370,44 @@ TEST_F('ChromeVoxBackgroundTest', 'ToggleDarkScreen', function() {
.replay(); .replay();
}); });
}); });
TEST_F('ChromeVoxBackgroundTest', 'NoFocusTalkBackDisabled', function() {
// Fire onCustomSpokenFeedbackEnabled event to communicate that Talkback is
// off for the current app.
this.dispatchOnCustomSpokenFeedbackToggledEvent(false);
const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree('<p>Test document</p>', function() {
ChromeVoxState.instance.setCurrentRange(null);
mockFeedback.call(doCmd('nextObject'))
.expectSpeech(
'No current ChromeVox focus. Press Alt+Shift+L to go to the ' +
'launcher.')
.call(doCmd('previousObject'))
.expectSpeech(
'No current ChromeVox focus. Press Alt+Shift+L to go to the ' +
'launcher.');
mockFeedback.replay();
});
});
TEST_F('ChromeVoxBackgroundTest', 'NoFocusTalkBackEnabled', function() {
// Fire onCustomSpokenFeedbackEnabled event to communicate that Talkback is
// on for the current app. We don't want to announce the no-focus hint message
// when TalkBack is on because we expect ChromeVox to have no focus in that
// case. If we announce the hint message, TalkBack and ChromeVox will
// try to speak at the same time.
this.dispatchOnCustomSpokenFeedbackToggledEvent(true);
const mockFeedback = this.createMockFeedback();
this.runWithLoadedTree('<p>Start here</p>', function() {
ChromeVoxState.instance.setCurrentRange(null);
mockFeedback.call(doCmd('nextObject'));
assertFalse(mockFeedback.utteranceInQueue(
'No current ChromeVox focus. ' +
'Press Alt+Shift+L to go to the launcher.'));
mockFeedback.call(doCmd('previousObject'));
assertFalse(mockFeedback.utteranceInQueue(
'No current ChromeVox focus. ' +
'Press Alt+Shift+L to go to the launcher.'));
mockFeedback.replay();
});
});
...@@ -270,6 +270,12 @@ CommandHandler.onCommand = function(command) { ...@@ -270,6 +270,12 @@ CommandHandler.onCommand = function(command) {
// Require a current range. // Require a current range.
if (!ChromeVoxState.instance.currentRange_) { if (!ChromeVoxState.instance.currentRange_) {
if (!ChromeVoxState.instance.talkBackEnabled) {
new Output()
.withString(Msgs.getMsg('no_focus'))
.withQueueMode(QueueMode.FLUSH)
.go();
}
return true; return true;
} }
......
...@@ -139,6 +139,20 @@ MockFeedback = class { ...@@ -139,6 +139,20 @@ MockFeedback = class {
ChromeVox.earcons = new MockEarcons(); ChromeVox.earcons = new MockEarcons();
} }
/**
* Returns true if |utterance| is in |pendingUtterances_|.
* @param {string} utterance
* @return {boolean}
*/
utteranceInQueue(utterance) {
for (const pendingUtterance of this.pendingUtterances_) {
if (pendingUtterance.text === utterance) {
return true;
}
}
return false;
}
/** /**
* Adds an expectation for one or more spoken utterances. * Adds an expectation for one or more spoken utterances.
* @param {...(string|RegExp)} var_args One or more utterance to add as * @param {...(string|RegExp)} var_args One or more utterance to add as
......
...@@ -3699,5 +3699,8 @@ ...@@ -3699,5 +3699,8 @@
<message desc="Title displayed in the panel for the form controls node menu." name="IDS_CHROMEVOX_PANEL_MENU_FORM_CONTROLS"> <message desc="Title displayed in the panel for the form controls node menu." name="IDS_CHROMEVOX_PANEL_MENU_FORM_CONTROLS">
Form Controls Form Controls
</message> </message>
<message desc="Announced to alert the user that ChromeVox has no current focus." name="IDS_CHROMEVOX_NO_FOCUS">
No current ChromeVox focus. Press Alt+Shift+L to go to the launcher.
</message>
</grit-part> </grit-part>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment