forked from google/GTXiLib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sid Janga
committed
Mar 20, 2018
0 parents
commit 8eb1d93
Showing
76 changed files
with
7,814 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# How to Contribute | ||
|
||
We'd love to accept your patches and contributions to this project. There are | ||
just a few small guidelines you need to follow. | ||
|
||
## Contributor License Agreement | ||
|
||
Contributions to this project must be accompanied by a Contributor License | ||
Agreement. You (or your employer) retain the copyright to your contribution, | ||
this simply gives us permission to use and redistribute your contributions as | ||
part of the project. Head over to <https://cla.developers.google.com/> to see | ||
your current agreements on file or to sign a new one. | ||
|
||
You generally only need to submit a CLA once, so if you've already submitted one | ||
(even if it was for a different project), you probably don't need to do it | ||
again. | ||
|
||
## Code reviews | ||
|
||
All submissions, including submissions by project members, require review. We | ||
use GitHub pull requests for this purpose. Consult | ||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more | ||
information on using pull requests. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed 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. | ||
// | ||
|
||
/** | ||
* Umbrella header for public GTX APIs. | ||
*/ | ||
#import <UIKit/UIKit.h> | ||
|
||
//! Project version number for GTAxe. | ||
FOUNDATION_EXPORT double GTAxeVersionNumber; | ||
|
||
//! Project version string for GTAxe. | ||
FOUNDATION_EXPORT const unsigned char GTAxeVersionString[]; | ||
|
||
#import <GTAxe/GTXAccessibilityTree.h> | ||
#import <GTAxe/GTXAnalytics.h> | ||
#import <GTAxe/GTXAnalyticsUtils.h> | ||
#import <GTAxe/GTXAssertions.h> | ||
#import <GTAxe/GTXAxeCore.h> | ||
#import <GTAxe/GTXCheckBlock.h> | ||
#import <GTAxe/GTXChecksCollection.h> | ||
#import <GTAxe/GTXCommon.h> | ||
#import <GTAxe/GTXElementBlacklist.h> | ||
#import <GTAxe/GTXErrorReporter.h> | ||
#import <GTAxe/GTXImageRGBAData.h> | ||
#import <GTAxe/GTXImageAndColorUtils.h> | ||
#import <GTAxe/GTXLogging.h> | ||
#import <GTAxe/GTXPluginXCTestCase.h> | ||
#import <GTAxe/GTXToolKit.h> | ||
#import <GTAxe/GTXTestSuite.h> | ||
#import <GTAxe/NSError+GTXAdditions.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed 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. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/** | ||
* An enumerator for the accessibility trees navigated by accessibility services like VoiceOver. | ||
*/ | ||
@interface GTXAccessibilityTree : NSEnumerator | ||
|
||
/** | ||
* Creates a new accessibility tree whose traversals will include the given @c rootElements. | ||
*/ | ||
- (instancetype)initWithRootElements:(NSArray *)rootElements; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed 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. | ||
// | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
#import "GTXAccessibilityTree.h" | ||
|
||
/** | ||
* There seems to be errors in accessibility children reported by some UIKit classes especially | ||
* UITextEffectsWindow which reports 9223372036854775807 possibly due to internal type conversions | ||
* with -1, we use this bounds value to detect that case.. | ||
*/ | ||
const NSInteger kAccessibilityChildrenUpperBound = 50000; | ||
|
||
@implementation GTXAccessibilityTree { | ||
// A queue of elements to be visited. | ||
NSMutableArray *_queue; | ||
// A queue of elements already visited. | ||
NSMutableSet *_visitedElements; | ||
} | ||
|
||
- (instancetype)initWithRootElements:(NSArray *)rootElements { | ||
self = [super init]; | ||
if (self) { | ||
_queue = [[NSMutableArray alloc] initWithArray:rootElements]; | ||
_visitedElements = [[NSMutableSet alloc] init]; | ||
} | ||
return self; | ||
} | ||
|
||
#pragma mark - NSEnumerator | ||
|
||
- (id)nextObject { | ||
if ([_queue count] == 0) { | ||
return nil; | ||
} | ||
|
||
id nextInQueue; | ||
// Get the next "unvisited" element. | ||
do { | ||
id candidateNext = [_queue firstObject]; | ||
[_queue removeObjectAtIndex:0]; | ||
if (![_visitedElements containsObject:candidateNext]) { | ||
if (![self gtx_isAccessibilityHiddenElement:candidateNext]) { | ||
nextInQueue = candidateNext; | ||
} | ||
} | ||
} while ([_queue count] > 0 && !nextInQueue); | ||
if (!nextInQueue) { | ||
return nil; | ||
} | ||
|
||
[_visitedElements addObject:nextInQueue]; | ||
if ([nextInQueue respondsToSelector:@selector(isAccessibilityElement)]) { | ||
if (![nextInQueue isAccessibilityElement]) { | ||
// nextInQueue could be an accessibility container, if so enqueue its children. | ||
// There are two ways of getting the children of an accessibility container: | ||
// First, using @selector(accessibilityElements) | ||
NSArray *axElements = [self gtx_accessibilityElementsOfElement:nextInQueue]; | ||
|
||
// Second, using @selector(accessibilityElementAtIndex:) | ||
NSArray *axElementsFromIndices = | ||
[self gtx_accessibilityElementsFromIndicesOfElement:nextInQueue]; | ||
|
||
// Ensure that either the children are available only through one method or elements via both | ||
// are the same. Otherwise we must fail as the the accessibility tree is inconsistent. | ||
if (axElements && axElementsFromIndices) { | ||
NSSet *accessibilityElementsSet = [NSSet setWithArray:axElements]; | ||
NSSet *accessibilityElementsFromIndicesSet = [NSSet setWithArray:axElementsFromIndices]; | ||
NSAssert([accessibilityElementsSet isEqualToSet:accessibilityElementsFromIndicesSet], | ||
@"Accessibility elements obtained from -accessibilityElements and" | ||
@" -accessibilityElementAtIndex: are different - they must not be. Either provide" | ||
@" elements via one method or provide the same elements.\nDetails:\nElements via" | ||
@" accessibilityElements:%@\nElements via accessibilityElementAtIndex:\n" | ||
@"accessibilityElementCount:%@\nElements:%@", | ||
accessibilityElementsSet, | ||
@([nextInQueue accessibilityElementCount]), | ||
accessibilityElementsFromIndicesSet); | ||
} else { | ||
// Set accessibilityElements to whichever is non nil or leave it as is. | ||
axElements = axElementsFromIndices ? axElementsFromIndices : axElements; | ||
} | ||
if (![nextInQueue respondsToSelector:@selector(accessibilityElementsHidden)] || | ||
![nextInQueue accessibilityElementsHidden]) { | ||
for (id element in axElements) { | ||
if (![_visitedElements containsObject:element]) { | ||
[_queue addObject:element]; | ||
} | ||
} | ||
} | ||
|
||
// nextInQueue could be a UIView subclass, if so enqueue its subviews. | ||
NSArray *subViews; | ||
if ([nextInQueue isKindOfClass:[UITableViewCell class]] || | ||
[nextInQueue isKindOfClass:[UICollectionViewCell class]]) { | ||
subViews = [nextInQueue contentView].subviews; | ||
} else if ([nextInQueue respondsToSelector:@selector(subviews)]) { | ||
subViews = [nextInQueue subviews]; | ||
} | ||
if ([nextInQueue respondsToSelector:@selector(isHidden)] && | ||
![nextInQueue isHidden]) { | ||
for (id child in subViews) { | ||
if (![_visitedElements containsObject:child]) { | ||
[_queue addObject:child]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return nextInQueue; | ||
} | ||
|
||
#pragma mark - NSExtendedEnumerator | ||
|
||
- (NSArray *)allObjects { | ||
NSMutableArray *remainingObjects = [[NSMutableArray alloc] init]; | ||
id nextObject; | ||
while ((nextObject = [self nextObject])) { | ||
[remainingObjects addObject:nextObject]; | ||
} | ||
return remainingObjects; | ||
} | ||
|
||
#pragma mark - Private | ||
|
||
|
||
/** | ||
* @return An array of accessible children of the given @c element as reported by the selector | ||
* -[NSObject(UIAccessibility) accessibilityElements]. | ||
*/ | ||
- (NSArray *)gtx_accessibilityElementsOfElement:(id)element { | ||
if ([element respondsToSelector:@selector(accessibilityElements)]) { | ||
return [element accessibilityElements]; | ||
} | ||
return nil; | ||
} | ||
|
||
/** | ||
* @return An array of accessible children of the given @c element as reported by the selector | ||
* -[NSObject(UIAccessibility) accessibilityElementAtIndex:]. | ||
*/ | ||
- (NSArray *)gtx_accessibilityElementsFromIndicesOfElement:(id)element { | ||
NSMutableArray *axElementsFromIndices; | ||
if ([element respondsToSelector:@selector(accessibilityElementAtIndex:)] && | ||
[element respondsToSelector:@selector(accessibilityElementCount)]) { | ||
NSInteger childrenCount = [element accessibilityElementCount]; | ||
// This is a workaround to deal with UIKit classes that are reporting incorrect | ||
// accessibilityElementCount, see kAccessibilityChildrenUpperBound. | ||
if (childrenCount > 0 && childrenCount < kAccessibilityChildrenUpperBound) { | ||
axElementsFromIndices = [[NSMutableArray alloc] initWithCapacity:(NSUInteger)childrenCount]; | ||
for (NSInteger index = 0; index < childrenCount; index++) { | ||
[axElementsFromIndices addObject:[element accessibilityElementAtIndex:index]]; | ||
} | ||
} | ||
} | ||
return axElementsFromIndices; | ||
} | ||
|
||
/** | ||
* Elements are hidden from accessibility trees | ||
* | ||
* @return @c YES if the element is hidden from accessibility tree @c NO otherwise. | ||
*/ | ||
- (BOOL)gtx_isAccessibilityHiddenElement:(id)element { | ||
BOOL isHidden = NO; | ||
BOOL isAccessibilityHidden = NO; | ||
BOOL isHiddenDueToAccessibilityFrame = NO; | ||
BOOL isHiddenDueToFrame = NO; | ||
if ([element respondsToSelector:@selector(isHidden)]) { | ||
isHidden = [element isHidden]; | ||
} | ||
if ([element respondsToSelector:@selector(accessibilityElementsHidden)]) { | ||
isAccessibilityHidden = [element accessibilityElementsHidden]; | ||
} | ||
if ([element respondsToSelector:@selector(accessibilityFrame)]) { | ||
CGRect accessibilityFrame = [element accessibilityFrame]; | ||
isHiddenDueToAccessibilityFrame = (accessibilityFrame.size.width == 0 || | ||
accessibilityFrame.size.height == 0); | ||
} | ||
if ([element respondsToSelector:@selector(frame)]) { | ||
CGRect frame = [element frame]; | ||
isHiddenDueToFrame = frame.size.width == 0 || frame.size.height == 0; | ||
} | ||
return (isHidden || isAccessibilityHidden || | ||
(isHiddenDueToFrame && isHiddenDueToAccessibilityFrame)); | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// Copyright 2018 Google Inc. | ||
// | ||
// Licensed 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. | ||
// | ||
|
||
#import <UIKit/UIKit.h> | ||
|
||
#import "GTXChecking.h" | ||
#import "GTXCheckBlock.h" | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
|
||
/** | ||
Enum of all possible analytics events handleed by GTAxe. | ||
*/ | ||
typedef NS_ENUM(NSUInteger, GTXAnalyticsEvent) { | ||
/** | ||
Enum for GTAxe checks being invoked. | ||
*/ | ||
GTXAnalyticsEventChecksPerformed, | ||
|
||
/** | ||
Enum for GTAxe checks failure detection. | ||
*/ | ||
GTXAnalyticsEventChecksFailed, | ||
}; | ||
|
||
|
||
/** | ||
Typedef for Analytics handler. | ||
@param event The analytics event to be handled. | ||
*/ | ||
typedef void(^GTXAnalyticsHandlerBlock)(GTXAnalyticsEvent event); | ||
|
||
|
||
/** | ||
Class that handles all analytics in GTAxe. | ||
*/ | ||
@interface GTXAnalytics : NSObject | ||
|
||
/** | ||
Boolean property that specifies if analytics is enabled or not. | ||
*/ | ||
@property (class, nonatomic, assign) BOOL enabled; | ||
|
||
/** | ||
Current analytics handler, users can override this for custom handling of analytics events. | ||
*/ | ||
@property (class, nonatomic) GTXAnalyticsHandlerBlock handler; | ||
|
||
|
||
/** | ||
Feeds an analytics event to be handled. | ||
@param event The event to be handled. | ||
*/ | ||
+ (void)invokeAnalyticsEvent:(GTXAnalyticsEvent)event; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
Oops, something went wrong.