Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
"use strict";
const { Actor } = require("resource://devtools/shared/protocol.js");
const {
parentAccessibilitySpec,
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
class ParentAccessibilityActor extends Actor {
constructor(conn) {
super(conn, parentAccessibilitySpec);
this.userPref = Services.prefs.getIntPref(
PREF_ACCESSIBILITY_FORCE_DISABLED
);
if (this.enabled && !this.accService) {
// Set a local reference to an accessibility service if accessibility was
// started elsewhere to ensure that parent process a11y service does not
// get GC'ed away.
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
}
Services.obs.addObserver(this, "a11y-consumers-changed");
Services.prefs.addObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
}
bootstrap() {
return {
canBeDisabled: this.canBeDisabled,
canBeEnabled: this.canBeEnabled,
};
}
observe(subject, topic, data) {
if (topic === "a11y-consumers-changed") {
// This event is fired when accessibility service consumers change. Since
// this observer lives in parent process there are 2 possible consumers of
// a11y service: XPCOM and PlatformAPI (e.g. screen readers). We only care
// about PlatformAPI consumer changes because when set, we can no longer
// disable accessibility service.
const { PlatformAPI } = JSON.parse(data);
this.emit("can-be-disabled-change", !PlatformAPI);
} else if (
!this.disabling &&
topic === "nsPref:changed" &&
data === PREF_ACCESSIBILITY_FORCE_DISABLED
) {
// PREF_ACCESSIBILITY_FORCE_DISABLED preference change event. When set to
// >=1, it means that the user wants to disable accessibility service and
// prevent it from starting in the future. Note: we also check
// this.disabling state when handling this pref change because this is how
// we disable the accessibility inspector itself.
this.emit("can-be-enabled-change", this.canBeEnabled);
}
}
/**
* A getter that indicates if accessibility service is enabled.
*
* @return {Boolean}
* True if accessibility service is on.
*/
get enabled() {
return Services.appinfo.accessibilityEnabled;
}
/**
* A getter that indicates if the accessibility service can be disabled.
*
* @return {Boolean}
* True if accessibility service can be disabled.
*/
get canBeDisabled() {
if (this.enabled) {
const a11yService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
const { PlatformAPI } = JSON.parse(a11yService.getConsumers());
return !PlatformAPI;
}
return true;
}
/**
* A getter that indicates if the accessibility service can be enabled.
*
* @return {Boolean}
* True if accessibility service can be enabled.
*/
get canBeEnabled() {
return Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1;
}
/**
* Enable accessibility service (via XPCOM service).
*/
enable() {
if (this.enabled || !this.canBeEnabled) {
return;
}
this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
}
/**
* Force disable accessibility service. This method removes the reference to
* the XPCOM a11y service object and flips the
* PREF_ACCESSIBILITY_FORCE_DISABLED preference on and off to shutdown a11y
* service.
*/
disable() {
if (!this.enabled || !this.canBeDisabled) {
return;
}
this.disabling = true;
this.accService = null;
// Set PREF_ACCESSIBILITY_FORCE_DISABLED to 1 to force disable
// accessibility service. This is the only way to guarantee an immediate
// accessibility service shutdown in all processes. This also prevents
// accessibility service from starting up in the future.
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
// Set PREF_ACCESSIBILITY_FORCE_DISABLED back to previous default or user
// set value. This will not start accessibility service until the user
// activates it again. It simply ensures that accessibility service can
// start again (when value is below 1).
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, this.userPref);
delete this.disabling;
}
/**
* Destroy the helper class, remove all listeners and if possible disable
* accessibility service in the parent process.
*/
destroy() {
this.disable();
super.destroy();
Services.obs.removeObserver(this, "a11y-consumers-changed");
Services.prefs.removeObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
}
}
exports.ParentAccessibilityActor = ParentAccessibilityActor;