diff --git a/README.md b/README.md index c120bd2..1117b00 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ The `MobileAccessibility` object, exposed by `window.MobileAccessibility`, provi - MobileAccessibility.isGuidedAccessEnabled - MobileAccessibility.isInvertColorsEnabled - MobileAccessibility.isMonoAudioEnabled +- MobileAccessibility.isReduceMotionEnabled - MobileAccessibility.isTouchExplorationEnabled - MobileAccessibility.getTextZoom - MobileAccessibility.setTextZoom @@ -284,6 +285,35 @@ Makes an asynchronous call to native `MobileAccessibility` to determine if mono - iOS +---------------------------------------------------- +#### MobileAccessibility.isReduceMotionEnabled(callback) + + +An iOS-specific proxy for the `MobileAccessibility.UIAccessibilityIsReduceMotionEnabled` method. + +##### Parameters + +- __callback__ (Function) A callback method to receive the boolean result asynchronously from the native `MobileAccessibility` plugin. + +##### Usage + +```javascript + function isReduceMotionEnabledCallback(boolean) { + if (boolean) { + console.log("Reduce Motion: ON"); + // Do something to improve the behavior of the application when reduce motion is enabled. + } else { + console.log("Reduce Motion: OFF"); + } + } + + MobileAccessibility.isReduceMotionEnabled(isReduceMotionEnabledCallback); +``` + +##### Supported Platforms + +- iOS + ------------------------------------------------------------ #### MobileAccessibility.isTouchExplorationEnabled(callback) @@ -503,6 +533,7 @@ The following event constants are for `window` events, to which an application c - MobileAccessibilityNotifications.GUIDED_ACCESS_STATUS_CHANGED - MobileAccessibilityNotifications.INVERT_COLORS_STATUS_CHANGED - MobileAccessibilityNotifications.MONO_AUDIO_STATUS_CHANGED +- MobileAccessibilityNotifications.REDUCE_MOTION_STATUS_CHANGED - MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED ---------------------------------------------------------------------------------------------- @@ -625,6 +656,30 @@ If a screen reader is active, `info.isMonoAudioEnabled` will equal `true`. window.addEventListener(MobileAccessibilityNotifications.MONO_AUDIO_STATUS_CHANGED, onMonoAudioStatusChanged, false); ``` +---------------------------------------------------------------------------------------- +#### MobileAccessibilityNotifications.REDUCE_MOTION_STATUS_CHANGED (reducemotionstatuschanged) + +The event fires when Reduce Motion has been enabled on an iOS device. +The event returns an object, `info`, with the current status of accessibility features on the device. +If a screen reader is active, `info.isReduceMotionEnabled` will equal `true`. + +```javascript + // Define a persistent callback method to handle the event + function onReduceMotionStatusChanged(info) { + if (info && typeof info.isReduceMotionEnabled !== "undefined") { + if (info.isReduceMotionEnabled) { + console.log("Reduce Motion: ON"); + // Do something to improve the behavior of the application while Reduce Motion is enabled. + } else { + console.log("Reduce Motion: OFF"); + } + } + } + + // Register the callback method to handle the event + window.addEventListener(MobileAccessibilityNotifications.REDUCE_MOTION_STATUS_CHANGED, onMReduceMotionStatusChanged, false); +``` + ------------------------------------------------------------------------------------------------------ #### MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED (touchexplorationstatuschanged) diff --git a/src/ios/CDVMobileAccessibility.h b/src/ios/CDVMobileAccessibility.h index 12c6b82..9aa698a 100644 --- a/src/ios/CDVMobileAccessibility.h +++ b/src/ios/CDVMobileAccessibility.h @@ -31,6 +31,7 @@ static const int BASE_UI_FONT_TEXT_STYLE_BODY_POINT_SIZE = 16; BOOL guidedAccessEnabled; BOOL invertColorsEnabled; BOOL monoAudioEnabled; + BOOL reduceMotionEnabled; } @property (strong) NSString* callbackId; @@ -40,6 +41,7 @@ static const int BASE_UI_FONT_TEXT_STYLE_BODY_POINT_SIZE = 16; @property BOOL guidedAccessEnabled; @property BOOL invertColorsEnabled; @property BOOL monoAudioEnabled; +@property BOOL reduceMotionEnabled; @property double mFontScale; @@ -51,6 +53,7 @@ static const int BASE_UI_FONT_TEXT_STYLE_BODY_POINT_SIZE = 16; - (void) getTextZoom:(CDVInvokedUrlCommand*)command; - (void) setTextZoom:(CDVInvokedUrlCommand*)command; - (void) updateTextZoom:(CDVInvokedUrlCommand*)command; +- (void) isReduceMotionEnabled:(CDVInvokedUrlCommand*)command; - (void) postNotification:(CDVInvokedUrlCommand*)command; - (void) start:(CDVInvokedUrlCommand*)command; - (void) stop:(CDVInvokedUrlCommand*)command; diff --git a/src/ios/CDVMobileAccessibility.m b/src/ios/CDVMobileAccessibility.m index f8e771c..4143584 100644 --- a/src/ios/CDVMobileAccessibility.m +++ b/src/ios/CDVMobileAccessibility.m @@ -39,8 +39,10 @@ @synthesize invertColorsEnabled; @synthesize monoAudioEnabled; @synthesize mFontScale; +@synthesize reduceMotionEnabled; #define iOS7Delta (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 ) ? 20 : 0 ) +#define iOS8Delta (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 ) ? 30 : 0 ) // ////////////////////////////////////////////////// @@ -215,6 +217,19 @@ } } +- (void)isReduceMotionEnabled:(CDVInvokedUrlCommand*)command +{ + [self.commandDelegate runInBackground:^{ + if (iOS8Delta) { + self.reduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled(); + } else { + self.reduceMotionEnabled = false; + } + CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:self.reduceMotionEnabled]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; +} + - (void)postNotification:(CDVInvokedUrlCommand *)command { @@ -309,6 +324,7 @@ self.guidedAccessEnabled = UIAccessibilityIsGuidedAccessEnabled(); self.invertColorsEnabled = UIAccessibilityIsInvertColorsEnabled(); self.monoAudioEnabled = UIAccessibilityIsMonoAudioEnabled(); + self.reduceMotionEnabled = UIAccessibilityIsReduceMotionEnabled(); NSMutableDictionary* mobileAccessibilityData = [NSMutableDictionary dictionaryWithCapacity:5]; [mobileAccessibilityData setObject:[NSNumber numberWithBool:self.voiceOverRunning] forKey:@"isScreenReaderRunning"]; @@ -316,6 +332,7 @@ [mobileAccessibilityData setObject:[NSNumber numberWithBool:self.guidedAccessEnabled] forKey:@"isGuidedAccessEnabled"]; [mobileAccessibilityData setObject:[NSNumber numberWithBool:self.invertColorsEnabled] forKey:@"isInvertColorsEnabled"]; [mobileAccessibilityData setObject:[NSNumber numberWithBool:self.monoAudioEnabled] forKey:@"isMonoAudioEnabled"]; + [mobileAccessibilityData setObject:[NSNumber numberWithBool:self.reduceMotionEnabled] forKey:@"isReduceMotionEnabled"]; return mobileAccessibilityData; } @@ -330,6 +347,7 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mobileAccessibilityStatusChanged:) name:UIAccessibilityGuidedAccessStatusDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mobileAccessibilityStatusChanged:) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mobileAccessibilityStatusChanged:) name:UIAccessibilityMonoAudioStatusDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mobileAccessibilityStatusChanged:) name:UIAccessibilityReduceMotionStatusDidChangeNotification object:nil]; // Update the callback on start CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getMobileAccessibilityStatus]]; @@ -356,6 +374,7 @@ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityAnnouncementDidFinishNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityMonoAudioStatusDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityReduceMotionStatusDidChangeNotification object:nil]; }]; } diff --git a/www/MobileAccessibilityNotifications.js b/www/MobileAccessibilityNotifications.js index 8cfd03a..0cbcaa4 100644 --- a/www/MobileAccessibilityNotifications.js +++ b/www/MobileAccessibilityNotifications.js @@ -29,6 +29,7 @@ module.exports = { GUIDED_ACCESS_STATUS_CHANGED : "guidedaccessstatuschanged", INVERT_COLORS_STATUS_CHANGED : "invertcolorsstatuschanged", MONO_AUDIO_STATUS_CHANGED : "monoaudiostatuschanged", + REDUCE_MOTION_STATUS_CHANGED : "reducemotionstatuschanged", TOUCH_EXPLORATION_STATUS_CHANGED : "touchexplorationstatechanged", /* iOS specific UIAccessibilityNotifications */ diff --git a/www/mobile-accessibility.js b/www/mobile-accessibility.js index 8065b6a..8f7667a 100644 --- a/www/mobile-accessibility.js +++ b/www/mobile-accessibility.js @@ -33,6 +33,7 @@ var MobileAccessibility = function() { this._isGuidedAccessEnabled = false; this._isInvertColorsEnabled = false; this._isMonoAudioEnabled = false; + this._isReduceMotionEnabled = false; this._isTouchExplorationEnabled = false; this._usePreferredTextZoom = false; this._isHighContrastEnabled = false; @@ -45,6 +46,7 @@ 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), + reducemotionstatuschanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.REDUCE_MOTION_STATUS_CHANGED), touchexplorationstatechanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED), highcontrastchanged : cordova.addWindowEventHandler(MobileAccessibilityNotifications.HIGH_CONTRAST_CHANGED) }; @@ -62,6 +64,7 @@ function handlers() { mobileAccessibility.channels.closedcaptioningstatuschanged.numHandlers + mobileAccessibility.channels.invertcolorsstatuschanged.numHandlers + mobileAccessibility.channels.monoaudiostatuschanged.numHandlers + + mobileAccessibility.channels.reducemotionstatuschanged.numHandlers + mobileAccessibility.channels.guidedaccessstatuschanged.numHandlers + mobileAccessibility.channels.touchexplorationstatechanged.numHandlers + mobileAccessibility.channels.highcontrastchanged.numHandlers; @@ -195,6 +198,14 @@ MobileAccessibility.prototype.isMonoAudioEnabled = function(callback) { exec(callback, null, "MobileAccessibility", "isMonoAudioEnabled", []); }; +/** + * Asynchronous call to native MobileAccessibility to determine if mono audio is enabled. + * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility. + */ +MobileAccessibility.prototype.isReduceMotionEnabled = function(callback) { + exec(callback, null, "MobileAccessibility", "isReduceMotionEnabled", []); +}; + /** * Asynchronous call to native MobileAccessibility to determine if Guided Access is enabled. * @param {function} callback A callback method to receive the asynchronous result from the native MobileAccessibility. @@ -255,12 +266,12 @@ MobileAccessibility.prototype.usePreferredTextZoom = function(bool) { window.localStorage.setItem("MobileAccessibility.usePreferredTextZoom", bool); } - var callback = function(){ + var callback = function(){ // Wrapping updateTextZoom call in a function to stop // the event parameter propagation. This fixes an error // on resume where cordova tried to call apply() on the // event, expecting a function. - mobileAccessibility.updateTextZoom(); + mobileAccessibility.updateTextZoom(); }; document.removeEventListener("resume", callback); @@ -347,6 +358,10 @@ MobileAccessibility.prototype._status = function(info) { mobileAccessibility._isMonoAudioEnabled = info.isMonoAudioEnabled; cordova.fireWindowEvent(MobileAccessibilityNotifications.MONO_AUDIO_STATUS_CHANGED, info); } + if (mobileAccessibility._isReduceMotionEnabled !== info.isReduceMotionEnabled) { + mobileAccessibility._isReduceMotionEnabled = info.isReduceMotionEnabled; + cordova.fireWindowEvent(MobileAccessibilityNotifications.REDUCE_MOTION_STATUS_CHANGED, info); + } if (mobileAccessibility._isTouchExplorationEnabled !== info.isTouchExplorationEnabled) { mobileAccessibility._isTouchExplorationEnabled = info.isTouchExplorationEnabled; cordova.fireWindowEvent(MobileAccessibilityNotifications.TOUCH_EXPLORATION_STATUS_CHANGED, info);