154 lines
5 KiB
JavaScript
154 lines
5 KiB
JavaScript
/* 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,
|
|
} = require("resource://devtools/shared/specs/accessibility.js");
|
|
|
|
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;
|