Bug 1602075 - make enable/disable panel UI conditional on the accessibility-panel-auto-init feature. r=mtigley

Differential Revision: https://phabricator.services.mozilla.com/D71584
This commit is contained in:
Yura Zenevich 2020-05-01 19:04:15 +00:00
Родитель c8683212ad
Коммит b503cad7f4
14 изменённых файлов: 184 добавлений и 81 удалений

Просмотреть файл

@ -56,6 +56,16 @@ class AccessibilityProxy {
return this.accessibilityFront && this.accessibilityFront.enabled;
}
/**
* Indicates whether the accessibility service is enabled.
*/
get canBeEnabled() {
// TODO: Just use parentAccessibilityFront after Firefox 75.
const { canBeEnabled } =
this.parentAccessibilityFront || this.accessibilityFront;
return canBeEnabled;
}
get currentTarget() {
return this._currentTarget;
}

Просмотреть файл

@ -44,6 +44,7 @@ class Description extends Component {
canBeEnabled: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
enableAccessibility: PropTypes.func.isRequired,
autoInit: PropTypes.bool.isRequired,
};
}
@ -71,20 +72,37 @@ class Description extends Component {
}
render() {
const { canBeEnabled } = this.props;
const { enabling } = this.state;
const enableButtonStr = enabling
? "accessibility.enabling"
: "accessibility.enable";
const { canBeEnabled, autoInit } = this.props;
let warningStringName = "accessibility.enable.disabledTitle";
let button;
if (!autoInit) {
const { enabling } = this.state;
const enableButtonStr = enabling
? "accessibility.enabling"
: "accessibility.enable";
let title;
let disableButton = false;
let title;
let disableButton = false;
if (canBeEnabled) {
title = L10N.getStr("accessibility.enable.enabledTitle");
} else {
disableButton = true;
title = L10N.getStr("accessibility.enable.disabledTitle");
if (canBeEnabled) {
title = L10N.getStr("accessibility.enable.enabledTitle");
} else {
disableButton = true;
title = L10N.getStr("accessibility.enable.disabledTitle");
}
button = Button(
{
id: "accessibility-enable-button",
onClick: this.onEnable,
disabled: enabling || disableButton,
busy: enabling,
"data-standalone": true,
title,
},
L10N.getStr(enableButtonStr)
);
warningStringName = "accessibility.description.general.p2";
}
return div(
@ -105,26 +123,22 @@ class Description extends Component {
l10n: L10N,
messageStringKey: "accessibility.description.general.p1",
}),
p({}, L10N.getStr("accessibility.description.general.p2"))
p({}, L10N.getStr(warningStringName))
)
),
Button(
{
id: "accessibility-enable-button",
onClick: this.onEnable,
disabled: enabling || disableButton,
busy: enabling,
"data-standalone": true,
title,
},
L10N.getStr(enableButtonStr)
)
button
);
}
}
const mapStateToProps = ({ ui }) => ({
canBeEnabled: ui.canBeEnabled,
const mapStateToProps = ({
ui: {
canBeEnabled,
supports: { autoInit },
},
}) => ({
canBeEnabled,
autoInit,
});
// Exports from this module

Просмотреть файл

@ -15,6 +15,7 @@ const {
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const {
enable,
reset,
updateCanBeEnabled,
updateCanBeDisabled,
@ -123,7 +124,15 @@ class MainFrame extends Component {
}
onCanBeEnabledChange(canBeEnabled) {
this.props.dispatch(updateCanBeEnabled(canBeEnabled));
const {
enableAccessibility,
dispatch,
supports: { autoInit },
} = this.props;
dispatch(updateCanBeEnabled(canBeEnabled));
if (canBeEnabled && autoInit) {
dispatch(enable(enableAccessibility));
}
}
onCanBeDisabledChange(canBeDisabled) {

Просмотреть файл

@ -41,6 +41,7 @@ class Toolbar extends Component {
toolboxDoc: PropTypes.object.isRequired,
audit: PropTypes.func.isRequired,
simulate: PropTypes.func,
autoInit: PropTypes.bool.isRequired,
};
}
@ -64,7 +65,7 @@ class Toolbar extends Component {
}
render() {
const { canBeDisabled, simulate, toolboxDoc, audit } = this.props;
const { canBeDisabled, simulate, toolboxDoc, audit, autoInit } = this.props;
const { disabling } = this.state;
const disableButtonStr = disabling
? "accessibility.disabling"
@ -95,21 +96,23 @@ class Toolbar extends Component {
className: "devtools-toolbar",
role: "toolbar",
},
Button(
{
className: "disable",
id: "accessibility-disable-button",
onClick: this.onDisable,
disabled: disabling || isDisabled,
busy: disabling,
title,
},
L10N.getStr(disableButtonStr)
),
div({
role: "separator",
className: "devtools-separator",
}),
!autoInit &&
Button(
{
className: "disable",
id: "accessibility-disable-button",
onClick: this.onDisable,
disabled: disabling || isDisabled,
busy: disabling,
title,
},
L10N.getStr(disableButtonStr)
),
!autoInit &&
div({
role: "separator",
className: "devtools-separator",
}),
// @remove after release 68 (See Bug 1551574)
span(
{
@ -131,8 +134,14 @@ class Toolbar extends Component {
}
}
const mapStateToProps = ({ ui }) => ({
canBeDisabled: ui.canBeDisabled,
const mapStateToProps = ({
ui: {
canBeDisabled,
supports: { autoInit },
},
}) => ({
canBeDisabled,
autoInit,
});
// Exports from this module

Просмотреть файл

@ -96,6 +96,16 @@ AccessibilityPanel.prototype = {
this.onTargetAvailable
);
// Bug 1602075: if auto init feature is enabled, enable accessibility
// service if necessary.
if (
this.accessibilityProxy.supports.autoInit &&
this.accessibilityProxy.canBeEnabled &&
!this.accessibilityProxy.enabled
) {
await this.accessibilityProxy.enableAccessibility();
}
this.picker = new Picker(this);
this.fluentBundles = await this.createFluentBundles();
@ -185,7 +195,7 @@ AccessibilityPanel.prototype = {
// Alright reset the flag we are about to refresh the panel.
this.shouldRefresh = false;
this.postContentMessage("initialize", {
supports: this.supports,
supports: this.accessibilityProxy.supports,
fluentBundles: this.fluentBundles,
toolbox: this._toolbox,
getAccessibilityTreeRoot: this.accessibilityProxy

Просмотреть файл

@ -123,7 +123,7 @@ function onReceiveChildren(cache, action) {
}
if (accessible.actorID) {
console.warn(`Error fetching children: `, accessible, error);
console.warn(`Error fetching children: `, error);
return cache;
}

Просмотреть файл

@ -25,21 +25,13 @@ function getInitialState() {
}
function simulation(state = getInitialState(), action) {
const { error } = action;
if (error) {
console.warn(
`Error running simulation: ${
typeof error == "string"
? error
: "simulate function in simulator.js returned an error"
}`
);
return state;
}
switch (action.type) {
case SIMULATE:
if (action.error) {
console.warn("Error running simulation", action.error);
return state;
}
const simTypes = action.simTypes;
if (simTypes.length === 0) {

Просмотреть файл

@ -32,7 +32,7 @@ add_task(async function testNoShowAccessibilityPropertiesContextMenu() {
);
ok(inspectA11YPropsItem.hidden, "Accessibility tools are not enabled.");
contextMenu.hidePopup();
gBrowser.removeCurrentTab();
await removeTab(tab);
});
addA11YPanelTask(

Просмотреть файл

@ -57,4 +57,7 @@ add_task(async () => {
await runA11yPanelTests(CONTENT_PROCESS_EXPECTED, env);
await disableAccessibilityInspector(env);
await closeToolbox();
await shutdownA11y();
await removeTab(gBrowser.selectedTab);
});

Просмотреть файл

@ -16,7 +16,7 @@ add_task(async function tabNotHighlighted() {
"should not be highlighted when toolbox opens"
);
gBrowser.removeCurrentTab();
await closeTabAndToolbox();
});
add_task(async function tabHighlighted() {
@ -27,5 +27,7 @@ add_task(async function tabHighlighted() {
await checkHighlighted(toolbox, true);
a11yService = null;
gBrowser.removeCurrentTab();
await closeToolbox();
await shutdownA11y();
await removeTab(gBrowser.selectedTab);
});

Просмотреть файл

@ -6,8 +6,10 @@
const TEST_URI = '<h1 id="h1">header</h1><p id="p">paragraph</p>';
add_task(async function() {
const { toolbox: toolbox1 } = await addTestTab(buildURL(TEST_URI));
const { toolbox: toolbox2 } = await addTestTab(buildURL(TEST_URI));
Services.prefs.setBoolPref("devtools.accessibility.auto-init.enabled", false);
const { toolbox: toolbox1, tab: tab1 } = await addTestTab(buildURL(TEST_URI));
const { toolbox: toolbox2, tab: tab2 } = await addTestTab(buildURL(TEST_URI));
const options = await openOptions(toolbox2);
info("Check that initially both accessibility panels are highlighted.");
@ -42,6 +44,14 @@ add_task(async function() {
await checkHighlighted(toolbox1, false);
await checkHighlighted(toolbox2, false);
await closeToolbox();
await shutdownA11y();
await removeTab(tab1);
await closeToolbox();
await shutdownA11y();
await removeTab(tab2);
Services.prefs.clearUserPref("devtools.accessibility.auto-init.enabled");
});
async function openOptions(toolbox) {

Просмотреть файл

@ -73,21 +73,36 @@ async function initA11y() {
return a11yService;
}
/**
* Force garbage collection.
*/
function forceGC() {
SpecialPowers.gc();
SpecialPowers.forceShrinkingGC();
SpecialPowers.forceCC();
SpecialPowers.gc();
SpecialPowers.forceShrinkingGC();
SpecialPowers.forceCC();
}
/**
* Check if accessibility service is enabled.
*/
function isA11YEnabled() {
return Services.appinfo.accessibilityEnabled;
}
/**
* Wait for accessibility service to shut down. We consider it shut down when
* an "a11y-init-or-shutdown" event is received with a value of "0".
*/
function shutdownA11y() {
if (!Services.appinfo.accessibilityEnabled) {
return Promise.resolve();
}
// Force collections to speed up accessibility service shutdown.
Cu.forceGC();
Cu.forceCC();
Cu.forceShrinkingGC();
function waitForA11YShutdown() {
return new Promise(resolve => {
if (!Services.appinfo.accessibilityEnabled) {
resolve();
return;
}
const observe = (subject, topic, data) => {
if (data === "0") {
Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
@ -102,6 +117,28 @@ function shutdownA11y() {
});
}
/**
* Ensure that accessibility is completely shutdown.
*/
async function shutdownA11y() {
forceGC();
if (isA11YEnabled()) {
await waitForA11YShutdown();
}
const browser = gBrowser.selectedBrowser;
if (await SpecialPowers.spawn(browser, [], isA11YEnabled)) {
await SpecialPowers.spawn(browser, [], waitForA11YShutdown);
}
// Sanity check
ok(!isA11YEnabled(), "Accessibility service in parent process is shut down.");
ok(
!(await SpecialPowers.spawn(browser, [], isA11YEnabled)),
"Accessibility service in content process is shut down."
);
}
registerCleanupFunction(async () => {
info("Cleaning up...");
await shutdownA11y();
@ -156,6 +193,15 @@ async function addTestTab(url) {
* cleanup function to make sure that the panel is still present.
*/
async function disableAccessibilityInspector(env) {
if (
Services.prefs.getBoolPref(
"devtools.accessibility.auto-init.enabled",
false
)
) {
return;
}
const { doc, win, panel } = env;
// Disable accessibility service through the panel and wait for the shutdown
// event.
@ -811,6 +857,9 @@ function addA11YPanelTask(msg, uri, task, options = {}) {
const env = await addTestTab(buildURL(uri, options));
await task(env);
await disableAccessibilityInspector(env);
await closeToolbox();
await shutdownA11y();
await removeTab(gBrowser.selectedTab);
});
}

Просмотреть файл

@ -396,11 +396,6 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
const targets = [...relation.getTargets().enumerate(Ci.nsIAccessible)];
let relationObject;
for (const target of targets) {
// Target of the relation is not part of the current root document.
if (target.rootDocument !== doc.rawAccessible) {
continue;
}
let targetAcc;
try {
targetAcc = this.walker.attachAccessible(target, doc.rawAccessible);

Просмотреть файл

@ -467,7 +467,7 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
}
const doc = this.getRawAccessibleFor(this.rootDoc);
if (isStale(doc)) {
if (!doc || isStale(doc)) {
return this.once("document-ready").then(docAcc => this.addRef(docAcc));
}