Commit 2f442a2b authored by dtseng@chromium.org's avatar dtseng@chromium.org

Support basic reading of focus for both desktop and tabs trees.

This implements:
- basic spoken and braille feedback on tabs and desktop trees.
- gives us a conceptual outline of the three entry points to interact with ChromeVox next:
1. keyboard (right now only possible by DOM events delivered through the content script)
2. through events received from the tabs automation tree
3.  through events received from the desktop automation tree
- test added against production ChromeVox for status tray.

Review URL: https://codereview.chromium.org/337843005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278682 0039d316-1c4b-4281-b951-d872f2087c98
parent 783fdc02
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Base test fixture for ChromeVox end to end tests.
*
* These tests run against production ChromeVox inside of the extension's
* background page context.
* @constructor
*/
function ChromeVoxE2ETest() {}
ChromeVoxE2ETest.prototype = {
__proto__: testing.Test.prototype,
/**
* @override
* No UI in the background context.
*/
runAccessibilityChecks: false,
/** @override */
isAsync: true,
/** @override */
browsePreload: null,
/** @override */
testGenCppIncludes: function() {
GEN_BLOCK(function() {/*!
#include "ash/accessibility_delegate.h"
#include "base/bind.h"
#include "base/callback.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/common/extensions/extension_constants.h"
*/});
},
/** @override */
testGenPreamble: function() {
GEN_BLOCK(function() {/*!
if (chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(false,
ash::A11Y_NOTIFICATION_NONE);
}
base::Closure load_cb =
base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback,
base::Unretained(chromeos::AccessibilityManager::Get()),
true,
ash::A11Y_NOTIFICATION_NONE);
WaitForExtension(extension_misc::kChromeVoxExtensionId, load_cb);
*/});
}
};
/**
* Similar to |TEST_F|. Generates a test for the given |testFixture|,
* |testName|, and |testFunction|.
* Used this variant when an |isAsync| fixture wants to temporarily mix in an
* sync test.
* @param {string} testFixture Fixture name.
* @param {string} testName Test name.
* @param {function} testFunction The test impl.
*/
function SYNC_TEST_F(testFixture, testName, testFunction) {
var wrappedTestFunction = function() {
testFunction();
testDone([true, '']);
};
TEST_F(testFixture, testName, wrappedTestFunction);
}
...@@ -3,52 +3,91 @@ ...@@ -3,52 +3,91 @@
// found in the LICENSE file. // found in the LICENSE file.
// Include test fixture. // Include test fixture.
GEN_INCLUDE(['../../../chromevox/testing/chromevox_unittest_base.js']); GEN_INCLUDE(['../../../chromevox/testing/chromevox_e2e_test.js']);
/** /**
* Test fixture for cvox2.Background. * Test fixture for cvox2.Background.
* @constructor * @constructor
* @extends {ChromeVoxUnitTestBase} * @extends {ChromeVoxE2ETest}
*/ */
function BackgroundTest() {} function BackgroundTest() {}
BackgroundTest.prototype = { BackgroundTest.prototype = {
__proto__: ChromeVoxUnitTestBase.prototype, __proto__: ChromeVoxE2ETest.prototype,
/** @override */ /** @override */
browsePreload: null, setUp: function() {
this.mockTts = new MockTts();
cvox.ChromeVox.tts = this.mockTts;
}
};
/** @override */ /**
testGenCppIncludes: function() { * Mock tts class.
GEN_BLOCK(function() {/*! * @constructor
#include "ash/accessibility_delegate.h" * @extends {cvox.TtsInterface}
#include "base/bind.h" */
#include "base/callback.h" var MockTts = function() {
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" };
#include "chrome/common/extensions/extension_constants.h"
*/}); MockTts.prototype = {
}, /** Tracks all spoken text. @type {!Array.<string>} */
utterances: [],
/** @override */ /** @override */
testGenPreamble: function() { speak: function(textString, queueMode, properties) {
GEN_BLOCK(function() {/*! this.utterances.push(textString);
if (chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) { },
chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(false,
ash::A11Y_NOTIFICATION_NONE);
}
base::Closure load_cb = /**
base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback, * Checks to see if a string was spoken.
base::Unretained(chromeos::AccessibilityManager::Get()), * @param {string} textString The string to check.
true, * @return {boolean} True if the string was spoken (possibly as part of a
ash::A11Y_NOTIFICATION_NONE); * larger utterance).
WaitForExtension(extension_misc::kChromeVoxExtensionId, load_cb); */
*/}); checkIfTextWasSpoken: function(textString) {
return this.utterances.some(function(t) {
return t.indexOf(textString) != -1;
});
} }
}; };
/** Tests ChromeVox classic is in this context. */ /** Tests that ChromeVox classic is in this context. */
TEST_F('BackgroundTest', 'ClassicNamespaces', function() { SYNC_TEST_F('BackgroundTest', 'ClassicNamespaces', function() {
assertEquals('object', typeof(cvox)); assertEquals('object', typeof(cvox));
assertEquals('function', typeof(cvox.ChromeVoxBackground)); assertEquals('function', typeof(cvox.ChromeVoxBackground));
}); });
/** Tests that ChromeVox next is in this context. */
SYNC_TEST_F('BackgroundTest', 'NextNamespaces', function() {
assertEquals('object', typeof(cvox2));
assertEquals('function', typeof(cvox2.Background));
});
/** Tests that ChromeVox reads the desktop tree. */
TEST_F('BackgroundTest', 'DesktopFocus', function() {
function findStatusTray(root) {
if (root.role == chrome.automation.RoleType.button &&
root.attributes.name == 'Status tray') {
return root;
}
for (var i = 0; i < root.children().length; i++) {
var found = findStatusTray(root.children()[i]);
if (found)
return found;
}
return null;
}
chrome.automation.getDesktop(function(root) {
var testButton = findStatusTray(root);
testButton.addEventListener(chrome.automation.EventType.focus,
function(e) {
var result =
cvox.ChromeVox.tts.checkIfTextWasSpoken('Status tray button');
testDone([result, '']);
},
true);
testButton.focus();
});
});
...@@ -20,7 +20,16 @@ cvox2.global.accessibility = ...@@ -20,7 +20,16 @@ cvox2.global.accessibility =
cvox2.Background = function() { cvox2.Background = function() {
// Only needed with unmerged ChromeVox classic loaded before. // Only needed with unmerged ChromeVox classic loaded before.
cvox2.global.accessibility.setAccessibilityEnabled(false); cvox2.global.accessibility.setAccessibilityEnabled(false);
chrome.automation.getDesktop(this.onGotDesktop.bind(this));
// Register listeners for ...
// Desktop.
chrome.automation.getDesktop(this.onGotTree.bind(this));
// Tabs.
chrome.tabs.onUpdated.addListener(this.onTabUpdated.bind(this));
// Keyboard events (currently Messages from content script).
chrome.extension.onConnect.addListener(this.onConnect.bind(this));
}; };
cvox2.Background.prototype = { cvox2.Background.prototype = {
...@@ -32,54 +41,58 @@ cvox2.Background.prototype = { ...@@ -32,54 +41,58 @@ cvox2.Background.prototype = {
PORT_ID: 'chromevox2', PORT_ID: 'chromevox2',
/** /**
* Waits until a desktop automation tree becomes available. * Handles chrome.extension.onConnect.
* Thereafter, registers a simple exploration mode for the desktop tree. * @param {Object} port The port.
* @param {AutomationTree} tree The desktop automation tree.
*/ */
onGotDesktop: function(tree) { onConnect: function(port) {
if (!tree.root) { if (port.name != this.PORT_ID)
window.setTimeout(this.onGotDesktop, 500);
return; return;
} port.onMessage.addListener(this.onMessage.bind(this));
chrome.extension.onConnect.addListener(function(port) { },
if (port.name != this.PORT_ID)
return; /**
var cur = tree.root; * Dispatches messages to specific handlers.
port.onMessage.addListener(function(message) { * @param {Object} message The message.
switch (message.keydown) { */
case 37: onMessage: function(message) {
cur = cur.previousSibling() || cur; if (message.keyDown)
break; this.onKeyDown(message);
case 38: },
cur = cur.parent() || cur;
break; /**
case 39: * Handles key down messages from the content script.
cur = cur.nextSibling() || cur; * @param {Object} message The key down message.
break; */
case 40: onKeyDown: function(message) {
cur = cur.firstChild() || cur; // TODO(dtseng): Implement.
break; },
}
var index = 1;
if (cur.parent())
index = cur.parent().children().indexOf(cur) + 1;
var name = '';
if (cur.attributes && cur.attributes['ax_attr_name'])
name = cur.attributes['ax_attr_name'];
var utterance = index + ' ' + name + cur.role;
chrome.tts.speak(String(utterance), {lang: 'en-US'});
});
}.bind(this));
/**
* Handles chrome.tabs.onUpdate.
* @param {number} tabId The tab id.
* @param {Object.<string, (string|boolean)>} changeInfo Information about
* the updated tab.
*/
onTabUpdated: function(tabId, changeInfo) {
chrome.automation.getTree(this.onGotTree.bind(this));
},
/**
* Handles all setup once a new automation tree appears.
* @param {AutomationTree} tree The new automation tree.
*/
onGotTree: function(root) {
// Register all automation event listeners. // Register all automation event listeners.
tree.root.addEventListener('focus', this.onDesktopEvent.bind(this), true); root.addEventListener(chrome.automation.EventType.focus,
this.onAutomationEvent.bind(this),
true);
}, },
/** /**
* A generic handler for all desktop automation events. * A generic handler for all desktop automation events.
* @param {AutomationEvent} evt The event. * @param {AutomationEvent} evt The event.
*/ */
onDesktopEvent: function(evt) { onAutomationEvent: function(evt) {
var output = evt.target.attributes.name + ' ' + evt.target.role; var output = evt.target.attributes.name + ' ' + evt.target.role;
cvox.ChromeVox.tts.speak(output); cvox.ChromeVox.tts.speak(output);
cvox.ChromeVox.braille.write(cvox.NavBraille.fromText(output)); cvox.ChromeVox.braille.write(cvox.NavBraille.fromText(output));
......
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