Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

288 lines (212 sloc) 8.095 kB
//
// UIView+PublicAutomation.m
// Frank
//
// Created by Pete Hodgson on 10/15/11.
// Copyright (c) 2011 ThoughtWorks. All rights reserved.
//
#import <PublicAutomation/UIAutomationBridge.h>
#import "LoadableCategory.h"
MAKE_CATEGORIES_LOADABLE(UIView_PublicAutomation)
NSString * formatCGPointVal(NSValue *val) {
CGPoint p = [val CGPointValue];
return [NSString stringWithFormat:@"[%.2f, %.2f]", p.x, p.y];
}
@implementation UIView(PublicAutomation)
#pragma mark - Utils
- (CGPoint)FEX_centerPoint {
return CGPointMake(0.5 * self.bounds.size.width, 0.5 * self.bounds.size.height);
}
- (CGPoint)FEX_pointFromX:(NSNumber*)x andY:(NSNumber*)y {
if (CGFLOAT_IS_DOUBLE) {
return CGPointMake([x doubleValue], [y doubleValue]);
}
else {
return CGPointMake([x floatValue], [y floatValue]);
}
}
#pragma mark - Test touch
- (BOOL)FEX_isPointInWindow:(CGPoint)point {
CGPoint pointInWindowCoords = [self.window convertPoint:point fromView:self];
return (CGRectContainsPoint(self.window.bounds, pointInWindowCoords));
}
- (BOOL)FEX_isPointInDirectViewHierarchy:(CGPoint)point touchRecipient:(UIView**)touchRecipient {
CGPoint pointInWindowCoords = [self.window convertPoint:point fromView:self];
UIView* touchedView = [self.window hitTest:pointInWindowCoords withEvent:nil];
if (touchRecipient) {
*touchRecipient = touchedView;
}
if ([touchedView isDescendantOfView:self]) {
return YES;
}
else if ([self isDescendantOfView:touchedView]) {
/* the following code implements the same functionality as `hitTest:withEvent:`
but it doesn't ignore views with disabled user interactions */
BOOL canContinue;
do {
canContinue = NO;
CGPoint testedPoint = [self.window convertPoint:pointInWindowCoords toView:touchedView];
NSArray* subviews = [[touchedView.subviews copy] autorelease];
for (NSUInteger i = subviews.count; i > 0; i--) {
UIView* subview = [subviews objectAtIndex:(i - 1)];
if (subview.alpha < 0.01 || subview.hidden) {
continue;
}
CGPoint testedPointInSubviewCoords = [subview convertPoint:testedPoint fromView:touchedView];
if ([subview pointInside:testedPointInSubviewCoords withEvent:nil]) {
if (subview == self) {
return YES;
}
else {
touchedView = subview;
canContinue = YES;
break;
}
}
}
} while (canContinue);
}
return NO;
}
- (BOOL)FEX_canTouchPoint:(CGPoint)point force:(BOOL)force raiseExceptions:(BOOL)raiseExceptions {
NSString* errorTitle = @"Touch failed";
if ([[UIApplication sharedApplication] isIgnoringInteractionEvents]) {
NSString* errorMessage = @"Application is ignoring interaction events";
NSLog(@"%@ - %@", errorTitle, errorMessage);
if (raiseExceptions) {
[NSException raise:errorTitle format:@"%@", errorMessage];
}
return NO;
}
if (![self FEX_isPointInWindow:point]) {
NSString* errorMessage = @"Touch point is outside window bounds";
NSLog(@"%@ - %@", errorTitle, errorMessage);
if (raiseExceptions) {
[NSException raise:errorTitle format:@"%@", errorMessage];
}
return NO;
}
UIView* touchedView = nil;
if (!force && ![self FEX_isPointInDirectViewHierarchy:point touchRecipient:&touchedView]) {
NSString* touchedViewDescriptor = nil;
if (touchedView != nil) {
touchedViewDescriptor = [NSString stringWithFormat:@"%p#%@", touchedView, NSStringFromClass([touchedView class])];
}
NSString* errorMessage = [NSString stringWithFormat:
@"View not touched because it would not be the recipient of the touch event - consider FEX_forcedTouch instead (touch recipient: %@)",
touchedViewDescriptor];
NSLog(@"%@ - %@", errorTitle, errorMessage);
if (raiseExceptions) {
[NSException raise:errorTitle format:@"%@", errorMessage];
}
return NO;
}
return YES;
}
- (BOOL)FEX_canTouch {
return [self FEX_canTouchPoint:[self FEX_centerPoint] force:NO raiseExceptions:NO];
}
- (BOOL)FEX_canTouchPointX:(NSNumber*)x y:(NSNumber*)y {
CGPoint point = [self FEX_pointFromX:x andY:y];
return [self FEX_canTouchPoint:point force:NO raiseExceptions:NO];
}
#pragma mark - Touch
- (BOOL)FEX_touchPoint:(CGPoint)point {
if (![self FEX_canTouchPoint:point force:NO raiseExceptions:YES]) {
return NO;
}
[UIAutomationBridge tapView:self atPoint:point];
return YES;
}
- (BOOL)touch {
return [self FEX_touchPoint:[self FEX_centerPoint]];
}
- (BOOL)FEX_forcedTouch {
CGPoint point = [self FEX_centerPoint];
if (![self FEX_canTouchPoint:point force:YES raiseExceptions:YES]) {
return NO;
}
[UIAutomationBridge tapView:self atPoint:point];
return YES;
}
- (BOOL)touchx:(NSNumber *)x y:(NSNumber *)y {
CGPoint point = [self FEX_pointFromX:x andY:y];
return [self FEX_touchPoint:point];
}
- (BOOL)FEX_forcedTouchx:(NSNumber *)x y:(NSNumber *)y {
CGPoint point = [self FEX_pointFromX:x andY:y];
if (![self FEX_canTouchPoint:point force:YES raiseExceptions:NO]) {
return NO;
}
[UIAutomationBridge tapView:self atPoint:point];
return YES;
}
//Modled on UIAutomation
#pragma mark - Touch Gestures
//Double Tap
- (BOOL)doubleTapPoint:(CGPoint)point {
if (![self FEX_canTouchPoint:point force:NO raiseExceptions:YES]) {
return NO;
}
[UIAutomationBridge doubleTapView:self atPoint:point];
return YES;
}
- (BOOL)doubleTap {
return [self doubleTapPoint:[self FEX_centerPoint]];
}
- (BOOL)doubleTapx:(NSNumber *)x y:(NSNumber *)y {
CGPoint point = [self FEX_pointFromX:x andY:y];
return [self doubleTapPoint:point];
}
////Tap With Options
//- (BOOL)tapWithOptions:(NSDictionary *)options pointIfInsideWindow:(CGPoint)point {
//
//}
//
//- (BOOL)tapWithOptions:(NSDictionary *)options {
//
//}
//
//- (BOOL)tapWithOptions:(NSDictionary *)options x:(NSNumber *)x y:(NSNumber *)y {
//
//}
//Touch and hold
- (BOOL)touchAndHold:(NSTimeInterval)duration point:(CGPoint)point {
if (![self FEX_canTouchPoint:point force:NO raiseExceptions:YES]) {
return NO;
}
[UIAutomationBridge longTapView:self atPoint:point forDuration:duration];
return YES;
}
- (BOOL)touchAndHold:(CGFloat)duration {
return [self touchAndHold:duration point:[self FEX_centerPoint]];
}
- (BOOL)touchAndHold:(CGFloat)duration x:(NSNumber *)x y:(NSNumber *)y {
CGPoint point = [self FEX_pointFromX:x andY:y];
return [self touchAndHold:duration point:point];
}
////Two finger tap
//- (BOOL)twofingerTapPointIfInsideWindow:(CGPoint)point {
//
//}
//
//- (BOOL)twofingerTap {
//
//}
//
//- (BOOL)twofingerTapx:(NSNumber *)x y:(NSNumber *)y {
//
//}
#pragma mark - Swipe Gestures
//TODO
//-(void)swipeInDirection:(NSString *)dir by:(int)pixels {
- (NSString *)swipeInDirection:(NSString *)strDir {
PADirection dir = [UIAutomationBridge parseDirection:strDir];
NSArray *swipeExtremes = [UIAutomationBridge swipeView:self inDirection:dir];
return [NSString stringWithFormat:@"%@ => %@", formatCGPointVal([swipeExtremes objectAtIndex:0]), formatCGPointVal([swipeExtremes objectAtIndex:1])];
}
- (BOOL)FEX_dragWithInitialDelayToX:(CGFloat)x y:(CGFloat)y {
[UIAutomationBridge dragViewWithInitialDelay:self toPoint:CGPointMake(x,y)];
return YES;
}
@end
Jump to Line
Something went wrong with that request. Please try again.