From 28c4fede57e8b11421c103fc36e76ed55fc7f4cf Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 7 Apr 2016 15:00:47 -0700 Subject: [PATCH] Add support for newly added a11y properties in iOS 8 / 9 and tvOS New a11y properties: - accessibilityNavigationStyle - accessibilityHeaderElements - accessibilityActivationPoint - accessibilityPath --- AsyncDisplayKit/ASDisplayNode.h | 7 ++ .../Private/ASDisplayNode+UIViewBridge.mm | 50 ++++++++++ .../Private/ASDisplayNodeInternal.h | 4 + AsyncDisplayKit/Private/_ASPendingState.mm | 91 ++++++++++++++++++- AsyncDisplayKitTests/ASDisplayNodeTests.m | 7 ++ 5 files changed, 158 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 0318ab588b..bef4fc5bbf 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -711,6 +711,13 @@ NS_ASSUME_NONNULL_END @property (atomic, assign) BOOL accessibilityViewIsModal; @property (atomic, assign) BOOL shouldGroupAccessibilityChildren; +@property (nonatomic) UIAccessibilityNavigationStyle accessibilityNavigationStyle NS_AVAILABLE_IOS(8_0); +#if TARGET_OS_TV +@property(nullable, nonatomic, copy) NSArray *accessibilityHeaderElements; +#endif +@property (nonatomic) CGPoint accessibilityActivationPoint; +@property (nullable, nonatomic, copy) UIBezierPath *accessibilityPath; + // Accessibility identification support @property (nullable, nonatomic, copy) NSString *accessibilityIdentifier; diff --git a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm index 9c3b692da7..abb2fedba0 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm @@ -865,6 +865,56 @@ nodeProperty = nodeValueExpr; _setToViewOnly(viewAndPendingViewStateProperty, vi _setAccessibilityToViewAndProperty(_accessibilityIdentifier, accessibilityIdentifier, accessibilityIdentifier, accessibilityIdentifier); } +- (void)setAccessibilityNavigationStyle:(UIAccessibilityNavigationStyle)accessibilityNavigationStyle +{ + _bridge_prologue_write; + _setAccessibilityToViewAndProperty(_accessibilityNavigationStyle, accessibilityNavigationStyle, accessibilityNavigationStyle, accessibilityNavigationStyle); +} + +- (UIAccessibilityNavigationStyle)accessibilityNavigationStyle +{ + _bridge_prologue_read; + return _getAccessibilityFromViewOrProperty(_accessibilityNavigationStyle, accessibilityNavigationStyle); +} + +#if TARGET_OS_TV +- (void)setAccessibilityHeaderElements:(NSArray *)accessibilityHeaderElements +{ + _bridge_prologue_write; + _setAccessibilityToViewAndProperty(_accessibilityHeaderElements, accessibilityHeaderElements, accessibilityHeaderElements, accessibilityHeaderElements); +} + +- (NSArray *)accessibilityHeaderElements +{ + _bridge_prologue_read; + return _getAccessibilityFromViewOrProperty(_accessibilityHeaderElements, accessibilityHeaderElements); +} +#endif + +- (void)setAccessibilityActivationPoint:(CGPoint)accessibilityActivationPoint +{ + _bridge_prologue_write; + _setAccessibilityToViewAndProperty(_accessibilityActivationPoint, accessibilityActivationPoint, accessibilityActivationPoint, accessibilityActivationPoint); +} + +- (CGPoint)accessibilityActivationPoint +{ + _bridge_prologue_read; + return _getAccessibilityFromViewOrProperty(_accessibilityActivationPoint, accessibilityActivationPoint); +} + +- (void)setAccessibilityPath:(UIBezierPath *)accessibilityPath +{ + _bridge_prologue_write; + _setAccessibilityToViewAndProperty(_accessibilityPath, accessibilityPath, accessibilityPath, accessibilityPath); +} + +- (UIBezierPath *)accessibilityPath +{ + _bridge_prologue_read; + return _getAccessibilityFromViewOrProperty(_accessibilityPath, accessibilityPath); +} + - (NSInteger)accessibilityElementCount { _bridge_prologue_read; diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 641288087d..878d921eec 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -141,6 +141,10 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo BOOL _accessibilityViewIsModal; BOOL _shouldGroupAccessibilityChildren; NSString *_accessibilityIdentifier; + UIAccessibilityNavigationStyle _accessibilityNavigationStyle; + NSArray *_accessibilityHeaderElements; + CGPoint _accessibilityActivationPoint; + UIBezierPath *_accessibilityPath; #if TIME_DISPLAYNODE_OPS @public diff --git a/AsyncDisplayKit/Private/_ASPendingState.mm b/AsyncDisplayKit/Private/_ASPendingState.mm index 51aa345ee3..643728f64f 100644 --- a/AsyncDisplayKit/Private/_ASPendingState.mm +++ b/AsyncDisplayKit/Private/_ASPendingState.mm @@ -67,6 +67,10 @@ typedef struct { int setAccessibilityViewIsModal:1; int setShouldGroupAccessibilityChildren:1; int setAccessibilityIdentifier:1; + int setAccessibilityNavigationStyle:1; + int setAccessibilityHeaderElements:1; + int setAccessibilityActivationPoint:1; + int setAccessibilityPath:1; } ASPendingStateFlags; @implementation _ASPendingState @@ -106,6 +110,10 @@ typedef struct { BOOL accessibilityViewIsModal; BOOL shouldGroupAccessibilityChildren; NSString *accessibilityIdentifier; + UIAccessibilityNavigationStyle accessibilityNavigationStyle; + NSArray *accessibilityHeaderElements; + CGPoint accessibilityActivationPoint; + UIBezierPath *accessibilityPath; ASPendingStateFlags _flags; } @@ -226,6 +234,10 @@ static UIColor *defaultTintColor = nil; accessibilityViewIsModal = NO; shouldGroupAccessibilityChildren = NO; accessibilityIdentifier = nil; + accessibilityNavigationStyle = UIAccessibilityNavigationStyleAutomatic; + accessibilityHeaderElements = nil; + accessibilityActivationPoint = CGPointZero; + accessibilityPath = nil; edgeAntialiasingMask = (kCALayerLeftEdge | kCALayerRightEdge | kCALayerTopEdge | kCALayerBottomEdge); return self; @@ -594,6 +606,59 @@ static UIColor *defaultTintColor = nil; } } +- (UIAccessibilityNavigationStyle)accessibilityNavigationStyle +{ + return accessibilityNavigationStyle; +} + +- (void)setAccessibilityNavigationStyle:(UIAccessibilityNavigationStyle)newAccessibilityNavigationStyle +{ + _flags.setAccessibilityNavigationStyle = YES; + accessibilityNavigationStyle = newAccessibilityNavigationStyle; +} + +- (NSArray *)accessibilityHeaderElements +{ + return accessibilityHeaderElements; +} + +- (void)setAccessibilityHeaderElements:(NSArray *)newAccessibilityHeaderElements +{ + _flags.setAccessibilityHeaderElements = YES; + if (accessibilityHeaderElements != newAccessibilityHeaderElements) { + accessibilityHeaderElements = [newAccessibilityHeaderElements copy]; + } +} + +- (CGPoint)accessibilityActivationPoint +{ + if (_flags.setAccessibilityActivationPoint) { + return accessibilityActivationPoint; + } + + // Default == Mid-point of the accessibilityFrame + return CGPointMake(CGRectGetMidX(accessibilityFrame), CGRectGetMidY(accessibilityFrame)); +} + +- (void)setAccessibilityActivationPoint:(CGPoint)newAccessibilityActivationPoint +{ + _flags.setAccessibilityActivationPoint = YES; + accessibilityActivationPoint = newAccessibilityActivationPoint; +} + +- (UIBezierPath *)accessibilityPath +{ + return accessibilityPath; +} + +- (void)setAccessibilityPath:(UIBezierPath *)newAccessibilityPath +{ + _flags.setAccessibilityPath = YES; + if (accessibilityPath != newAccessibilityPath) { + accessibilityPath = newAccessibilityPath; + } +} + - (void)applyToLayer:(CALayer *)layer { ASPendingStateFlags flags = _flags; @@ -827,6 +892,20 @@ static UIColor *defaultTintColor = nil; if (flags.setAccessibilityIdentifier) view.accessibilityIdentifier = accessibilityIdentifier; + + if (flags.setAccessibilityNavigationStyle) + view.accessibilityNavigationStyle = accessibilityNavigationStyle; + +#if TARGET_OS_TV + if (flags.setAccessibilityHeaderElements) + view.accessibilityHeaderElements = accessibilityHeaderElements; +#endif + + if (flags.setAccessibilityActivationPoint) + view.accessibilityActivationPoint = accessibilityActivationPoint; + + if (flags.setAccessibilityPath) + view.accessibilityPath = accessibilityPath; // For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - make sure UIView gets setFrame: if (flags.setFrame && setFrameDirectly) { @@ -926,6 +1005,12 @@ static UIColor *defaultTintColor = nil; pendingState.accessibilityViewIsModal = view.accessibilityViewIsModal; pendingState.shouldGroupAccessibilityChildren = view.shouldGroupAccessibilityChildren; pendingState.accessibilityIdentifier = view.accessibilityIdentifier; + pendingState.accessibilityNavigationStyle = view.accessibilityNavigationStyle; +#if TARGET_OS_TV + pendingState.accessibilityHeaderElements = view.accessibilityHeaderElements; +#endif + pendingState.accessibilityActivationPoint = view.accessibilityActivationPoint; + pendingState.accessibilityPath = view.accessibilityPath; return pendingState; } @@ -992,7 +1077,11 @@ static UIColor *defaultTintColor = nil; || flags.setAccessibilityElementsHidden || flags.setAccessibilityViewIsModal || flags.setShouldGroupAccessibilityChildren - || flags.setAccessibilityIdentifier); + || flags.setAccessibilityIdentifier + || flags.setAccessibilityNavigationStyle + || flags.setAccessibilityHeaderElements + || flags.setAccessibilityActivationPoint + || flags.setAccessibilityPath); } - (void)dealloc diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index 4b3a12c5ff..213923f42d 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -415,6 +415,10 @@ for (ASDisplayNode *n in @[ nodes ]) {\ XCTAssertEqual(YES, node.accessibilityElementsHidden, @"accessibilityElementsHidden broken %@", hasLoadedView); XCTAssertEqual(YES, node.accessibilityViewIsModal, @"accessibilityViewIsModal broken %@", hasLoadedView); XCTAssertEqual(YES, node.shouldGroupAccessibilityChildren, @"shouldGroupAccessibilityChildren broken %@", hasLoadedView); + XCTAssertEqual(UIAccessibilityNavigationStyleSeparate, node.accessibilityNavigationStyle, @"accessibilityNavigationStyle broken %@", hasLoadedView); + XCTAssertTrue(CGPointEqualToPoint(CGPointMake(1.0, 1.0), node.accessibilityActivationPoint), @"accessibilityActivationPoint broken %@", hasLoadedView); + XCTAssertNotNil(node.accessibilityPath, @"accessibilityPath broken %@", hasLoadedView); + if (!isLayerBacked) { XCTAssertEqual(UIViewAutoresizingFlexibleLeftMargin, node.autoresizingMask, @"autoresizingMask %@", hasLoadedView); @@ -468,6 +472,9 @@ for (ASDisplayNode *n in @[ nodes ]) {\ node.accessibilityElementsHidden = YES; node.accessibilityViewIsModal = YES; node.shouldGroupAccessibilityChildren = YES; + node.accessibilityNavigationStyle = UIAccessibilityNavigationStyleSeparate; + node.accessibilityActivationPoint = CGPointMake(1.0, 1.0); + node.accessibilityPath = [UIBezierPath bezierPath]; if (!isLayerBacked) { node.exclusiveTouch = YES;