diff --git a/plugin.xml b/plugin.xml
index 16a42d4..3a6b728 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -17,6 +17,10 @@
+
+
+
+
diff --git a/www/MobileAccessibilityNotifications.js b/www/MobileAccessibilityNotifications.js
new file mode 100644
index 0000000..764886c
--- /dev/null
+++ b/www/MobileAccessibilityNotifications.js
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/**
+ * Mobile Accessibility Notification event constants
+ */
+module.exports = {
+ /* MobileAccessibility window events */
+ SCREEN_READER_STATUS_CHANGED : "screenreaderstatuschanged",
+ CLOSED_CAPTIONING_STATUS_CHANGED : "closedcaptioningstatuschanged",
+ GUIDED_ACCESS_STATUS_CHANGED : "guidedaccessstatuschanged",
+ INVERT_COLORS_STATUS_CHANGED : "invertcolorsstatuschanged",
+ MONO_AUDIO_STATUS_CHANGED : "monoaudiostatuschanged",
+ TOUCH_EXPLORATION_STATUS_CHANGED : "touchexplorationstatechanged",
+
+ /* iOS specific UIAccessibilityNotifications */
+ SCREEN_CHANGED : 1000,
+ LAYOUT_CHANGED : 1001,
+ ANNOUNCEMENT : 1008,
+ PAGE_SCROLLED : 1009
+};
diff --git a/www/mobile-accessibility.js b/www/mobile-accessibility.js
index 4f00943..d05a330 100644
--- a/www/mobile-accessibility.js
+++ b/www/mobile-accessibility.js
@@ -1,4 +1,4 @@
-/*
+/**
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -24,7 +24,8 @@ var argscheck = require('cordova/argscheck'),
exec = require('cordova/exec'),
device = require('org.apache.cordova.device.device'),
network = require('org.apache.cordova.network-information.network'),
- connection = require('org.apache.cordova.network-information.Connection');
+ connection = require('org.apache.cordova.network-information.Connection'),
+ MobileAccessibilityNotifications = require('com.phonegap.plugin.mobile-accessibility.MobileAccessibilityNotifications');
var MobileAccessibility = function() {
this._isScreenReaderRunning = false;
@@ -36,12 +37,12 @@ var MobileAccessibility = function() {
this._usePreferredTextZoom = false;
// Create new event handlers on the window (returns a channel instance)
this.channels = {
- screenreaderstatuschanged:cordova.addWindowEventHandler("screenreaderstatuschanged"),
- closedcaptioningstatuschanged:cordova.addWindowEventHandler("closedcaptioningstatuschanged"),
- guidedaccessstatuschanged:cordova.addWindowEventHandler("guidedaccessstatuschanged"),
- invertcolorsstatuschanged:cordova.addWindowEventHandler("invertcolorsstatuschanged"),
- monoaudiostatuschanged:cordova.addWindowEventHandler("monoaudiostatuschanged"),
- touchexplorationstatechanged:cordova.addWindowEventHandler("touchexplorationstatechanged")
+ screenreaderstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.SCREEN_READER_STATUS_CHANGED),
+ closedcaptioningstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.CLOSED_CAPTIONING_STATUS_CHANGED),
+ guidedaccessstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.GUIDED_ACCESS_STATUS_CHANGED),
+ invertcolorsstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.INVERT_COLORS_STATUS_CHANGED),
+ monoaudiostatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.MONO_AUDIO_STATUS_CHANGED),
+ touchexplorationstatechanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED)
};
for (var key in this.channels) {
this.channels[key].onHasSubscribersChange = MobileAccessibility.onHasSubscribersChange;
@@ -83,72 +84,84 @@ MobileAccessibility.onHasSubscribersChange = function() {
* @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility.
*/
MobileAccessibility.prototype.isScreenReaderRunning = function(callback) {
- exec(function(bool) {
- mobileAccessibility.activateOrDeactivateChromeVox(bool);
- callback(Boolean(bool));
- }, null, "MobileAccessibility", "isScreenReaderRunning", []);
+ exec(function(bool) {
+ mobileAccessibility.activateOrDeactivateChromeVox(bool);
+ callback(Boolean(bool));
+ }, null, "MobileAccessibility", "isScreenReaderRunning", []);
+};
+MobileAccessibility.prototype.isVoiceOverRunning = function(callback) {
+ if (device.platform.toLowerCase() === "ios") {
+ MobileAccessibility.prototype.isScreenReaderRunning(callback);
+ } else {
+ callback(false);
+ }
+};
+MobileAccessibility.prototype.isTalkBackRunning = function(callback) {
+ if (device.platform.toLowerCase() === "android" || device.platform.toLowerCase() === "amazon-fireos") {
+ MobileAccessibility.prototype.isScreenReaderRunning(callback);
+ } else {
+ callback(false);
+ }
};
-MobileAccessibility.prototype.isVoiceOverRunning = MobileAccessibility.prototype.isScreenReaderRunning;
-MobileAccessibility.prototype.isTalkBackRunning = MobileAccessibility.prototype.isScreenReaderRunning;
MobileAccessibility.prototype.isChromeVoxActive = function () {
- return typeof cvox !== "undefined" && cvox.ChromeVox.host.ttsLoaded() && cvox.Api.isChromeVoxActive();
+ return typeof cvox !== "undefined" && cvox.ChromeVox.host.ttsLoaded() && cvox.Api.isChromeVoxActive();
};
MobileAccessibility.prototype.activateOrDeactivateChromeVox = function(bool) {
- if (device.platform !== "Android") return;
- if (typeof cvox === "undefined") {
- if (bool) {
- console.warn('A screen reader is running but ChromeVox has failed to initialize.');
- if (navigator.connection.type === Connection.UNKNOWN || navigator.connection.type === Connection.NONE) {
- mobileAccessibility.injectLocalAndroidVoxScript();
- }
- }
- } else {
- // activate or deactivate ChromeVox based on whether or not or not the screen reader is running.
- try {
- cvox.ChromeVox.host.activateOrDeactivateChromeVox(bool);
- } catch (err) {
- console.error(err);
- }
- }
-
- if (bool) {
- if (!mobileAccessibility.hasOrientationChangeListener) {
- window.addEventListener("orientationchange", mobileAccessibility.onOrientationChange);
- mobileAccessibility.hasOrientationChangeListener = true;
- }
- } else if(mobileAccessibility.hasOrientationChangeListener) {
- window.removeEventListener("orientationchange", mobileAccessibility.onOrientationChange);
- mobileAccessibility.hasOrientationChangeListener = false;
- }
+ if (device.platform !== "Android") return;
+ if (typeof cvox === "undefined") {
+ if (bool) {
+ console.warn('A screen reader is running but ChromeVox has failed to initialize.');
+ if (navigator.connection.type === Connection.UNKNOWN || navigator.connection.type === Connection.NONE) {
+ mobileAccessibility.injectLocalAndroidVoxScript();
+ }
+ }
+ } else {
+ // activate or deactivate ChromeVox based on whether or not or not the screen reader is running.
+ try {
+ cvox.ChromeVox.host.activateOrDeactivateChromeVox(bool);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
+ if (bool) {
+ if (!mobileAccessibility.hasOrientationChangeListener) {
+ window.addEventListener("orientationchange", mobileAccessibility.onOrientationChange);
+ mobileAccessibility.hasOrientationChangeListener = true;
+ }
+ } else if(mobileAccessibility.hasOrientationChangeListener) {
+ window.removeEventListener("orientationchange", mobileAccessibility.onOrientationChange);
+ mobileAccessibility.hasOrientationChangeListener = false;
+ }
};
MobileAccessibility.prototype.hasOrientationChangeListener = false;
MobileAccessibility.prototype.onOrientationChange = function(event) {
- if (!mobileAccessibility.isChromeVoxActive()) return;
- cvox.ChromeVox.navigationManager.updateIndicator();
+ if (!mobileAccessibility.isChromeVoxActive()) return;
+ cvox.ChromeVox.navigationManager.updateIndicator();
};
MobileAccessibility.prototype.scriptInjected = false;
MobileAccessibility.prototype.injectLocalAndroidVoxScript = function() {
- var versionsplit = device.version.split('.');
- if (device.platform !== "Android" ||
- !(versionsplit[0] > 4 || (versionsplit[0] == 4 && versionsplit[1] >= 1)) ||
- typeof cvox !== "undefined" || mobileAccessibility.scriptInjected) return;
- var script = document.createElement('script');
+ var versionsplit = device.version.split('.');
+ if (device.platform !== "Android" ||
+ !(versionsplit[0] > 4 || (versionsplit[0] == 4 && versionsplit[1] >= 1)) ||
+ typeof cvox !== "undefined" || mobileAccessibility.scriptInjected) return;
+ var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function(){
- // console.log(this.src + ' has loaded');
- if (mobileAccessibility.isChromeVoxActive()) {
- cordova.fireWindowEvent("screenreaderstatuschanged", {
- isScreenReaderRunning: true
- });
- }
+ // console.log(this.src + ' has loaded');
+ if (mobileAccessibility.isChromeVoxActive()) {
+ cordova.fireWindowEvent("screenreaderstatuschanged", {
+ isScreenReaderRunning: true
+ });
+ }
};
-
- script.src = (versionsplit[0] > 4 || versionsplit[1] > 3)
- ? "plugins/com.phonegap.plugin.mobile-accessibility/android/chromeandroidvox.js"
- : "plugins/com.phonegap.plugin.mobile-accessibility/android/AndroidVox_v1.js";
+
+ script.src = (versionsplit[0] > 4 || versionsplit[1] > 3)
+ ? "plugins/com.phonegap.plugin.mobile-accessibility/android/chromeandroidvox.js"
+ : "plugins/com.phonegap.plugin.mobile-accessibility/android/AndroidVox_v1.js";
document.getElementsByTagName('head')[0].appendChild(script);
mobileAccessibility.scriptInjected = true;
};
@@ -193,49 +206,57 @@ MobileAccessibility.prototype.isTouchExplorationEnabled = function(callback) {
exec(callback, null, "MobileAccessibility", "isTouchExplorationEnabled", []);
};
+/**
+ * Asynchronous call to native MobileAccessibility to return the current text zoom percent value for the WebView.
+ * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility.
+ */
MobileAccessibility.prototype.getTextZoom = function(callback) {
- exec(callback, null, "MobileAccessibility", "getTextZoom", []);
+ exec(callback, null, "MobileAccessibility", "getTextZoom", []);
};
+/**
+ * Asynchronous call to native MobileAccessibility to set the current text zoom percent value for the WebView.
+ * @param {Number} textZoom A percentage value by which text in the WebView should be scaled.
+ * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility.
+ */
MobileAccessibility.prototype.setTextZoom = function(textZoom, callback) {
- exec(callback, null, "MobileAccessibility", "setTextZoom", [textZoom]);
+ exec(callback, null, "MobileAccessibility", "setTextZoom", [textZoom]);
};
-MobileAccessibility.prototype.updateTextZoom = function() {
- exec(null, null, "MobileAccessibility", "updateTextZoom", []);
+/**
+ * Asynchronous call to native MobileAccessibility to retrieve the user's preferred text zoom from system settings and apply it to the application WebView.
+ * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility.
+ */
+MobileAccessibility.prototype.updateTextZoom = function(callback) {
+ exec(callback, null, "MobileAccessibility", "updateTextZoom", []);
};
MobileAccessibility.prototype.usePreferredTextZoom = function(bool) {
- var currentValue = window.localStorage.getItem("MobileAccessibility.usePreferredTextZoom") === "true";
-
- if (arguments.length === 0) {
- return currentValue;
- }
-
- if (currentValue != bool) {
- window.localStorage.setItem("MobileAccessibility.usePreferredTextZoom", bool);
- }
-
- document.removeEventListener("resume", mobileAccessibility.updateTextZoom);
-
- if (bool) {
- // console.log("We should update the text zoom at this point: " + bool)
- document.addEventListener("resume", mobileAccessibility.updateTextZoom, false);
- mobileAccessibility.updateTextZoom();
- } else {
- mobileAccessibility.setTextZoom(100);
- }
-
- return Boolean(bool);
+ var currentValue = window.localStorage.getItem("MobileAccessibility.usePreferredTextZoom") === "true";
+
+ if (arguments.length === 0) {
+ return currentValue;
+ }
+
+ if (currentValue != bool) {
+ window.localStorage.setItem("MobileAccessibility.usePreferredTextZoom", bool);
+ }
+
+ document.removeEventListener("resume", mobileAccessibility.updateTextZoom);
+
+ if (bool) {
+ // console.log("We should update the text zoom at this point: " + bool)
+ document.addEventListener("resume", mobileAccessibility.updateTextZoom, false);
+ mobileAccessibility.updateTextZoom();
+ } else {
+ mobileAccessibility.setTextZoom(100);
+ }
+
+ return Boolean(bool);
};
-MobileAccessibility.prototype.MobileAccessibilityNotifications = {
- SCREEN_CHANGED : 1000,
- LAYOUT_CHANGED : 1001,
- ANNOUNCEMENT : 1008,
- PAGE_SCROLLED : 1009
-}
-
+MobileAccessibility.prototype.MobileAccessibilityNotifications = MobileAccessibilityNotifications;
+
/**
* Posts a notification with a string for a screen reader to announce, if it is running.
* @param {uint} mobileAccessibilityNotification A numeric constant for the type of notification to send. Constants are defined in MobileAccessibility.MobileAccessibilityNotifications.
@@ -253,22 +274,22 @@ MobileAccessibility.prototype.postNotification = function(mobileAccessibilityNot
* @param {Object} [properties] Speech properties to use for this utterance.
*/
MobileAccessibility.prototype.speak = function(string, queueMode, properties) {
- if (this.isChromeVoxActive()) {
- cvox.ChromeVox.tts.speak(string, queueMode, properties);
- } else {
- exec(null, null, "MobileAccessibility", "postNotification", [mobileAccessibility.MobileAccessibilityNotifications.ANNOUNCEMENT, string]);
- }
+ if (this.isChromeVoxActive()) {
+ cvox.ChromeVox.tts.speak(string, queueMode, properties);
+ } else {
+ exec(null, null, "MobileAccessibility", "postNotification", [MobileAccessibilityNotifications.ANNOUNCEMENT, string]);
+ }
}
/**
* Stops speech.
*/
MobileAccessibility.prototype.stop = function() {
- if (this.isChromeVoxActive()) {
- cvox.ChromeVox.tts.stop();
- } else {
- exec(null, null, "MobileAccessibility", "postNotification", [mobileAccessibility.MobileAccessibilityNotifications.ANNOUNCEMENT]);
- }
+ if (this.isChromeVoxActive()) {
+ cvox.ChromeVox.tts.stop();
+ } else {
+ exec(null, null, "MobileAccessibility", "postNotification", [MobileAccessibilityNotifications.ANNOUNCEMENT]);
+ }
}
/**
@@ -284,30 +305,30 @@ MobileAccessibility.prototype.stop = function() {
*/
MobileAccessibility.prototype._status = function(info) {
if (info) {
- mobileAccessibility.activateOrDeactivateChromeVox(info.isScreenReaderRunning);
- if (mobileAccessibility._isScreenReaderRunning !== info.isScreenReaderRunning) {
+ mobileAccessibility.activateOrDeactivateChromeVox(info.isScreenReaderRunning);
+ if (mobileAccessibility._isScreenReaderRunning !== info.isScreenReaderRunning) {
mobileAccessibility._isScreenReaderRunning = info.isScreenReaderRunning;
- cordova.fireWindowEvent("screenreaderstatuschanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.SCREEN_READER_STATUS_CHANGED, info);
}
if (mobileAccessibility._isClosedCaptioningEnabled !== info.isClosedCaptioningEnabled) {
mobileAccessibility._isClosedCaptioningEnabled = info.isClosedCaptioningEnabled;
- cordova.fireWindowEvent("closedcaptioningstatuschanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.CLOSED_CAPTIONING_STATUS_CHANGED, info);
}
if (mobileAccessibility._isGuidedAccessEnabled !== info.isGuidedAccessEnabled) {
mobileAccessibility._isGuidedAccessEnabled = info.isGuidedAccessEnabled;
- cordova.fireWindowEvent("guidedaccessstatuschanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.GUIDED_ACCESS_STATUS_CHANGED, info);
}
if (mobileAccessibility._isInvertColorsEnabled !== info.isInvertColorsEnabled) {
mobileAccessibility._isInvertColorsEnabled = info.isInvertColorsEnabled;
- cordova.fireWindowEvent("invertcolorsstatuschanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.INVERT_COLORS_STATUS_CHANGED, info);
}
if (mobileAccessibility._isMonoAudioEnabled !== info.isMonoAudioEnabled) {
mobileAccessibility._isMonoAudioEnabled = info.isMonoAudioEnabled;
- cordova.fireWindowEvent("monoaudiostatuschanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.MONO_AUDIO_STATUS_CHANGED, info);
}
if (mobileAccessibility._isTouchExplorationEnabled !== info.isTouchExplorationEnabled) {
mobileAccessibility._isTouchExplorationEnabled = info.isTouchExplorationEnabled;
- cordova.fireWindowEvent("touchexplorationstatechanged", info);
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED, info);
}
}
};
@@ -320,5 +341,5 @@ MobileAccessibility.prototype._error = function(e) {
};
var mobileAccessibility = new MobileAccessibility();
-
+
module.exports = mobileAccessibility;