Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Direct app exec #38

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
8 changes: 8 additions & 0 deletions Frank.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
4C1DD76D12BADFE100E10B8C /* OrientationCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C1DD76912BADFE100E10B8C /* OrientationCommand.h */; };
4C1DD76E12BADFE100E10B8C /* AppCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1DD76A12BADFE100E10B8C /* AppCommand.m */; };
4C1DD76F12BADFE100E10B8C /* AppCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C1DD76B12BADFE100E10B8C /* AppCommand.h */; };
5390A25A1A65E5B600EB436B /* DirectAppExecCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 5390A2581A65E5B600EB436B /* DirectAppExecCommand.h */; };
5390A25B1A65E5B600EB436B /* DirectAppExecCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 5390A2591A65E5B600EB436B /* DirectAppExecCommand.m */; };
65DBDD7416A89CCA007D3D43 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = AB7947C115C4418700052B74 /* GCDAsyncSocket.m */; };
65DBDD8D16A89CCA007D3D43 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
65DBDDA816A89CDC007D3D43 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = ABA9E4BB15C81E7900112290 /* DDAbstractDatabaseLogger.m */; };
Expand Down Expand Up @@ -344,6 +346,8 @@
4C1DD76912BADFE100E10B8C /* OrientationCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrientationCommand.h; sourceTree = "<group>"; };
4C1DD76A12BADFE100E10B8C /* AppCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppCommand.m; sourceTree = "<group>"; };
4C1DD76B12BADFE100E10B8C /* AppCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppCommand.h; sourceTree = "<group>"; };
5390A2581A65E5B600EB436B /* DirectAppExecCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectAppExecCommand.h; sourceTree = "<group>"; };
5390A2591A65E5B600EB436B /* DirectAppExecCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectAppExecCommand.m; sourceTree = "<group>"; };
65DBDD9216A89CCA007D3D43 /* libCocoaAsyncSocket.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCocoaAsyncSocket.a; sourceTree = BUILT_PRODUCTS_DIR; };
65DBDDB516A89CDC007D3D43 /* libCocoaLumberjack.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCocoaLumberjack.a; sourceTree = BUILT_PRODUCTS_DIR; };
65DBDDDA16A89E5B007D3D43 /* libCocoaAsyncSocketMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCocoaAsyncSocketMac.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -708,6 +712,8 @@
4C1DD76A12BADFE100E10B8C /* AppCommand.m */,
303CFCE216C80B830004BD05 /* DeviceCommand.h */,
303CFCE316C80B830004BD05 /* DeviceCommand.m */,
5390A2581A65E5B600EB436B /* DirectAppExecCommand.h */,
5390A2591A65E5B600EB436B /* DirectAppExecCommand.m */,
D6FA01B714283C4F00576AF0 /* EnginesCommand.h */,
D6FA01B714283C4F00576AEE /* EnginesCommand.m */,
A91F3AA415F6E456003F434F /* ExitCommand.h */,
Expand Down Expand Up @@ -899,6 +905,7 @@
D6FA01B714283C4F00576AF1 /* EnginesCommand.h in Headers */,
A91F3AA615F6E456003F434F /* ExitCommand.h in Headers */,
C9605E641606BF2900170F88 /* IOSKeyboardCommand.h in Headers */,
5390A25A1A65E5B600EB436B /* DirectAppExecCommand.h in Headers */,
C9605E6A1606BFAE00170F88 /* UIImage+Frank.h in Headers */,
C18A5EF0160D4AB400DC25F6 /* ImageCaptureRoute.h in Headers */,
C18A5EF5160D4AD300DC25F6 /* UIView+ImageCapture.h in Headers */,
Expand Down Expand Up @@ -1270,6 +1277,7 @@
D6BD521F146C34BF001770B1 /* SelectorEngineRegistry.m in Sources */,
0071264714F8956700E738ED /* ViewJSONSerializer.m in Sources */,
D6FA01B714283C4F00576AE1 /* FranklyProtocolHelper.m in Sources */,
5390A25B1A65E5B600EB436B /* DirectAppExecCommand.m in Sources */,
D6A1D28015A8D05E00EC056C /* UIView+Frank.m in Sources */,
D6FA01B714283C4F00576AEF /* EnginesCommand.m in Sources */,
A91F3AA715F6E456003F434F /* ExitCommand.m in Sources */,
Expand Down
12 changes: 10 additions & 2 deletions gem/lib/frank-cucumber/core_frank_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@
end

Then /^I should see an alert view titled "([^\"]*)"$/ do |expected_mark|
values = frankly_map( 'alertView', 'title')
if frankly_os_version.to_f >= 7.0
values = frankly_map( "view:'_UIModalItemRepresentationView' label", 'text')
else
values = frankly_map( 'alertView', 'title')
end
values.should include(expected_mark)
end

Expand All @@ -76,7 +80,11 @@
end

Then /^I should not see an alert view$/ do
check_element_does_not_exist( 'alertView' )
if frankly_os_version.to_f >= 7.0
check_element_does_not_exist( '_UIModalItemRepresentationView' )
else
check_element_does_not_exist( 'alertView' )
end
end

Then /^I should see an element of class "([^\"]*)" with name "([^\"]*)" with the following labels: "([^\"]*)"$/ do |className, classLabel, listOfLabels|
Expand Down
16 changes: 16 additions & 0 deletions src/DirectAppExecCommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// DirectAppExecCommand.h
// Frank
//
// Created by Martin Taylor on 4-Apr-14.
// Copyright (c) 2014 Texas Instruments, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "FrankCommandRoute.h"

@interface DirectAppExecCommand : NSObject<FrankCommand>{

}

@end
54 changes: 54 additions & 0 deletions src/DirectAppExecCommand.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// DirectAppExecCommand.m
// Frank
//
// Created by Martin Taylor on 4-Apr-14.
// Copyright (c) 2014 Texas Instruments, Inc. All rights reserved.
//
// NOTE: This code was copied directly from AppCommand.m. The only difference in this command is that the
// RequestRouter.m executes it on the HTTP thread rather than on the main UI thread.
//
#import <Foundation/Foundation.h>
#import "DirectAppExecCommand.h"

#import "Operation.h"
#import "ViewJSONSerializer.h"
#import "FranklyProtocolHelper.h"
#import "JSON.h"

@implementation DirectAppExecCommand

- (NSString *)handleCommandWithRequestBody:(NSString *)requestBody {

NSDictionary *requestCommand = FROM_JSON(requestBody);
NSDictionary *operationDict = [requestCommand objectForKey:@"operation"];
Operation *operation = [[[Operation alloc] initFromJsonRepresentation:operationDict] autorelease];

#if TARGET_OS_IPHONE
id <UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
#else
id <NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
#endif

if( ![operation appliesToObject:appDelegate] )
{
return [FranklyProtocolHelper generateErrorResponseWithReason:@"operation doesn't apply" andDetails:@"operation does not appear to be implemented in app delegate"];
}

id result;

@try {
result = [operation applyToObject:appDelegate];
}
@catch (NSException *e) {
NSLog( @"Exception while applying operation to app delegate:\n%@", e );
return [FranklyProtocolHelper generateErrorResponseWithReason:@"exception while executing operation" andDetails:[e reason]];
}

NSMutableArray *results = [NSMutableArray new];
[results addObject:[ViewJSONSerializer jsonify:result]];

return [FranklyProtocolHelper generateSuccessResponseWithResults: results];
}

@end
2 changes: 2 additions & 0 deletions src/FrankServer.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import "DeviceCommand.h"
#import "ExitCommand.h"
#import "AppCommand.h"
#import "DirectAppExecCommand.h"
#import "AccessibilityCheckCommand.h"
#import "EnginesCommand.h"
#import "VersionCommand.h"
Expand Down Expand Up @@ -64,6 +65,7 @@ - (id) initWithStaticFrankBundleNamed:(NSString *)bundleName
[frankCommandRoute registerCommand:[[[DeviceCommand alloc] init] autorelease] withName:@"device"];
[frankCommandRoute registerCommand:[[[AccessibilityCheckCommand alloc] init]autorelease] withName:@"accessibility_check"];
[frankCommandRoute registerCommand:[[[AppCommand alloc] init]autorelease] withName:@"app_exec"];
[frankCommandRoute registerCommand:[[[DirectAppExecCommand alloc] init]autorelease] withName:@"direct_app_exec"];
[frankCommandRoute registerCommand:[[[EnginesCommand alloc] init]autorelease] withName:@"engines"];
[frankCommandRoute registerCommand:[[[VersionCommand alloc] initWithVersion:[NSString stringWithFormat:@"%s",xstr(FRANK_PRODUCT_VERSION)]]autorelease] withName:@"version"];
[frankCommandRoute registerCommand:[[[ExitCommand alloc] init] autorelease] withName:@"exit"];
Expand Down
2 changes: 1 addition & 1 deletion src/OrientationCommand.m
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ - (NSString *)getOrientationDescriptionViaDevice{
- (NSString *)handleGet{
NSDictionary *orientationDescription = [self getOrientationRepresentationViaDevice];
if( !orientationDescription )
orientationDescription = [self getOrientationRepresentationViaDevice];
orientationDescription = [self getOrientationRepresentationViaStatusBar];

return TO_JSON(orientationDescription);
}
Expand Down
12 changes: 10 additions & 2 deletions src/RequestRouter.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,17 @@ - (void) registerRoute: (id<Route>) route {
NSArray *pathComponents = [self pathComponentsWithPath:path];
__block NSObject<HTTPResponse> *response = nil;
for (id<Route> route in _routes) {
dispatch_sync(dispatch_get_main_queue(), ^{
/*
* If the first pathComponent is "direct_app_exec" then the execution should happen in THIS thread,
* not in the main UI thread as is true for all other commands.
*/
if ([path hasSuffix:@"direct_app_exec"]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really happy with this approach. Feels pretty hacky to hard-code intimate knowledge about that specific command in the path routing code.

Is there a way we can instead have the DirectAppExecCommand run its command in its own thread? That seems like it'd achieve the same goals.

response = [[route handleRequestForPath:pathComponents withConnection:connection] retain];
});
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
response = [[route handleRequestForPath:pathComponents withConnection:connection] retain];
});
}
[response autorelease];

if( nil != response )
Expand Down