diff --git a/plugin.xml b/plugin.xml
index 0e86f97..558d9c5 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -62,4 +62,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/windows/mobile-accessibility-proxy.js b/src/windows/mobile-accessibility-proxy.js
new file mode 100644
index 0000000..166c3e5
--- /dev/null
+++ b/src/windows/mobile-accessibility-proxy.js
@@ -0,0 +1,261 @@
+/**
+ *
+ * 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.
+ *
+*/
+
+/*global Windows:true*/
+
+var cordova = require('cordova'),
+ accessibilitySettings,
+ uiSettings,
+ callbackContext,
+ fontScale = 1,
+ styleElement,
+ bodyStyleDeclaration,
+ audio,
+ synth;
+
+function getAccessibilitySettings() {
+ if (!accessibilitySettings) {
+ accessibilitySettings = new Windows.UI.ViewManagement.AccessibilitySettings();
+ }
+ return accessibilitySettings;
+}
+
+function getUISettings() {
+ if (!uiSettings) {
+ uiSettings = new Windows.UI.ViewManagement.UISettings();
+ }
+ return uiSettings;
+}
+
+function getFontScale() {
+ if (!uiSettings) {
+ uiSettings = getUISettings();
+ }
+ var scale = uiSettings.textScaleFactor;
+ // console.log("getFontScale " + scale);
+ return scale;
+}
+
+function getTextZoom() {
+ var zoom = Math.round(fontScale * 100);
+ // console.log("getTextZoom " + zoom);
+ return zoom;
+}
+
+function createStyleElement() {
+ if (!styleElement) {
+ styleElement = document.createElement("style");
+ styleElement.type = "text/css";
+ document.head.appendChild(styleElement);
+ }
+}
+
+function setTextZoom(zoom) {
+ // console.log("setTextZoom " + zoom);
+ fontScale = zoom/100;
+
+ createStyleElement();
+
+ if (bodyStyleDeclaration) {
+ styleElement.removeChild(bodyStyleDeclaration);
+ }
+
+ bodyStyleDeclaration = document.createTextNode("body {-ms-text-size-adjust: " + zoom + "%}");
+
+ styleElement.appendChild(bodyStyleDeclaration);
+}
+
+function onHighContrastChanged(event) {
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.HIGH_CONTRAST_CHANGED,
+ getMobileAccessibilityStatus());
+ sendMobileAccessibilityStatusChangedCallback();
+}
+
+function sendMobileAccessibilityStatusChangedCallback() {
+ console.log("sendMobileAccessibilityStatusChangedCallback");
+ if (callbackContext && typeof callbackContext === "function") {
+ callbackContext(getMobileAccessibilityStatus());
+ }
+}
+
+function getMobileAccessibilityStatus() {
+ return {
+ isScreenReaderRunning: false,
+ isClosedCaptioningEnabled: false,
+ isHighContrastEnabled: accessibilitySettings.highContrast,
+ highContrastScheme: (accessibilitySettings.highContrast ? accessibilitySettings.highContrastScheme : undefined)
+ };
+}
+
+module.exports = {
+ start:function(win, fail, args) {
+ if (typeof win === "function") {
+ callbackContext = win;
+ }
+ if (!accessibilitySettings) {
+ accessibilitySettings = getAccessibilitySettings();
+ }
+ accessibilitySettings.addEventListener("highcontrastchanged", onHighContrastChanged);
+
+ if (!uiSettings) {
+ uiSettings = getUISettings();
+ }
+ },
+ stop:function(win, fail, args) {
+ if (accessibilitySettings) {
+ accessibilitySettings.removeEventListener("highcontrastchanged", onHighContrastChanged);
+ }
+
+ if (synth) {
+ synth.close();
+ synth = null;
+ }
+
+ if (audio) {
+ audio = null;
+ }
+
+ if (callbackContext) {
+ callbackContext = null;
+ }
+ },
+ isScreenReaderRunning:function(win, fail, args) {
+ console && console.error && console.error("Error : Windows 8.1 does not yet have a way to detect that Narrator is running.");
+ fail && setTimeout(function() {
+ fail(new Error("Windows Phone 8.1 does not yet have a way to detect that Narrator is running."));
+ }, 0);
+ if (win && typeof win === "function") {
+ win(false);
+ }
+ },
+ isClosedCaptioningEnabled:function(win, fail, args) {
+ console && console.error && console.error("Error : MobileAccessibility.isClosedCaptioningEnabled is not yet implemented on Windows 8.1.");
+ fail && setTimeout(function() {
+ fail(new Error("MobileAccessibility.isClosedCaptioningEnabled is not yet implemented on Windows 8.1."));
+ }, 0);
+ if (win && typeof win === "function") {
+ win(false);
+ }
+ },
+ isHighContrastEnabled:function(win, fail, args) {
+ if (!accessibilitySettings) {
+ accessibilitySettings = getAccessibilitySettings();
+ }
+
+ if (win && typeof win === "function") {
+ win(accessibilitySettings.highContrast);
+ }
+ return accessibilitySettings.highContrast;
+ },
+ getHighContrastScheme:function(win, fail, args) {
+ if (!accessibilitySettings) {
+ accessibilitySettings = getAccessibilitySettings();
+ }
+
+ var highContrastScheme = accessibilitySettings.highContrast ? accessibilitySettings.highContrastScheme : undefined;
+
+ if (win) {
+ win(highContrastScheme);
+ }
+ return highContrastScheme;
+ },
+ getTextZoom:function(win, fail, args) {
+ var zoom = Math.round(fontScale * 100);
+
+ if (win) {
+ win(zoom);
+ }
+
+ return zoom;
+ },
+ setTextZoom:function(win, fail, args) {
+ var zoom = args[0];
+ setTextZoom(args[0]);
+
+ if (win) {
+ win(zoom);
+ }
+
+ return zoom;
+ },
+ updateTextZoom:function(win, fail, args) {
+ var scale = getFontScale(),
+ zoom;
+ if (scale !== fontScale) {
+ fontScale = scale;
+ }
+ zoom = getTextZoom();
+ setTextZoom(zoom);
+
+ if (win) {
+ win(zoom);
+ }
+
+ return zoom;
+ },
+ postNotification:function(win, fail, args) {
+ var str = args[1];
+
+ if (str && typeof str === "string") {
+ // The object for controlling and playing audio.
+ if (!audio) {
+ audio = new Audio();
+ } else if (audio.pause) {
+ audio.pause();
+ audio.src = null;
+ }
+
+ // The object for controlling the speech synthesis engine (voice).
+ if (!synth) {
+ synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
+ }
+
+ if (str && str.length && str !== "\u200b") {
+
+ // Generate the audio stream from plain text.
+ synth.synthesizeTextToStreamAsync(str).then(function (markersStream) {
+
+ // Convert the stream to a URL Blob.
+ var blob = MSApp.createBlobFromRandomAccessStream(markersStream.contentType, markersStream);
+ // Send the Blob to the audio object.
+ audio.src = URL.createObjectURL(blob, { oneTimeOnly: true });
+ // Start at beginning when speak is hit
+ markersStream.seek(0);
+ audio.AutoPlay = Boolean(true);
+
+ // Audio on completed
+ audio.onended = function () {
+ if (win) {
+ win({
+ stringValue: str,
+ wasSuccessful: true
+ });
+ }
+ };
+
+ audio.play();
+ });
+ }
+ }
+ }
+};
+
+require("cordova/exec/proxy").add("MobileAccessibility", module.exports);
diff --git a/www/MobileAccessibilityNotifications.js b/www/MobileAccessibilityNotifications.js
index 764886c..8cfd03a 100644
--- a/www/MobileAccessibilityNotifications.js
+++ b/www/MobileAccessibilityNotifications.js
@@ -35,5 +35,8 @@ module.exports = {
SCREEN_CHANGED : 1000,
LAYOUT_CHANGED : 1001,
ANNOUNCEMENT : 1008,
- PAGE_SCROLLED : 1009
+ PAGE_SCROLLED : 1009,
+
+ /* Windows specific high contrast event */
+ HIGH_CONTRAST_CHANGED : "highcontrastchanged"
};
diff --git a/www/mobile-accessibility.js b/www/mobile-accessibility.js
index da84839..d5d6336 100644
--- a/www/mobile-accessibility.js
+++ b/www/mobile-accessibility.js
@@ -35,6 +35,9 @@ var MobileAccessibility = function() {
this._isMonoAudioEnabled = false;
this._isTouchExplorationEnabled = false;
this._usePreferredTextZoom = false;
+ this._isHighContrastEnabled = false;
+ this._highContrastScheme = undefined;
+
// Create new event handlers on the window (returns a channel instance)
this.channels = {
screenreaderstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.SCREEN_READER_STATUS_CHANGED),
@@ -42,7 +45,8 @@ var MobileAccessibility = function() {
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)
+ touchexplorationstatechanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED),
+ highcontrastchanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.HIGH_CONTRAST_CHANGED)
};
for (var key in this.channels) {
this.channels[key].onHasSubscribersChange = MobileAccessibility.onHasSubscribersChange;
@@ -59,7 +63,8 @@ function handlers() {
mobileAccessibility.channels.invertcolorsstatuschanged.numHandlers +
mobileAccessibility.channels.monoaudiostatuschanged.numHandlers +
mobileAccessibility.channels.guidedaccessstatuschanged.numHandlers +
- mobileAccessibility.channels.touchexplorationstatechanged.numHandlers;
+ mobileAccessibility.channels.touchexplorationstatechanged.numHandlers +
+ mobileAccessibility.channels.highcontrastchanged.numHandlers;
};
/**
@@ -206,6 +211,14 @@ MobileAccessibility.prototype.isTouchExplorationEnabled = function(callback) {
exec(callback, null, "MobileAccessibility", "isTouchExplorationEnabled", []);
};
+/**
+ * Asynchronous call to native MobileAccessibility to determine if High Contrast is enabled on Windows.
+ * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility.
+ */
+MobileAccessibility.prototype.isHighContrastEnabled = function(callback) {
+ exec(callback, null, "MobileAccessibility", "isHighContrastEnabled", []);
+};
+
/**
* 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.
@@ -293,7 +306,7 @@ MobileAccessibility.prototype.stop = function() {
}
/**
- * Callback from native MobileAccessibility returning an which describes the status of MobileAccessibility features.
+ * Callback from native MobileAccessibility returning an object which describes the status of MobileAccessibility features.
*
* @param {Object} info
* @config {Boolean} [isScreenReaderRunning] Boolean to indicate screen reader status.
@@ -329,7 +342,12 @@ MobileAccessibility.prototype._status = function(info) {
if (mobileAccessibility._isTouchExplorationEnabled !== info.isTouchExplorationEnabled) {
mobileAccessibility._isTouchExplorationEnabled = info.isTouchExplorationEnabled;
cordova.fireWindowEvent(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED, info);
- }
+ }
+ if (mobileAccessibility._isHighContrastEnabled !== info.isHighContrastEnabled) {
+ mobileAccessibility._isHighContrastEnabled = info.isHighContrastEnabled;
+ mobileAccessibility._highContrastScheme = info.highContrastScheme;
+ cordova.fireWindowEvent(MobileAccessibilityNotifications.HIGH_CONTRAST_CHANGED, info);
+ }
}
};