Bug 978075 - Screen reader turn on and off announce. r=yzen

This patch does several other things:
 1. When a PrefCache with no default setting available is created, or cleared, set value to null.
 2. Removed weird margin change in announce box.
 3. Add announce method to speech presenter.
 4. Don't start and stop AccessFu implicitly in AccessFuTest.
 5. Change tests to two start/stop pairs where in one pair we activate via pref, and
     the other one via settings (TODO).
This commit is contained in:
Eitan Isaacson 2014-03-04 10:10:38 -08:00
parent dc243c34da
commit e22a4c8a91
9 changed files with 146 additions and 90 deletions

View File

@ -38,7 +38,6 @@
#announce-box:not(.showing) {
opacity: 0.0;
margin: 0.1em;
-moz-transition: opacity 0.4s linear;
}

View File

@ -134,6 +134,11 @@ this.AccessFu = {
this.readyCallback();
delete this.readyCallback;
}
if (Utils.MozBuildApp !== 'mobile/android') {
this.announce(
Utils.stringBundle.GetStringFromName('screenReaderStarted'));
}
},
/**
@ -149,6 +154,11 @@ this.AccessFu = {
Utils.win.document.removeChild(this.stylesheet.get());
if (Utils.MozBuildApp !== 'mobile/android') {
this.announce(
Utils.stringBundle.GetStringFromName('screenReaderStopped'));
}
for each (let mm in Utils.AllMessageManagers) {
mm.sendAsyncMessage('AccessFu:Stop');
this._removeMessageListeners(mm);
@ -368,8 +378,7 @@ this.AccessFu = {
},
announce: function announce(aAnnouncement) {
this._output(Presentation.announce(aAnnouncement),
Utils.CurrentBrowser);
this._output(Presentation.announce(aAnnouncement), Utils.CurrentBrowser);
},
// So we don't enable/disable twice
@ -515,7 +524,8 @@ var Output = {
init: function init() {
let window = Utils.win;
this.webspeechEnabled = !!window.speechSynthesis;
this.webspeechEnabled = !!window.speechSynthesis &&
!!window.SpeechSynthesisUtterance;
let settingsToGet = 2;
let settingsCallback = (aName, aSetting) => {

View File

@ -33,10 +33,6 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
XPCOMUtils.defineLazyModuleGetter(this, 'States',
'resource://gre/modules/accessibility/Constants.jsm');
var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
getService(Ci.nsIStringBundleService).
createBundle('chrome://global/locale/AccessFu.properties');
this.EXPORTED_SYMBOLS = ['UtteranceGenerator', 'BrailleGenerator'];
this.OutputGenerator = {
@ -194,7 +190,7 @@ this.OutputGenerator = {
return;
}
let landmark = gStringBundle.GetStringFromName(landmarkName);
let landmark = Utils.stringBundle.GetStringFromName(landmarkName);
if (!landmark) {
return;
}
@ -221,7 +217,7 @@ this.OutputGenerator = {
}
typeName = 'textInputType_' + typeName;
try {
aDesc.push(gStringBundle.GetStringFromName(typeName));
aDesc.push(Utils.stringBundle.GetStringFromName(typeName));
} catch (x) {
Logger.warning('Failed to get a string from a bundle for', typeName);
}
@ -244,7 +240,7 @@ this.OutputGenerator = {
_getLocalizedState: function _getLocalizedState(aState) {},
_getPluralFormString: function _getPluralFormString(aString, aCount) {
let str = gStringBundle.GetStringFromName(this._getOutputName(aString));
let str = Utils.stringBundle.GetStringFromName(this._getOutputName(aString));
str = PluralForm.get(aCount, str);
return str.replace('#1', aCount);
},
@ -378,7 +374,7 @@ this.OutputGenerator = {
let output = [];
let desc = this._getLocalizedState(aState);
desc.push(
gStringBundle.formatStringFromName(
Utils.stringBundle.formatStringFromName(
'objItemOf', [localizedRole, itemno.value, itemof.value], 3));
output.push(desc.join(' '));
@ -406,7 +402,7 @@ this.OutputGenerator = {
table.columnCount);
let tableRowInfo = this._getPluralFormString('tableRowInfo',
table.rowCount);
output.push(gStringBundle.formatStringFromName(
output.push(Utils.stringBundle.formatStringFromName(
this._getOutputName('tableInfo'), [this._getLocalizedRole(aRoleStr),
tableColumnInfo, tableRowInfo], 3));
this._addName(output, aAccessible, aFlags);
@ -455,13 +451,13 @@ this.UtteranceGenerator = {
//TODO: May become more verbose in the future.
genForAction: function genForAction(aObject, aActionName) {
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
return [Utils.stringBundle.GetStringFromName(this.gActionMap[aActionName])];
},
genForLiveRegion: function genForLiveRegion(aContext, aIsHide, aModifiedText) {
let utterance = [];
if (aIsHide) {
utterance.push(gStringBundle.GetStringFromName('hidden'));
utterance.push(Utils.stringBundle.GetStringFromName('hidden'));
}
return utterance.concat(
aModifiedText || this.genForContext(aContext).output);
@ -469,7 +465,7 @@ this.UtteranceGenerator = {
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
try {
return [gStringBundle.GetStringFromName(aAnnouncement)];
return [Utils.stringBundle.GetStringFromName(aAnnouncement)];
} catch (x) {
return [aAnnouncement];
}
@ -478,24 +474,24 @@ this.UtteranceGenerator = {
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
switch (aTabState) {
case 'newtab':
return [gStringBundle.GetStringFromName('tabNew')];
return [Utils.stringBundle.GetStringFromName('tabNew')];
case 'loading':
return [gStringBundle.GetStringFromName('tabLoading')];
return [Utils.stringBundle.GetStringFromName('tabLoading')];
case 'loaded':
return [aObject.name || '',
gStringBundle.GetStringFromName('tabLoaded')];
Utils.stringBundle.GetStringFromName('tabLoaded')];
case 'loadstopped':
return [gStringBundle.GetStringFromName('tabLoadStopped')];
return [Utils.stringBundle.GetStringFromName('tabLoadStopped')];
case 'reload':
return [gStringBundle.GetStringFromName('tabReload')];
return [Utils.stringBundle.GetStringFromName('tabReload')];
default:
return [];
}
},
genForEditingMode: function genForEditingMode(aIsEditing) {
return [gStringBundle.GetStringFromName(
aIsEditing ? 'editingMode' : 'navigationMode')];
return [Utils.stringBundle.GetStringFromName(
aIsEditing ? 'editingMode' : 'navigationMode')];
},
objectOutputFunctions: {
@ -510,7 +506,8 @@ this.UtteranceGenerator = {
let level = {};
aAccessible.groupPosition(level, {}, {});
let utterance =
[gStringBundle.formatStringFromName('headingLevel', [level.value], 1)];
[Utils.stringBundle.formatStringFromName(
'headingLevel', [level.value], 1)];
this._addName(utterance, aAccessible, aFlags);
this._addLandmark(utterance, aAccessible);
@ -524,9 +521,9 @@ this.UtteranceGenerator = {
aAccessible.groupPosition({}, itemof, itemno);
let utterance = [];
if (itemno.value == 1) // Start of list
utterance.push(gStringBundle.GetStringFromName('listStart'));
utterance.push(Utils.stringBundle.GetStringFromName('listStart'));
else if (itemno.value == itemof.value) // last item
utterance.push(gStringBundle.GetStringFromName('listEnd'));
utterance.push(Utils.stringBundle.GetStringFromName('listEnd'));
this._addName(utterance, aAccessible, aFlags);
this._addLandmark(utterance, aAccessible);
@ -560,13 +557,13 @@ this.UtteranceGenerator = {
let desc = [];
let addCellChanged = function addCellChanged(aDesc, aChanged, aString, aIndex) {
if (aChanged) {
aDesc.push(gStringBundle.formatStringFromName(aString,
aDesc.push(Utils.stringBundle.formatStringFromName(aString,
[aIndex + 1], 1));
}
};
let addExtent = function addExtent(aDesc, aExtent, aString) {
if (aExtent > 1) {
aDesc.push(gStringBundle.formatStringFromName(aString,
aDesc.push(Utils.stringBundle.formatStringFromName(aString,
[aExtent], 1));
}
};
@ -609,7 +606,8 @@ this.UtteranceGenerator = {
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
try {
return gStringBundle.GetStringFromName(this._getOutputName(aRoleStr));
return Utils.stringBundle.GetStringFromName(
this._getOutputName(aRoleStr));
} catch (x) {
return '';
}
@ -619,7 +617,8 @@ this.UtteranceGenerator = {
let stateUtterances = [];
if (aState.contains(States.UNAVAILABLE)) {
stateUtterances.push(gStringBundle.GetStringFromName('stateUnavailable'));
stateUtterances.push(
Utils.stringBundle.GetStringFromName('stateUnavailable'));
}
// Don't utter this in Jelly Bean, we let TalkBack do it for us there.
@ -629,29 +628,33 @@ this.UtteranceGenerator = {
if (Utils.AndroidSdkVersion < 16 && aState.contains(States.CHECKABLE)) {
let statetr = aState.contains(States.CHECKED) ?
'stateChecked' : 'stateNotChecked';
stateUtterances.push(gStringBundle.GetStringFromName(statetr));
stateUtterances.push(Utils.stringBundle.GetStringFromName(statetr));
}
if (aState.contains(States.EXPANDABLE)) {
let statetr = aState.contains(States.EXPANDED) ?
'stateExpanded' : 'stateCollapsed';
stateUtterances.push(gStringBundle.GetStringFromName(statetr));
stateUtterances.push(Utils.stringBundle.GetStringFromName(statetr));
}
if (aState.contains(States.REQUIRED)) {
stateUtterances.push(gStringBundle.GetStringFromName('stateRequired'));
stateUtterances.push(
Utils.stringBundle.GetStringFromName('stateRequired'));
}
if (aState.contains(States.TRAVERSED)) {
stateUtterances.push(gStringBundle.GetStringFromName('stateTraversed'));
stateUtterances.push(
Utils.stringBundle.GetStringFromName('stateTraversed'));
}
if (aState.contains(States.HASPOPUP)) {
stateUtterances.push(gStringBundle.GetStringFromName('stateHasPopup'));
stateUtterances.push(
Utils.stringBundle.GetStringFromName('stateHasPopup'));
}
if (aState.contains(States.SELECTED)) {
stateUtterances.push(gStringBundle.GetStringFromName('stateSelected'));
stateUtterances.push(
Utils.stringBundle.GetStringFromName('stateSelected'));
}
return stateUtterances;
@ -744,7 +747,7 @@ this.BrailleGenerator = {
}
};
desc.push(gStringBundle.formatStringFromName(
desc.push(Utils.stringBundle.formatStringFromName(
this._getOutputName('cellInfo'), [cell.columnIndex + 1,
cell.rowIndex + 1], 2));
@ -815,10 +818,11 @@ this.BrailleGenerator = {
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
try {
return gStringBundle.GetStringFromName(this._getOutputName(aRoleStr));
return Utils.stringBundle.GetStringFromName(
this._getOutputName(aRoleStr));
} catch (x) {
try {
return gStringBundle.GetStringFromName(
return Utils.stringBundle.GetStringFromName(
OutputGenerator._getOutputName(aRoleStr));
} catch (y) {
return '';

View File

@ -499,6 +499,17 @@ SpeechPresenter.prototype = {
}]
}
};
},
announce: function SpeechPresenter_announce(aAnnouncement) {
return {
type: this.type,
details: {
actions: [{
method: 'speak', data: aAnnouncement, options: { enqueue: false }
}]
}
};
}
};

View File

@ -169,6 +169,13 @@ this.Utils = {
return this.isContentProcess;
},
get stringBundle() {
delete this.stringBundle;
this.stringBundle = Services.strings.createBundle(
'chrome://global/locale/AccessFu.properties');
return this.stringBundle;
},
getMessageManager: function getMessageManager(aBrowser) {
try {
return aBrowser.QueryInterface(Ci.nsIFrameLoaderOwner).
@ -775,18 +782,23 @@ this.PrefCache = function PrefCache(aName, aCallback, aRunCallbackNow) {
PrefCache.prototype = {
_getValue: function _getValue(aBranch) {
if (!this.type) {
this.type = aBranch.getPrefType(this.name);
}
switch (this.type) {
case Ci.nsIPrefBranch.PREF_STRING:
return aBranch.getCharPref(this.name);
case Ci.nsIPrefBranch.PREF_INT:
return aBranch.getIntPref(this.name);
case Ci.nsIPrefBranch.PREF_BOOL:
return aBranch.getBoolPref(this.name);
default:
return null;
try {
if (!this.type) {
this.type = aBranch.getPrefType(this.name);
}
switch (this.type) {
case Ci.nsIPrefBranch.PREF_STRING:
return aBranch.getCharPref(this.name);
case Ci.nsIPrefBranch.PREF_INT:
return aBranch.getIntPref(this.name);
case Ci.nsIPrefBranch.PREF_BOOL:
return aBranch.getBoolPref(this.name);
default:
return null;
}
} catch (x) {
// Pref does not exist.
return null;
}
},

View File

@ -93,16 +93,11 @@ var AccessFuTest = {
// Disable the console service logging.
Logger.test = false;
Logger.logLevel = Logger.INFO;
AccessFu.doneCallback = function doneCallback() {
// This is being called once AccessFu has been shut down.
// Detach AccessFu from everything it attached itself to.
// Finish through idle callback to let AccessFu._disable complete.
SimpleTest.executeSoon(function () {
AccessFu.detach();
// and finish the test run.
SimpleTest.finish();
};
// Tear down accessibility and make AccessFu stop.
SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 0);
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
});
},
nextTest: function AccessFuTest_nextTest() {
@ -138,8 +133,12 @@ var AccessFuTest = {
// Enable logging to the console service.
Logger.test = true;
Logger.logLevel = Logger.DEBUG;
// This is being called once accessibility has been turned on.
};
SpecialPowers.pushPrefEnv({
'set': [['accessibility.accessfu.notify_output', 1],
['dom.mozSettings.enabled', true]]
}, function () {
if (AccessFuTest._waitForExplicitFinish) {
// Run all test functions asynchronously.
AccessFuTest.nextTest();
@ -148,11 +147,7 @@ var AccessFuTest = {
[testFunc() for (testFunc of gTestFuncs)];
AccessFuTest.finish();
}
};
// Invoke the whole thing.
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 1);
});
}
};

View File

@ -13,43 +13,57 @@
src="./jsatcommon.js"></script>
<script type="application/javascript">
function confirmAccessFuStart() {
ok(AccessFu._enabled, "AccessFu was started and enabled.");
AccessFuTest.nextTest();
function prefStart() {
// Start AccessFu via pref.
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
}
// Listen for 'EventManager.stop' and enable AccessFu again.
function onStop() {
function settingsStart() {
ok(true, "EventManager was stopped.");
isnot(AccessFu._enabled, true, "AccessFu was disabled.");
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
AccessFu._enable();
AccessFuTest.once([{
"method": "speak",
"data": "Screen reader started",
"options": {
"enqueue": false
}
}], AccessFuTest.nextTest);
// XXX: Bug 978076 - test start with SettingsManager.
//navigator.mozSettings.createLock().set(
// {'accessibility.screenreader': false});
AccessFu._enable()
}
// Make sure EventManager is started again.
function onFinalStart() {
ok(true, "EventManager was started again.");
function settingsStop() {
ok(AccessFu._enabled, "AccessFu was enabled again.");
AccessFuTest.finish();
}
// Listen for initial 'EventManager.start' and disable AccessFu.
function onInitialStart() {
ok(true, "EventManager was started.");
AccessFuTest.once_log("EventManager.stop", AccessFuTest.nextTest);
AccessFuTest.once([{
"method": "speak",
"data": "Screen reader stopped",
"options": {
"enqueue": false
}
}], AccessFuTest.finish);
// XXX: Bug 978076 - test stop with SettingsManager.
//navigator.mozSettings.createLock().set(
// {'accessibility.screenreader': false});
AccessFu._disable();
}
function init() {
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
// Listen for initial 'EventManager.start' and disable AccessFu.
function prefStop() {
ok(AccessFu._enabled, "AccessFu was started via preference.");
AccessFuTest.once_log("EventManager.stop", AccessFuTest.nextTest);
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
}
function doTest() {
AccessFuTest.addFunc(confirmAccessFuStart);
AccessFuTest.addFunc(init);
AccessFuTest.addFunc(onInitialStart);
AccessFuTest.addFunc(onStop);
AccessFuTest.addFunc(onFinalStart);
AccessFuTest.addFunc(prefStart);
AccessFuTest.addFunc(prefStop);
AccessFuTest.addFunc(settingsStart);
AccessFuTest.addFunc(settingsStop);
AccessFuTest.waitForExplicitFinish();
AccessFuTest.runTests(); // Will call SimpleTest.finish();
}

View File

@ -13,10 +13,16 @@
src="./jsatcommon.js"></script>
<script type="application/javascript">
function EventManagerStarted() {
function startAccessFu() {
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
}
function stopAccessFu() {
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
}
function hide(id) {
var element = document.getElementById(id);
element.style.display = "none";
@ -245,14 +251,14 @@
}];
function doTest() {
AccessFuTest.addFunc(EventManagerStarted);
AccessFuTest.addFunc(startAccessFu);
tests.forEach(function addTest(test) {
AccessFuTest.addFunc(function () {
AccessFuTest.once(test.expected, AccessFuTest.nextTest);
test.action();
});
});
AccessFuTest.addFunc(AccessFuTest.finish);
AccessFuTest.addFunc(stopAccessFu);
AccessFuTest.waitForExplicitFinish();
AccessFuTest.runTests();
}

View File

@ -2,6 +2,11 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# Screen reader started/stopped
screenReaderStarted = Screen reader started
screenReaderStopped = Screen reader stopped
# Roles
menubar = menu bar
scrollbar = scroll bar
grip = grip