summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2016-07-29 15:34:00 -0400
committerJoel Fischer <joeljfischer@gmail.com>2016-07-29 15:34:00 -0400
commit1eb39d3a2120fada750dac046da601d5da31a20c (patch)
tree5c494ee4f83764c869d3fca7cda8322e19256e9b
parente8e5a5b684f23d2645b565c11ab9d47c3b0f3735 (diff)
parentca91918b55c22d084857205151593ba54bcca208 (diff)
downloadsdl_ios-feature/external_security_support.tar.gz
Merge branch 'develop' into feature/external_security_supportfeature/external_security_support
# Conflicts: # SmartDeviceLink/SDLProxy.m # SmartDeviceLink/SDLStreamingMediaManager.h # SmartDeviceLink/SDLStreamingMediaManager.m
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj88
-rw-r--r--SmartDeviceLink/CGPoint_Util.h39
-rw-r--r--SmartDeviceLink/CGPoint_Util.m20
-rw-r--r--SmartDeviceLink/SDLPinchGesture.h62
-rw-r--r--SmartDeviceLink/SDLPinchGesture.m79
-rw-r--r--SmartDeviceLink/SDLProxy.m14
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.h28
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.m135
-rw-r--r--SmartDeviceLink/SDLTouch.h65
-rw-r--r--SmartDeviceLink/SDLTouch.m64
-rw-r--r--SmartDeviceLink/SDLTouchManager.h63
-rw-r--r--SmartDeviceLink/SDLTouchManager.m284
-rw-r--r--SmartDeviceLink/SDLTouchManagerDelegate.h104
-rw-r--r--SmartDeviceLink/SmartDeviceLink.h2
-rw-r--r--SmartDeviceLink/dispatch_timer.h18
-rw-r--r--SmartDeviceLink/dispatch_timer.m38
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/CGPointUtilSpec.m72
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/DispatchTimerSpec.m47
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLPinchGestureSpec.m182
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m609
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchSpec.m107
21 files changed, 2100 insertions, 20 deletions
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index d13a74534..fc67b26e8 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -787,6 +787,26 @@
5DEE55C51B864AB3004F0D0F /* OHHTTPStubs.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5DEE55C41B864AB3004F0D0F /* OHHTTPStubs.framework.dSYM */; };
5DEE55C61B8666A8004F0D0F /* OHHTTPStubs.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5DEE55C11B864A7D004F0D0F /* OHHTTPStubs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5DF2BB9D1B94E38A00CE5994 /* SDLURLSessionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF2BB9C1B94E38A00CE5994 /* SDLURLSessionSpec.m */; };
+ DA4353DF1D271FD10099B8C4 /* CGPointUtilSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4353DE1D271FD10099B8C4 /* CGPointUtilSpec.m */; };
+ DA4353E31D2720A30099B8C4 /* SDLPinchGestureSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4353E21D2720A30099B8C4 /* SDLPinchGestureSpec.m */; };
+ DA4353E91D2721680099B8C4 /* DispatchTimerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4353E61D2721680099B8C4 /* DispatchTimerSpec.m */; };
+ DA4353EA1D2721680099B8C4 /* SDLTouchManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4353E71D2721680099B8C4 /* SDLTouchManagerSpec.m */; };
+ DA4353EB1D2721680099B8C4 /* SDLTouchSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4353E81D2721680099B8C4 /* SDLTouchSpec.m */; };
+ DAC572571D1067270004288B /* SDLTouchManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC572551D1067270004288B /* SDLTouchManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAC572581D1067270004288B /* SDLTouchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC572561D1067270004288B /* SDLTouchManager.m */; };
+ DAC5725B1D10B81E0004288B /* SDLTouch.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC572591D10B81E0004288B /* SDLTouch.m */; };
+ DAC5725C1D10B81E0004288B /* SDLTouch.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC5725A1D10B81E0004288B /* SDLTouch.h */; };
+ DAC572621D10C5020004288B /* SDLPinchGesture.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC572601D10C5020004288B /* SDLPinchGesture.m */; };
+ DAC572631D10C5020004288B /* SDLPinchGesture.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC572611D10C5020004288B /* SDLPinchGesture.h */; };
+ DAC572661D10C5640004288B /* CGPoint_Util.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC572641D10C5640004288B /* CGPoint_Util.m */; };
+ DAC572671D10C5640004288B /* CGPoint_Util.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC572651D10C5640004288B /* CGPoint_Util.h */; };
+ DAC5726A1D10D5FC0004288B /* dispatch_timer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC572681D10D5FC0004288B /* dispatch_timer.m */; };
+ DAC5726B1D10D5FC0004288B /* dispatch_timer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC572691D10D5FC0004288B /* dispatch_timer.h */; };
+ DAC5726C1D11B4840004288B /* SDLTouchManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC5725F1D10BD690004288B /* SDLTouchManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DACBA1DC1D22D46D002356F8 /* SDLOnTouchEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D61FB331A84238B00846EE7 /* SDLOnTouchEvent.m */; };
+ DACBA1DE1D22D642002356F8 /* SDLTouchType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D61FBEB1A84238C00846EE7 /* SDLTouchType.m */; };
+ DACBA1DF1D22D6CE002356F8 /* SDLTouchEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D61FBE71A84238C00846EE7 /* SDLTouchEvent.m */; };
+ DACBA1E01D22E856002356F8 /* SDLTouchCoord.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D61FBE51A84238C00846EE7 /* SDLTouchCoord.m */; };
E9C32B861AB20B4300F283AF /* NSThread+ThreadIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = E9C32B841AB20B4300F283AF /* NSThread+ThreadIndex.h */; };
E9C32B871AB20B4300F283AF /* NSThread+ThreadIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = E9C32B851AB20B4300F283AF /* NSThread+ThreadIndex.m */; };
E9C32B911AB20BA200F283AF /* SDLIAPSession.h in Headers */ = {isa = PBXBuildFile; fileRef = E9C32B891AB20BA200F283AF /* SDLIAPSession.h */; };
@@ -1662,6 +1682,22 @@
5DEE55C11B864A7D004F0D0F /* OHHTTPStubs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OHHTTPStubs.framework; path = Carthage/Build/iOS/OHHTTPStubs.framework; sourceTree = "<group>"; };
5DEE55C41B864AB3004F0D0F /* OHHTTPStubs.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = OHHTTPStubs.framework.dSYM; path = Carthage/Build/iOS/OHHTTPStubs.framework.dSYM; sourceTree = "<group>"; };
5DF2BB9C1B94E38A00CE5994 /* SDLURLSessionSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLURLSessionSpec.m; path = "UtilitiesSpecs/HTTP Connection/SDLURLSessionSpec.m"; sourceTree = "<group>"; };
+ DA4353DE1D271FD10099B8C4 /* CGPointUtilSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CGPointUtilSpec.m; path = UtilitiesSpecs/Touches/CGPointUtilSpec.m; sourceTree = "<group>"; };
+ DA4353E21D2720A30099B8C4 /* SDLPinchGestureSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLPinchGestureSpec.m; path = UtilitiesSpecs/Touches/SDLPinchGestureSpec.m; sourceTree = "<group>"; };
+ DA4353E61D2721680099B8C4 /* DispatchTimerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DispatchTimerSpec.m; path = UtilitiesSpecs/Touches/DispatchTimerSpec.m; sourceTree = "<group>"; };
+ DA4353E71D2721680099B8C4 /* SDLTouchManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLTouchManagerSpec.m; path = UtilitiesSpecs/Touches/SDLTouchManagerSpec.m; sourceTree = "<group>"; };
+ DA4353E81D2721680099B8C4 /* SDLTouchSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLTouchSpec.m; path = UtilitiesSpecs/Touches/SDLTouchSpec.m; sourceTree = "<group>"; };
+ DAC572551D1067270004288B /* SDLTouchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLTouchManager.h; sourceTree = "<group>"; };
+ DAC572561D1067270004288B /* SDLTouchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLTouchManager.m; sourceTree = "<group>"; };
+ DAC572591D10B81E0004288B /* SDLTouch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLTouch.m; sourceTree = "<group>"; };
+ DAC5725A1D10B81E0004288B /* SDLTouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLTouch.h; sourceTree = "<group>"; };
+ DAC5725F1D10BD690004288B /* SDLTouchManagerDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLTouchManagerDelegate.h; sourceTree = "<group>"; };
+ DAC572601D10C5020004288B /* SDLPinchGesture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLPinchGesture.m; sourceTree = "<group>"; };
+ DAC572611D10C5020004288B /* SDLPinchGesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLPinchGesture.h; sourceTree = "<group>"; };
+ DAC572641D10C5640004288B /* CGPoint_Util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CGPoint_Util.m; sourceTree = "<group>"; };
+ DAC572651D10C5640004288B /* CGPoint_Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CGPoint_Util.h; sourceTree = "<group>"; };
+ DAC572681D10D5FC0004288B /* dispatch_timer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = dispatch_timer.m; sourceTree = "<group>"; };
+ DAC572691D10D5FC0004288B /* dispatch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dispatch_timer.h; sourceTree = "<group>"; };
E9C32B841AB20B4300F283AF /* NSThread+ThreadIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSThread+ThreadIndex.h"; sourceTree = "<group>"; };
E9C32B851AB20B4300F283AF /* NSThread+ThreadIndex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSThread+ThreadIndex.m"; sourceTree = "<group>"; };
E9C32B891AB20BA200F283AF /* SDLIAPSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLIAPSession.h; sourceTree = "<group>"; };
@@ -2669,6 +2705,7 @@
5D5934F61A85189500687FB9 /* Utilities */ = {
isa = PBXGroup;
children = (
+ DAC5724C1D0FE3B60004288B /* Touches */,
5DCC199D1B8221D2004FFAD9 /* HTTP Connection */,
E9C32B831AB20B2900F283AF /* @categories */,
5D5934F71A8519A700687FB9 /* JSON */,
@@ -2919,6 +2956,7 @@
5DB92D201AC47AC400C15BB0 /* UtilitiesSpecs */ = {
isa = PBXGroup;
children = (
+ DA1166D71D14601C00438CEA /* Touches */,
5DEE55BE1B8509A5004F0D0F /* HTTP Connection */,
5DB92D2B1AC4A32A00C15BB0 /* Prioritized Objects */,
5DB92D231AC47B2C00C15BB0 /* SDLHexUtilitySpec.m */,
@@ -2965,6 +3003,36 @@
name = "HTTP Connection";
sourceTree = "<group>";
};
+ DA1166D71D14601C00438CEA /* Touches */ = {
+ isa = PBXGroup;
+ children = (
+ DA4353E61D2721680099B8C4 /* DispatchTimerSpec.m */,
+ DA4353E71D2721680099B8C4 /* SDLTouchManagerSpec.m */,
+ DA4353E81D2721680099B8C4 /* SDLTouchSpec.m */,
+ DA4353DE1D271FD10099B8C4 /* CGPointUtilSpec.m */,
+ DA4353E21D2720A30099B8C4 /* SDLPinchGestureSpec.m */,
+ );
+ name = Touches;
+ sourceTree = "<group>";
+ };
+ DAC5724C1D0FE3B60004288B /* Touches */ = {
+ isa = PBXGroup;
+ children = (
+ DAC572551D1067270004288B /* SDLTouchManager.h */,
+ DAC572561D1067270004288B /* SDLTouchManager.m */,
+ DAC5725F1D10BD690004288B /* SDLTouchManagerDelegate.h */,
+ DAC5725A1D10B81E0004288B /* SDLTouch.h */,
+ DAC572591D10B81E0004288B /* SDLTouch.m */,
+ DAC572611D10C5020004288B /* SDLPinchGesture.h */,
+ DAC572601D10C5020004288B /* SDLPinchGesture.m */,
+ DAC572651D10C5640004288B /* CGPoint_Util.h */,
+ DAC572641D10C5640004288B /* CGPoint_Util.m */,
+ DAC572691D10D5FC0004288B /* dispatch_timer.h */,
+ DAC572681D10D5FC0004288B /* dispatch_timer.m */,
+ );
+ name = Touches;
+ sourceTree = "<group>";
+ };
E9C32B831AB20B2900F283AF /* @categories */ = {
isa = PBXGroup;
children = (
@@ -2997,6 +3065,7 @@
5DB92D321AC9C8BA00C15BB0 /* SDLRPCStruct.h in Headers */,
5D61FD151A84238C00846EE7 /* SDLOnLockScreenStatus.h in Headers */,
5D61FD291A84238C00846EE7 /* SDLPerformInteraction.h in Headers */,
+ DAC572571D1067270004288B /* SDLTouchManager.h in Headers */,
5D61FD521A84238C00846EE7 /* SDLProxyFactory.h in Headers */,
5D61FCDA1A84238C00846EE7 /* SDLJingle.h in Headers */,
5D61FE0D1A84238C00846EE7 /* SDLVRCapabilities.h in Headers */,
@@ -3047,6 +3116,7 @@
5D61FD091A84238C00846EE7 /* SDLOnDriverDistraction.h in Headers */,
E9C32B9E1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.h in Headers */,
5D61FC4B1A84238C00846EE7 /* SDLBeltStatus.h in Headers */,
+ DAC5726B1D10D5FC0004288B /* dispatch_timer.h in Headers */,
5D61FC351A84238C00846EE7 /* SDLAirbagStatus.h in Headers */,
5D61FC8A1A84238C00846EE7 /* SDLDiagnosticMessageResponse.h in Headers */,
5D61FC2D1A84238C00846EE7 /* SDLAddCommand.h in Headers */,
@@ -3120,6 +3190,7 @@
5D61FC981A84238C00846EE7 /* SDLECallInfo.h in Headers */,
5D61FD7B1A84238C00846EE7 /* SDLScrollableMessage.h in Headers */,
5D61FD3D1A84238C00846EE7 /* SDLPrimaryAudioSource.h in Headers */,
+ DAC5725C1D10B81E0004288B /* SDLTouch.h in Headers */,
5D61FCCD1A84238C00846EE7 /* SDLImage.h in Headers */,
5D61FD481A84238C00846EE7 /* SDLProtocolMessage.h in Headers */,
5D61FC8C1A84238C00846EE7 /* SDLDIDResult.h in Headers */,
@@ -3169,6 +3240,7 @@
5D61FC611A84238C00846EE7 /* SDLChoice.h in Headers */,
5D61FC7C1A84238C00846EE7 /* SDLDeleteInteractionChoiceSetResponse.h in Headers */,
5D61FDB91A84238C00846EE7 /* SDLSyncPDataResponse.h in Headers */,
+ DAC572631D10C5020004288B /* SDLPinchGesture.h in Headers */,
5D61FC311A84238C00846EE7 /* SDLAddSubMenu.h in Headers */,
5D61FD171A84238C00846EE7 /* SDLOnPermissionsChange.h in Headers */,
5D61FDD51A84238C00846EE7 /* SDLTouchEventCapabilities.h in Headers */,
@@ -3236,6 +3308,7 @@
5D8B174F1AC9D266006A6E1C /* SDLDialNumber.h in Headers */,
5D61FCAD1A84238C00846EE7 /* SDLFunctionID.h in Headers */,
5D61FDF51A84238C00846EE7 /* SDLV1ProtocolHeader.h in Headers */,
+ DAC572671D10C5640004288B /* CGPoint_Util.h in Headers */,
5D61FDF91A84238C00846EE7 /* SDLV2ProtocolHeader.h in Headers */,
5D61FD4A1A84238C00846EE7 /* SDLProtocolMessageAssembler.h in Headers */,
5D61FD4C1A84238C00846EE7 /* SDLProtocolMessageDisassembler.h in Headers */,
@@ -3244,6 +3317,7 @@
5D61FDFB1A84238C00846EE7 /* SDLV2ProtocolMessage.h in Headers */,
5D61FCFC1A84238C00846EE7 /* SDLNames.h in Headers */,
5D61FCFD1A84238C00846EE7 /* SDLObjectWithPriority.h in Headers */,
+ DAC5726C1D11B4840004288B /* SDLTouchManagerDelegate.h in Headers */,
5D61FD3F1A84238C00846EE7 /* SDLPrioritizedObjectCollection.h in Headers */,
5D61FCBF1A84238C00846EE7 /* SDLHexUtility.h in Headers */,
5D61FCA21A84238C00846EE7 /* SDLEncoder.h in Headers */,
@@ -3493,6 +3567,7 @@
5D61FDB21A84238C00846EE7 /* SDLSubscribeVehicleData.m in Sources */,
5D61FC991A84238C00846EE7 /* SDLECallInfo.m in Sources */,
5D61FD601A84238C00846EE7 /* SDLRegisterAppInterfaceResponse.m in Sources */,
+ DAC572621D10C5020004288B /* SDLPinchGesture.m in Sources */,
5D61FCF51A84238C00846EE7 /* SDLMaintenanceModeStatus.m in Sources */,
5D61FCD81A84238C00846EE7 /* SDLInteractionMode.m in Sources */,
5D61FCB01A84238C00846EE7 /* SDLGenericResponse.m in Sources */,
@@ -3512,6 +3587,7 @@
5D61FDA41A84238C00846EE7 /* SDLSoftButtonType.m in Sources */,
5D61FC521A84238C00846EE7 /* SDLButtonCapabilities.m in Sources */,
5D61FC791A84238C00846EE7 /* SDLDeleteFileResponse.m in Sources */,
+ DAC572581D1067270004288B /* SDLTouchManager.m in Sources */,
5D61FC641A84238C00846EE7 /* SDLClusterModeStatus.m in Sources */,
5D61FCF91A84238C00846EE7 /* SDLMenuParams.m in Sources */,
5D61FD7C1A84238C00846EE7 /* SDLScrollableMessage.m in Sources */,
@@ -3556,6 +3632,7 @@
5D61FC3A1A84238C00846EE7 /* SDLAlertManeuver.m in Sources */,
5D61FC5E1A84238C00846EE7 /* SDLChangeRegistrationResponse.m in Sources */,
5D61FC7D1A84238C00846EE7 /* SDLDeleteInteractionChoiceSetResponse.m in Sources */,
+ DAC572661D10C5640004288B /* CGPoint_Util.m in Sources */,
E9C32B9D1AB20C5900F283AF /* EAAccessory+SDLProtocols.m in Sources */,
5D61FCC61A84238C00846EE7 /* SDLHMIZoneCapabilities.m in Sources */,
5D61FD161A84238C00846EE7 /* SDLOnLockScreenStatus.m in Sources */,
@@ -3616,6 +3693,7 @@
5D61FD5C1A84238C00846EE7 /* SDLReadDIDResponse.m in Sources */,
5D61FD321A84238C00846EE7 /* SDLPolicyDataParser.m in Sources */,
5D61FC621A84238C00846EE7 /* SDLChoice.m in Sources */,
+ DAC5725B1D10B81E0004288B /* SDLTouch.m in Sources */,
5D61FCEB1A84238C00846EE7 /* SDLLayoutMode.m in Sources */,
5D61FC2E1A84238C00846EE7 /* SDLAddCommand.m in Sources */,
5D61FE021A84238C00846EE7 /* SDLVehicleDataNotificationStatus.m in Sources */,
@@ -3651,6 +3729,7 @@
5D61FE0E1A84238C00846EE7 /* SDLVRCapabilities.m in Sources */,
5D61FDC21A84238C00846EE7 /* SDLSystemRequestResponse.m in Sources */,
5D61FD001A84238C00846EE7 /* SDLOnAppInterfaceUnregistered.m in Sources */,
+ DAC5726A1D10D5FC0004288B /* dispatch_timer.m in Sources */,
5D61FC6C1A84238C00846EE7 /* SDLCreateInteractionChoiceSet.m in Sources */,
5D61FD081A84238C00846EE7 /* SDLOnCommand.m in Sources */,
5D53C46E1B7A99B9003526EA /* SDLStreamingMediaManager.m in Sources */,
@@ -3729,6 +3808,7 @@
162E83121A9BDE8B00906325 /* SDLOnButtonPressSpec.m in Sources */,
162E838D1A9BDE8B00906325 /* SDLStartTimeSpec.m in Sources */,
162E836E1A9BDE8B00906325 /* SDLUnsubscribeButtonResponseSpec.m in Sources */,
+ DACBA1DC1D22D46D002356F8 /* SDLOnTouchEvent.m in Sources */,
162E835B1A9BDE8B00906325 /* SDLPerformInteractionResponseSpec.m in Sources */,
162E832D1A9BDE8B00906325 /* SDLEncodedSyncPDataSpec.m in Sources */,
5DB92D241AC47B2C00C15BB0 /* SDLHexUtilitySpec.m in Sources */,
@@ -3754,6 +3834,7 @@
162E83811A9BDE8B00906325 /* SDLImageFieldSpec.m in Sources */,
162E834F1A9BDE8B00906325 /* SDLDeleteCommandResponseSpec.m in Sources */,
162E83231A9BDE8B00906325 /* SDLAddSubMenuSpec.m in Sources */,
+ DA4353E91D2721680099B8C4 /* DispatchTimerSpec.m in Sources */,
162E82F21A9BDE8B00906325 /* SDLPredefinedLayoutSpec.m in Sources */,
162E83521A9BDE8B00906325 /* SDLDeleteSubMenuResponseSpec.m in Sources */,
162E82E91A9BDE8B00906325 /* SDLKeypressModeSpec.m in Sources */,
@@ -3775,6 +3856,7 @@
162E83831A9BDE8B00906325 /* SDLKeyboardPropertiesSpec.m in Sources */,
162E82D11A9BDE8A00906325 /* SDLButtonNameSpec.m in Sources */,
162E839E1A9BDE8B00906325 /* SDLRPCStructSpec.m in Sources */,
+ DA4353DF1D271FD10099B8C4 /* CGPointUtilSpec.m in Sources */,
162E83291A9BDE8B00906325 /* SDLDeleteFileSpec.m in Sources */,
1680B11D1A9CD7AD00DBD79E /* SDLProtocolMessageDisassemblerSpec.m in Sources */,
162E838E1A9BDE8B00906325 /* SDLSyncMsgVersionSpec.m in Sources */,
@@ -3808,6 +3890,7 @@
5DF2BB9D1B94E38A00CE5994 /* SDLURLSessionSpec.m in Sources */,
162E83381A9BDE8B00906325 /* SDLScrollableMessageSpec.m in Sources */,
162E82E81A9BDE8B00906325 /* SDLKeyboardLayoutSpec.m in Sources */,
+ DA4353EB1D2721680099B8C4 /* SDLTouchSpec.m in Sources */,
162E83541A9BDE8B00906325 /* SDLEncodedSyncPDataResponseSpec.m in Sources */,
162E83161A9BDE8B00906325 /* SDLOnHashChangeSpec.m in Sources */,
162E82FE1A9BDE8B00906325 /* SDLTBTStateSpec.m in Sources */,
@@ -3820,6 +3903,7 @@
162E82CD1A9BDE8A00906325 /* SDLAudioStreamingStateSpec.m in Sources */,
162E831A1A9BDE8B00906325 /* SDLOnLockScreenStatusSpec.m in Sources */,
162E83431A9BDE8B00906325 /* SDLSyncPDataSpec.m in Sources */,
+ DACBA1E01D22E856002356F8 /* SDLTouchCoord.m in Sources */,
167ED9461A9BCE5D00797BE5 /* SwiftSpec.swift in Sources */,
162E838B1A9BDE8B00906325 /* SDLSoftButtonCapabilitiesSpec.m in Sources */,
162E834C1A9BDE8B00906325 /* SDLAlertResponseSpec.m in Sources */,
@@ -3832,6 +3916,7 @@
162E83741A9BDE8B00906325 /* SDLBodyInformationSpec.m in Sources */,
162E83641A9BDE8B00906325 /* SDLSetMediaClockTimerResponseSpec.m in Sources */,
162E839C1A9BDE8B00906325 /* SDLRPCRequestSpec.m in Sources */,
+ DA4353E31D2720A30099B8C4 /* SDLPinchGestureSpec.m in Sources */,
5D8B17561AC9E399006A6E1C /* SDLDialNumberSpec.m in Sources */,
162E833D1A9BDE8B00906325 /* SDLShowConstantTBTSpec.m in Sources */,
162E83651A9BDE8B00906325 /* SDLShowConstantTBTResponseSpec.m in Sources */,
@@ -3881,6 +3966,7 @@
162E83891A9BDE8B00906325 /* SDLScreenParamsSpec.m in Sources */,
162E83441A9BDE8B00906325 /* SDLSystemRequestSpec.m in Sources */,
162E83001A9BDE8B00906325 /* SDLTextFieldNameSpec.m in Sources */,
+ DA4353EA1D2721680099B8C4 /* SDLTouchManagerSpec.m in Sources */,
162E82FC1A9BDE8B00906325 /* SDLSystemAction.m in Sources */,
162E82CC1A9BDE8A00906325 /* SDLAppInterfaceUnregisteredReasonSpec.m in Sources */,
162E83321A9BDE8B00906325 /* SDLPerformAudioPassThruSpec.m in Sources */,
@@ -3900,6 +3986,7 @@
162E83561A9BDE8B00906325 /* SDLGenericResponseSpec.m in Sources */,
162E82D51A9BDE8A00906325 /* SDLCompassDirectionSpec.m in Sources */,
162E83861A9BDE8B00906325 /* SDLParameterPermissionsSpec.m in Sources */,
+ DACBA1DF1D22D6CE002356F8 /* SDLTouchEvent.m in Sources */,
162E831B1A9BDE8B00906325 /* SDLOnPermissionsChangeSpec.m in Sources */,
162E83711A9BDE8B00906325 /* SDLAirbagStatusSpec.m in Sources */,
162E82CF1A9BDE8A00906325 /* SDLBitsPerSampleSpec.m in Sources */,
@@ -3915,6 +4002,7 @@
162E82F41A9BDE8B00906325 /* SDLPrimaryAudioSource.m in Sources */,
162E83461A9BDE8B00906325 /* SDLUnsubscribeButtonSpec.m in Sources */,
162E82EB1A9BDE8B00906325 /* SDLLayoutModeSpec.m in Sources */,
+ DACBA1DE1D22D642002356F8 /* SDLTouchType.m in Sources */,
1680B1181A9CD7AD00DBD79E /* SDLV1ProtocolMessageSpec.m in Sources */,
162E82EC1A9BDE8B00906325 /* SDLLockScreenStatusSpec.m in Sources */,
162E832F1A9BDE8B00906325 /* SDLGetDTCsSpec.m in Sources */,
diff --git a/SmartDeviceLink/CGPoint_Util.h b/SmartDeviceLink/CGPoint_Util.h
new file mode 100644
index 000000000..9ea06e1b6
--- /dev/null
+++ b/SmartDeviceLink/CGPoint_Util.h
@@ -0,0 +1,39 @@
+//
+// CGPoint_Util.h
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#ifndef CGPoint_Util_h
+#define CGPoint_Util_h
+
+#include <stdio.h>
+#include <CoreGraphics/CGGeometry.h>
+
+/**
+ * @abstract
+ * Calculate the center of two points.
+ * @param point1
+ * First point.
+ * @param point2
+ * Second point.
+ * @return CGPoint
+ * Center of the points.
+ */
+CGPoint CGPointCenterOfPoints(CGPoint point1, CGPoint point2);
+
+/**
+ * @abstract
+ * Calculate the distance between two points.
+ * @param point1
+ * First point.
+ * @param point2
+ * Second point.
+ * @return CGFloat
+ * Distance between the points.
+ */
+CGFloat CGPointDistanceBetweenPoints(CGPoint point1, CGPoint point2);
+
+#endif /* CGPoint_Util_h */
diff --git a/SmartDeviceLink/CGPoint_Util.m b/SmartDeviceLink/CGPoint_Util.m
new file mode 100644
index 000000000..67be5c9fc
--- /dev/null
+++ b/SmartDeviceLink/CGPoint_Util.m
@@ -0,0 +1,20 @@
+//
+// CGPoint_Util.c
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#include "CGPoint_Util.h"
+#include "math.h"
+
+CGPoint CGPointCenterOfPoints(CGPoint point1, CGPoint point2) {
+ CGFloat xCenter = (point1.x + point2.x) / 2.0f;
+ CGFloat yCenter = (point1.y + point2.y) / 2.0f;
+ return CGPointMake(xCenter, yCenter);
+}
+
+CGFloat CGPointDistanceBetweenPoints(CGPoint point1, CGPoint point2) {
+ return hypotf(point1.x - point2.x, point1.y - point2.y);
+} \ No newline at end of file
diff --git a/SmartDeviceLink/SDLPinchGesture.h b/SmartDeviceLink/SDLPinchGesture.h
new file mode 100644
index 000000000..33617594e
--- /dev/null
+++ b/SmartDeviceLink/SDLPinchGesture.h
@@ -0,0 +1,62 @@
+//
+// SDLPinchGesture.h
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "SDLTouch.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLPinchGesture : NSObject
+
+/**
+ * @abstract
+ * Initializes a pinch gesture.
+ * @param firstTouch
+ * First touch of the gesture
+ * @param secondTouch
+ * Second touch of the gesture
+ * @return SDLPinchGesture
+ * Instance of SDLPinchGesture.
+ */
+- (instancetype)initWithFirstTouch:(SDLTouch*)firstTouch secondTouch:(SDLTouch*)secondTouch;
+
+/**
+ * @abstract
+ * First touch of a pinch gesture.
+ */
+@property (nonatomic, strong) SDLTouch* firstTouch;
+
+/**
+ * @abstract
+ * Second touch of a pinch gesture.
+ */
+@property (nonatomic, strong) SDLTouch* secondTouch;
+
+/**
+ * @abstract
+ * Distance between first and second touches.
+ */
+@property (nonatomic, assign, readonly) CGFloat distance;
+
+/**
+ * @abstract
+ * Center point between first and second touches.
+ */
+@property (nonatomic, assign, readonly) CGPoint center;
+
+/**
+ * @abstract
+ * Returns whether or not the pinch gesture is valid. This is true if both touches
+ * are non null.
+ */
+@property (nonatomic, assign, readonly) BOOL isValid;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLPinchGesture.m b/SmartDeviceLink/SDLPinchGesture.m
new file mode 100644
index 000000000..3e522f8dd
--- /dev/null
+++ b/SmartDeviceLink/SDLPinchGesture.m
@@ -0,0 +1,79 @@
+//
+// SDLPinchGesture.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import "SDLPinchGesture.h"
+
+#import "SDLTouch.h"
+#import "CGPoint_Util.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLPinchGesture
+
+@synthesize distance = _distance;
+@synthesize center = _center;
+
+- (instancetype)initWithFirstTouch:(SDLTouch*)firstTouch secondTouch:(SDLTouch*)secondTouch {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _firstTouch = firstTouch;
+ _secondTouch = secondTouch;
+ _distance = -1;
+ _center = CGPointZero;
+
+ return self;
+}
+
+#pragma mark - Setters
+- (void)setFirstTouch:(SDLTouch *)firstTouch {
+ if (firstTouch.identifier == SDLTouchIdentifierFirstFinger) {
+ _firstTouch = firstTouch;
+ [self sdl_invalidate];
+ }
+}
+
+- (void)setSecondTouch:(SDLTouch *)secondTouch {
+ if (secondTouch.identifier == SDLTouchIdentifierSecondFinger) {
+ _secondTouch = secondTouch;
+ [self sdl_invalidate];
+ }
+}
+
+#pragma mark - Getters
+- (CGFloat)distance {
+ if (_distance == -1) {
+ _distance = CGPointDistanceBetweenPoints(self.firstTouch.location,
+ self.secondTouch.location);
+ }
+ return _distance;
+}
+
+- (CGPoint)center {
+ if (CGPointEqualToPoint(_center, CGPointZero)) {
+ _center = CGPointCenterOfPoints(self.firstTouch.location,
+ self.secondTouch.location);
+ }
+ return _center;
+}
+
+- (BOOL)isValid {
+ return (self.firstTouch != nil) && (self.secondTouch != nil);
+}
+
+#pragma mark - Private
+- (void)sdl_invalidate {
+ _distance = -1;
+ _center = CGPointZero;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLProxy.m b/SmartDeviceLink/SDLProxy.m
index 1f98bec6a..c4189452d 100644
--- a/SmartDeviceLink/SDLProxy.m
+++ b/SmartDeviceLink/SDLProxy.m
@@ -29,7 +29,7 @@
#import "SDLProtocolMessage.h"
#import "SDLProtocolMessage.h"
#import "SDLPutFile.h"
-#import "SDLRequestType.h"
+#import "SDLRPCPayload.h"
#import "SDLRPCPayload.h"
#import "SDLRPCRequestFactory.h"
#import "SDLRPCResponse.h"
@@ -64,7 +64,8 @@ const int POLICIES_CORRELATION_ID = 65535;
@property (copy, nonatomic) NSString *appId;
@property (strong, nonatomic) NSMutableSet *mutableProxyListeners;
-@property (nonatomic, strong, readwrite) SDLStreamingMediaManager *streamingMediaManager;
+@property (nonatomic, strong, readwrite, nullable) SDLStreamingMediaManager *streamingMediaManager;
+@property (nonatomic, strong, nullable) SDLDisplayCapabilities* displayCapabilities;
@property (nonatomic, strong) NSMutableDictionary<SDLVehicleMake *, Class> *securityManagers;
@end
@@ -111,6 +112,8 @@ const int POLICIES_CORRELATION_ID = 65535;
_transport = nil;
_protocol = nil;
_mutableProxyListeners = nil;
+ _streamingMediaManager = nil;
+ _displayCapabilities = nil;
}
}
@@ -177,8 +180,12 @@ const int POLICIES_CORRELATION_ID = 65535;
- (SDLStreamingMediaManager *)streamingMediaManager {
if (_streamingMediaManager == nil) {
- _streamingMediaManager = [[SDLStreamingMediaManager alloc] initWithProtocol:self.protocol];
+ if (self.displayCapabilities == nil) {
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"SDLStreamingMediaManager must be accessed only after a successful RegisterAppInterfaceResponse" userInfo:nil];
+ }
+ _streamingMediaManager = [[SDLStreamingMediaManager alloc] initWithProtocol:self.protocol displayCapabilities:self.displayCapabilities];
[self.protocol.protocolDelegateTable addObject:_streamingMediaManager];
+ [self.mutableProxyListeners addObject:_streamingMediaManager.touchManager];
}
return _streamingMediaManager;
@@ -373,6 +380,7 @@ const int POLICIES_CORRELATION_ID = 65535;
NSString *logMessage = [NSString stringWithFormat:@"Framework Version: %@", self.proxyVersion];
[SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName];
SDLRegisterAppInterfaceResponse *registerResponse = (SDLRegisterAppInterfaceResponse *)response;
+ self.displayCapabilities = registerResponse.displayCapabilities;
self.protocol.securityManager = [self securityManagerForMake:registerResponse.vehicleType.make];
if ([SDLGlobals globals].protocolVersion >= 4) {
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h
index 9978913e9..59e1917db 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaManager.h
@@ -12,6 +12,8 @@
#import "SDLProtocolListener.h"
@class SDLAbstractProtocol;
+@class SDLDisplayCapabilities;
+@class SDLTouchManager;
NS_ASSUME_NONNULL_BEGIN
@@ -52,8 +54,32 @@ typedef void (^SDLStreamingEncryptionStartBlock)(BOOL success, BOOL encryption,
@property (assign, nonatomic, readonly) BOOL videoSessionAuthenticated;
@property (assign, nonatomic, readonly) BOOL audioSessionAuthenticated;
+/**
+ * Touch Manager responsible for providing touch event notifications.
+ */
+@property (nonatomic, strong, readonly) SDLTouchManager* touchManager;
+
+/**
+ * The settings used in a VTCompressionSessionRef encoder. These will be verified when the video stream is started. Acceptable properties for this are located in VTCompressionProperties. If set to nil, the defaultVideoEncoderSettings will be used.
+ *
+ * @warning Video streaming must not be connected to update the encoder properties. If it is running, issue a stopVideoSession before updating.
+ */
+@property (strong, nonatomic, null_resettable) NSDictionary* videoEncoderSettings;
+
+/**
+ * Provides default video encoder settings used.
+ */
+@property (strong, nonatomic, readonly) NSDictionary* defaultVideoEncoderSettings;
+
+/**
+ * This is the current screen size of a connected display. This will be the size the video encoder uses to encode the raw image data.
+ */
+@property (assign, nonatomic, readonly) CGSize screenSize;
+
+
+- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol __deprecated_msg(("Please use initWithProtocol:displayCapabilities: instead"));
-- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol;
+- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol displayCapabilities:(SDLDisplayCapabilities*)displayCapabilities;
/**
* This method will attempt to start a streaming video session. It will set up iOS's video encoder, and call out to the head unit asking if it will start a video session.
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m
index 99de10e07..ac5197246 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaManager.m
@@ -11,7 +11,11 @@
@import UIKit;
#import "SDLAbstractProtocol.h"
+#import "SDLDisplayCapabilities.h"
#import "SDLGlobals.h"
+#import "SDLImageResolution.h"
+#import "SDLScreenParams.h"
+#import "SDLTouchManager.h"
NSString *const SDLErrorDomainStreamingMediaVideo = @"com.sdl.streamingmediamanager.video";
@@ -39,6 +43,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (copy, nonatomic, nullable) SDLStreamingEncryptionStartBlock videoStartBlock;
@property (copy, nonatomic, nullable) SDLStreamingEncryptionStartBlock audioStartBlock;
+@property (nonatomic, strong, readwrite) SDLTouchManager *touchManager;
+
@end
@@ -46,14 +52,47 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Class Lifecycle
+- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol displayCapabilities:(SDLDisplayCapabilities*)displayCapabilities {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+
+ _protocol = protocol;
+
+ SDLImageResolution* resolution = displayCapabilities.screenParams.resolution;
+ if (resolution != nil) {
+ _screenSize = CGSizeMake(resolution.resolutionWidth.floatValue,
+ resolution.resolutionHeight.floatValue);
+ } else {
+ NSLog(@"Could not retrieve screen size. Defaulting to 640 x 480.");
+ _screenSize = CGSizeMake(640,
+ 480);
+ }
+
+ return self;
+
+}
+
- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol {
- self = [super init];
+ self = [self init];
if (!self) {
return nil;
}
- _compressionSession = NULL;
+ _protocol = protocol;
+ return self;
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _compressionSession = NULL;
+
_currentFrameNumber = 0;
_videoSessionConnected = NO;
_audioSessionConnected = NO;
@@ -61,10 +100,24 @@ NS_ASSUME_NONNULL_BEGIN
_audioSessionAuthenticated = NO;
_encryptVideoSession = NO;
_encryptAudioSession = NO;
- _protocol = protocol;
+ _protocol = nil;
_videoStartBlock = nil;
_audioStartBlock = nil;
+
+ _screenSize = CGSizeMake(640, 480);
+ _videoEncoderSettings = self.defaultVideoEncoderSettings;
+ _touchManager = [[SDLTouchManager alloc] init];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(sdl_applicationDidEnterBackground:)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(sdl_applicationDidResignActive:)
+ name:UIApplicationWillResignActiveNotification
+ object:nil];
return self;
}
@@ -182,6 +235,31 @@ NS_ASSUME_NONNULL_BEGIN
return YES;
}
+#pragma mark - Update video encoder
+
+- (void)setVideoEncoderSettings:(NSDictionary * _Nullable)videoEncoderSettings {
+ if (self.videoSessionConnected) {
+ @throw [NSException exceptionWithName:SDLErrorDomainStreamingMediaVideo reason:@"Cannot update video encoder settings while video session is connected." userInfo:nil];
+ return;
+ }
+
+ if (videoEncoderSettings) {
+ _videoEncoderSettings = videoEncoderSettings;
+ } else {
+ _videoEncoderSettings = self.defaultVideoEncoderSettings;
+ }
+}
+
+- (NSDictionary*)defaultVideoEncoderSettings {
+ static NSDictionary* defaultVideoEncoderSettings = nil;
+ if (defaultVideoEncoderSettings == nil) {
+ defaultVideoEncoderSettings = @{
+ (__bridge NSString*)kVTCompressionPropertyKey_ProfileLevel : (__bridge NSString*)kVTProfileLevel_H264_Baseline_AutoLevel,
+ (__bridge NSString*)kVTCompressionPropertyKey_RealTime : @YES
+ };
+ }
+ return defaultVideoEncoderSettings;
+}
#pragma mark - SDLProtocolListener Methods
@@ -287,8 +365,7 @@ void sdl_videoEncoderOutputCallback(void *outputCallbackRefCon, void *sourceFram
OSStatus status;
// Create a compression session
- // TODO (Joel F.)[2015-08-18]: Dimensions should be from the Head Unit
- status = VTCompressionSessionCreate(NULL, 640, 480, kCMVideoCodecType_H264, NULL, NULL, NULL, &sdl_videoEncoderOutputCallback, (__bridge void *)self, &_compressionSession);
+ status = VTCompressionSessionCreate(NULL, self.screenSize.width, self.screenSize.height, kCMVideoCodecType_H264, NULL, NULL, NULL, &sdl_videoEncoderOutputCallback, (__bridge void *)self, &_compressionSession);
if (status != noErr) {
// TODO: Log the error
@@ -299,24 +376,41 @@ void sdl_videoEncoderOutputCallback(void *outputCallbackRefCon, void *sourceFram
return NO;
}
- // Set the profile level of the video stream
- status = VTSessionSetProperty(self.compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Baseline_AutoLevel);
+ // Validate that the video encoder properties are valid.
+ CFDictionaryRef supportedProperties;
+ status = VTSessionCopySupportedPropertyDictionary(self.compressionSession, &supportedProperties);
if (status != noErr) {
if (*error != nil) {
*error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];
}
-
+
return NO;
}
-
- // Set the session to compress in real time
- status = VTSessionSetProperty(self.compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
- if (status != noErr) {
- if (*error != nil) {
- *error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];
+
+ for (NSString* key in self.videoEncoderSettings.allKeys) {
+ if (CFDictionaryContainsKey(supportedProperties, (__bridge CFStringRef)key) == false) {
+ if (*error != nil) {
+ NSString* description = [NSString stringWithFormat:@"\"%@\" is not a supported key.", key];
+ *error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{NSLocalizedDescriptionKey : description}];
+ }
+ CFRelease(supportedProperties);
+ return NO;
+ }
+ }
+ CFRelease(supportedProperties);
+
+ // Populate the video encoder settings from provided dictionary.
+ for (NSString* key in self.videoEncoderSettings.allKeys) {
+ id value = self.videoEncoderSettings[key];
+
+ status = VTSessionSetProperty(self.compressionSession, (__bridge CFStringRef)key, (__bridge CFTypeRef)value);
+ if (status != noErr) {
+ if (*error != nil) {
+ *error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];
+ }
+
+ return NO;
}
-
- return NO;
}
return YES;
@@ -417,6 +511,15 @@ void sdl_videoEncoderOutputCallback(void *outputCallbackRefCon, void *sourceFram
return streamingDataQueue;
}
+#pragma mark - Private Functions
+- (void)sdl_applicationDidEnterBackground:(NSNotification*)notification {
+ [self.touchManager cancelPendingTouches];
+}
+
+- (void)sdl_applicationDidResignActive:(NSNotification*)notification {
+ [self.touchManager cancelPendingTouches];
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLTouch.h b/SmartDeviceLink/SDLTouch.h
new file mode 100644
index 000000000..6cfb1f2db
--- /dev/null
+++ b/SmartDeviceLink/SDLTouch.h
@@ -0,0 +1,65 @@
+//
+// SDLTouch.h
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@class SDLTouchEvent;
+
+typedef enum {
+ SDLTouchIdentifierFirstFinger = 0,
+ SDLTouchIdentifierSecondFinger = 1
+} SDLTouchIdentifier;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLTouch : NSObject
+
+/**
+ * @abstract
+ * Initializes a touch.
+ * @param touchEvent
+ * Incoming touch event from onOnTouchEvent notification.
+ * @return SDLTouch
+ * Instance of SDLTouch.
+ */
+- (instancetype)initWithTouchEvent:(SDLTouchEvent*)touchEvent;
+
+/**
+ * @abstract
+ * Identifier of the touch's finger. Refer to SDLTouchIdentifier for valid
+ * identifiers.
+ */
+@property (nonatomic, assign, readonly) NSInteger identifier;
+
+/**
+ * @abstract
+ * Location of touch point, in the head unit's coordinate system.
+ */
+@property (nonatomic, assign, readonly) CGPoint location;
+
+/**
+ * @abstract
+ * Timestamp in which the touch occured.
+ */
+@property (nonatomic, assign, readonly) NSUInteger timeStamp;
+
+/**
+ * @abstract
+ * Returns whether or not this touch is a first finger.
+ */
+@property (nonatomic, assign, readonly) BOOL isFirstFinger;
+
+/**
+ * @abstract
+ * Returns whether or not this touch is a second finger.
+ */
+@property (nonatomic, assign, readonly) BOOL isSecondFinger;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLTouch.m b/SmartDeviceLink/SDLTouch.m
new file mode 100644
index 000000000..2481ee69a
--- /dev/null
+++ b/SmartDeviceLink/SDLTouch.m
@@ -0,0 +1,64 @@
+//
+// SDLTouch.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import "SDLTouch.h"
+
+#import "SDLTouchEvent.h"
+#import "SDLTouchCoord.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLTouch
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _identifier = -1;
+ _location = CGPointZero;
+ _timeStamp = 0;
+
+ return self;
+}
+
+- (instancetype)initWithTouchEvent:(SDLTouchEvent*)touchEvent {
+ self = [self init];
+ if (self) {
+ _identifier = touchEvent.touchEventId.unsignedIntegerValue;
+
+ id firstTimeStamp = touchEvent.timeStamp.firstObject;
+ // In the event we receive a null timestamp, we will supply a device timestamp.
+ if ([firstTimeStamp isKindOfClass:[NSNull class]]
+ && [firstTimeStamp isEqual:[NSNull null]]) {
+ _timeStamp = [[NSDate date] timeIntervalSince1970] * 1000.0;
+ } else {
+ NSNumber* timeStampNumber = (NSNumber*)firstTimeStamp;
+ _timeStamp = timeStampNumber.unsignedIntegerValue;
+ }
+
+ SDLTouchCoord* coord = touchEvent.coord.firstObject;
+ _location = CGPointMake(coord.x.floatValue,
+ coord.y.floatValue);
+ }
+ return self;
+}
+
+#pragma mark - Getters
+- (BOOL)isFirstFinger {
+ return self.identifier == SDLTouchIdentifierFirstFinger;
+}
+
+- (BOOL)isSecondFinger {
+ return self.identifier == SDLTouchIdentifierSecondFinger;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLTouchManager.h b/SmartDeviceLink/SDLTouchManager.h
new file mode 100644
index 000000000..b89917218
--- /dev/null
+++ b/SmartDeviceLink/SDLTouchManager.h
@@ -0,0 +1,63 @@
+//
+// SDLTouchManager.h
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "SDLTouchManagerDelegate.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLTouchManager : NSObject
+
+@property (nonatomic, weak, nullable) id<SDLTouchManagerDelegate> touchEventDelegate;
+
+/**
+ * @abstract
+ * Distance between two taps on the screen, in the head unit's coordinate system, used
+ * for registering double-tap callbacks.
+ * @remark
+ * Default is 50 pixels.
+ */
+@property (nonatomic, assign) CGFloat tapDistanceThreshold;
+
+/**
+ * @abstract
+ * Time (in seconds) between tap events to register a double-tap callback.
+ * @remark
+ * Default is 0.4 seconds.
+ */
+@property (nonatomic, assign) CGFloat tapTimeThreshold;
+
+/**
+ * @abstract
+ * Time (in seconds) between movement events to register panning or pinching
+ * callbacks.
+ * @remark
+ * Default is 0.05 seconds.
+ */
+@property (nonatomic, assign) CGFloat movementTimeThreshold;
+
+/**
+ * @abstract
+ * Boolean denoting whether or not the touch manager should deliver touch event
+ * callbacks.
+ * @remark
+ * Default is true.
+ */
+@property (nonatomic, assign, getter=isTouchEnabled) BOOL touchEnabled;
+
+/**
+ * @abstract
+ * Cancels pending touch event timers that may be in progress.
+ * @remark
+ * Currently only impacts the timer used to register single taps.
+ */
+- (void)cancelPendingTouches;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLTouchManager.m b/SmartDeviceLink/SDLTouchManager.m
new file mode 100644
index 000000000..fc023026f
--- /dev/null
+++ b/SmartDeviceLink/SDLTouchManager.m
@@ -0,0 +1,284 @@
+//
+// SDLTouchManager.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import "SDLTouchManager.h"
+
+#import "dispatch_timer.h"
+#import "CGPoint_Util.h"
+
+#import "SDLDebugTool.h"
+#import "SDLOnTouchEvent.h"
+#import "SDLPinchGesture.h"
+#import "SDLProxyListener.h"
+#import "SDLTouch.h"
+#import "SDLTouchCoord.h"
+#import "SDLTouchEvent.h"
+#import "SDLTouchType.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSUInteger, SDLPerformingTouchType) {
+ SDLPerformingTouchTypeNone,
+ SDLPerformingTouchTypeSingleTouch,
+ SDLPerformingTouchTypeMultiTouch,
+ SDLPerformingTouchTypePanningTouch
+};
+
+/*!
+ * @abstract
+ * Touch Manager will ignore touches that represent more than 2 fingers on the screen.
+ */
+static NSUInteger const MaximumNumberOfTouches = 2;
+
+@interface SDLTouchManager () <SDLProxyListener>
+
+/*!
+ * @abstract
+ * First Touch received from onOnTouchEvent.
+ */
+@property (nonatomic, strong, nullable) SDLTouch* previousTouch;
+
+/*!
+ * @abstract
+ * Cached previous single tap used for double tap detection.
+ */
+@property (nonatomic, strong, nullable) SDLTouch* singleTapTouch;
+
+/*!
+ * @abstract
+ * Distance of a previously generated pinch event. Used to calculate the scale of zoom motion.
+ */
+@property (nonatomic, assign) CGFloat previousPinchDistance;
+
+/*!
+ * @abstract
+ * Current in-progress pinch gesture.
+ */
+@property (nonatomic, strong, nullable) SDLPinchGesture* currentPinchGesture;
+
+/*!
+ * @abstract
+ * Timer used for distinguishing between single & double taps.
+ */
+@property (nonatomic, strong, nullable) dispatch_source_t singleTapTimer;
+
+/*!
+ * @abstract
+ * Current touch type being performed.
+ */
+@property (nonatomic, assign) SDLPerformingTouchType performingTouchType;
+
+@end
+
+@implementation SDLTouchManager
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _movementTimeThreshold = 0.05f;
+ _tapTimeThreshold = 0.4f;
+ _tapDistanceThreshold = 50.0f;
+ _touchEnabled = YES;
+
+ return self;
+}
+
+#pragma mark - Public
+- (void)cancelPendingTouches {
+ [self sdl_cancelSingleTapTimer];
+}
+
+#pragma mark - SDLProxyListener Delegate
+- (void)onProxyOpened { }
+- (void)onProxyClosed { }
+- (void)onOnHMIStatus:(SDLOnHMIStatus *)notification { }
+- (void)onOnDriverDistraction:(SDLOnDriverDistraction *)notification { }
+
+- (void)onOnTouchEvent:(SDLOnTouchEvent *)notification {
+ if (!self.isTouchEnabled) {
+ return;
+ }
+
+ SDLTouchEvent* touchEvent = notification.event.firstObject;
+
+ SDLTouch* touch = [[SDLTouch alloc] initWithTouchEvent:touchEvent];
+
+ if (touch.identifier > MaximumNumberOfTouches) {
+ return;
+ }
+
+ if ([notification.type isEqualToEnum:SDLTouchType.BEGIN]) {
+ [self sdl_handleTouchBegan:touch];
+ } else if ([notification.type isEqualToEnum:SDLTouchType.MOVE]) {
+ [self sdl_handleTouchMoved:touch];
+ } else if ([notification.type isEqualToEnum:SDLTouchType.END]) {
+ [self sdl_handleTouchEnded:touch];
+ }
+}
+
+#pragma mark - Private
+- (void)sdl_handleTouchBegan:(SDLTouch*)touch {
+ if (!touch.isFirstFinger
+ && !self.isTouchEnabled) {
+ return; // no-op
+ }
+
+ _performingTouchType = SDLPerformingTouchTypeSingleTouch;
+
+ switch (touch.identifier) {
+ case SDLTouchIdentifierFirstFinger:
+ self.previousTouch = touch;
+ break;
+ case SDLTouchIdentifierSecondFinger:
+ _performingTouchType = SDLPerformingTouchTypeMultiTouch;
+ self.currentPinchGesture = [[SDLPinchGesture alloc] initWithFirstTouch:self.previousTouch
+ secondTouch:touch];
+ self.previousPinchDistance = self.currentPinchGesture.distance;
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:pinchDidStartAtCenterPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ pinchDidStartAtCenterPoint:self.currentPinchGesture.center];
+ }
+ break;
+ }
+}
+
+- (void)sdl_handleTouchMoved:(SDLTouch*)touch {
+ if ((touch.timeStamp - self.previousTouch.timeStamp) <= (self.movementTimeThreshold * NSEC_PER_USEC)
+ || !self.isTouchEnabled) {
+ return; // no-op
+ }
+
+ switch (self.performingTouchType) {
+ case SDLPerformingTouchTypeMultiTouch:
+ switch (touch.identifier) {
+ case SDLTouchIdentifierFirstFinger:
+ self.currentPinchGesture.firstTouch = touch;
+ break;
+ case SDLTouchIdentifierSecondFinger:
+ self.currentPinchGesture.secondTouch = touch;
+ break;
+ }
+
+
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePinchAtCenterPoint:withScale:)]) {
+ CGFloat scale = self.currentPinchGesture.distance / self.previousPinchDistance;
+ [self.touchEventDelegate touchManager:self
+ didReceivePinchAtCenterPoint:self.currentPinchGesture.center
+ withScale:scale];
+ }
+
+ self.previousPinchDistance = self.currentPinchGesture.distance;
+ break;
+ case SDLPerformingTouchTypeSingleTouch:
+ _performingTouchType = SDLPerformingTouchTypePanningTouch;
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidStartAtPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ panningDidStartAtPoint:touch.location];
+ }
+ break;
+ case SDLPerformingTouchTypePanningTouch:
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePanningFromPoint:toPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ didReceivePanningFromPoint:self.previousTouch.location toPoint:touch.location];
+ }
+ break;
+ case SDLPerformingTouchTypeNone:
+ break;
+ }
+
+ self.previousTouch = touch;
+}
+
+- (void)sdl_handleTouchEnded:(SDLTouch*)touch {
+ if (!self.isTouchEnabled) {
+ return; // no-op
+ }
+
+ switch (self.performingTouchType) {
+ case SDLPerformingTouchTypeMultiTouch:
+ switch (touch.identifier) {
+ case SDLTouchIdentifierFirstFinger:
+ self.currentPinchGesture.firstTouch = touch;
+ break;
+ case SDLTouchIdentifierSecondFinger:
+ self.currentPinchGesture.secondTouch = touch;
+ break;
+ }
+
+ if (self.currentPinchGesture.isValid) {
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:pinchDidEndAtCenterPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ pinchDidEndAtCenterPoint:self.currentPinchGesture.center];
+ }
+ self.currentPinchGesture = nil;
+ }
+ break;
+ case SDLPerformingTouchTypePanningTouch:
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidEndAtPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ panningDidEndAtPoint:touch.location];
+ }
+ break;
+ case SDLPerformingTouchTypeSingleTouch:
+ if (self.singleTapTimer == nil) { // Initial Tap
+ self.singleTapTouch = touch;
+ [self sdl_initializeSingleTapTimerAtPoint:self.singleTapTouch.location];
+ } else { // Double Tap
+ [self sdl_cancelSingleTapTimer];
+
+ NSUInteger timeStampDelta = touch.timeStamp - self.singleTapTouch.timeStamp;
+ CGFloat xDelta = fabs(touch.location.x - self.singleTapTouch.location.x);
+ CGFloat yDelta = fabs(touch.location.y - self.singleTapTouch.location.y);
+
+ if (timeStampDelta <= self.tapTimeThreshold * NSEC_PER_USEC
+ && xDelta <= self.tapDistanceThreshold
+ && yDelta <= self.tapDistanceThreshold) {
+ CGPoint centerPoint = CGPointCenterOfPoints(touch.location,
+ self.singleTapTouch.location);
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveDoubleTapAtPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ didReceiveDoubleTapAtPoint:centerPoint];
+ }
+ }
+
+ self.singleTapTouch = nil;
+ }
+ break;
+ case SDLPerformingTouchTypeNone:
+ break;
+ }
+ self.previousTouch = nil;
+ _performingTouchType = SDLPerformingTouchTypeNone;
+}
+
+- (void)sdl_initializeSingleTapTimerAtPoint:(CGPoint)point {
+ __weak typeof(self) weakSelf = self;
+ self.singleTapTimer = dispatch_create_timer(self.tapTimeThreshold, NO, ^{
+ typeof(weakSelf) strongSelf = weakSelf;
+ strongSelf.singleTapTouch = nil;
+ if ([strongSelf.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveSingleTapAtPoint:)]) {
+ [strongSelf.touchEventDelegate touchManager:strongSelf
+ didReceiveSingleTapAtPoint:point];
+ }
+ });
+}
+
+- (void)sdl_cancelSingleTapTimer {
+ if (self.singleTapTimer == NULL) {
+ return;
+ }
+ dispatch_stop_timer(self.singleTapTimer);
+ self.singleTapTimer = NULL;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SDLTouchManagerDelegate.h b/SmartDeviceLink/SDLTouchManagerDelegate.h
new file mode 100644
index 000000000..f23a4ec6d
--- /dev/null
+++ b/SmartDeviceLink/SDLTouchManagerDelegate.h
@@ -0,0 +1,104 @@
+//
+// SDLTouchManagerDelegate.h
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/14/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+@class SDLTouchManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol SDLTouchManagerDelegate <NSObject>
+
+@optional
+
+/**
+ * @abstract
+ * Single tap was received.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Location of the single tap in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager didReceiveSingleTapAtPoint:(CGPoint)point;
+
+/**
+ * @abstract
+ * Double tap was received.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Location of the double tap in the head unit's coordinate system. This is the
+ * average of the first and second tap.
+ */
+- (void)touchManager:(SDLTouchManager*)manager didReceiveDoubleTapAtPoint:(CGPoint)point;
+
+/**
+ * @abstract
+ * Panning did start.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Location of the panning start point in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager panningDidStartAtPoint:(CGPoint)point;
+
+/**
+ * @abstract
+ * Panning did move.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param fromPoint
+ * Location of the panning's previous point in the head unit's coordinate system.
+ * @param toPoint
+ * Location of the panning's new point in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager didReceivePanningFromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint;
+
+/**
+ * @abstract
+ * Panning did end.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Location of the panning's end point in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager panningDidEndAtPoint:(CGPoint)point;
+
+/**
+ * @abstract
+ * Pinch did start.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Center point of the pinch in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager pinchDidStartAtCenterPoint:(CGPoint)point;
+
+/**
+ * @abstract
+ * Pinch did move.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Center point of the pinch in the head unit's coordinate system.
+ * @param scale
+ * Scale relative to the distance between touch points.
+ */
+- (void)touchManager:(SDLTouchManager*)manager didReceivePinchAtCenterPoint:(CGPoint)point withScale:(CGFloat)scale;
+
+/**
+ * @abstract
+ * Pinch did end.
+ * @param manager
+ * Current initalized SDLTouchManager issuing the callback.
+ * @param point
+ * Center point of the pinch in the head unit's coordinate system.
+ */
+- (void)touchManager:(SDLTouchManager*)manager pinchDidEndAtCenterPoint:(CGPoint)point;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h
index 6fdff29d6..294ac5fa4 100644
--- a/SmartDeviceLink/SmartDeviceLink.h
+++ b/SmartDeviceLink/SmartDeviceLink.h
@@ -19,6 +19,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLProxyFactory.h"
#import "SDLSecurityType.h"
#import "SDLStreamingMediaManager.h"
+#import "SDLTouchManager.h"
#import "SDLTTSChunkFactory.h"
/***** Debug *****/
@@ -38,6 +39,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLAbstractProtocol.h"
#import "SDLProtocol.h"
#import "SDLProtocolListener.h"
+#import "SDLTouchManagerDelegate.h"
// Header
#import "SDLProtocolHeader.h"
diff --git a/SmartDeviceLink/dispatch_timer.h b/SmartDeviceLink/dispatch_timer.h
new file mode 100644
index 000000000..a35068390
--- /dev/null
+++ b/SmartDeviceLink/dispatch_timer.h
@@ -0,0 +1,18 @@
+//
+// dispatch_timer.h
+// MobileNav
+//
+// Created by Muller, Alexander (A.) on 5/12/16.
+// Copyright © 2016 Alex Muller. All rights reserved.
+//
+
+#ifndef dispatch_timer_h
+#define dispatch_timer_h
+
+#include <stdio.h>
+#include <dispatch/dispatch.h>
+
+dispatch_source_t dispatch_create_timer(double afterInterval, bool repeating, dispatch_block_t block);
+void dispatch_stop_timer(dispatch_source_t timer);
+
+#endif /* dispatch_timer_h */
diff --git a/SmartDeviceLink/dispatch_timer.m b/SmartDeviceLink/dispatch_timer.m
new file mode 100644
index 000000000..7e2a5bec2
--- /dev/null
+++ b/SmartDeviceLink/dispatch_timer.m
@@ -0,0 +1,38 @@
+//
+// dispatch_timer.c
+// MobileNav
+//
+// Created by Muller, Alexander (A.) on 5/12/16.
+// Copyright © 2016 Alex Muller. All rights reserved.
+//
+
+#include "dispatch_timer.h"
+
+dispatch_source_t dispatch_create_timer(double afterInterval, bool repeating, dispatch_block_t block) {
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
+ 0);
+ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
+ 0,
+ 0,
+ queue);
+ dispatch_source_set_timer(timer,
+ dispatch_time(DISPATCH_TIME_NOW, afterInterval * NSEC_PER_SEC),
+ afterInterval * NSEC_PER_SEC,
+ (1ull * NSEC_PER_SEC) / 10);
+ dispatch_source_set_event_handler(timer, ^{
+ if (!repeating) {
+ dispatch_stop_timer(timer);
+ }
+ if (block) {
+ block();
+ }
+ });
+ dispatch_resume(timer);
+
+ return timer;
+}
+
+void dispatch_stop_timer(dispatch_source_t timer) {
+ dispatch_source_set_event_handler(timer, NULL);
+ dispatch_source_cancel(timer);
+}
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/CGPointUtilSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/CGPointUtilSpec.m
new file mode 100644
index 000000000..f4c227291
--- /dev/null
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/CGPointUtilSpec.m
@@ -0,0 +1,72 @@
+//
+// CGPointUtilSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 7/1/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "CGPoint_Util.h"
+
+QuickSpecBegin(CGPointUtilSpec)
+
+describe(@"CGPoint_Util Tests", ^{
+ __block CGPoint first;
+ __block CGPoint second;
+ context(@"For two positive points", ^{
+ beforeEach(^{
+ first = CGPointMake(100, 200);
+ second = CGPointMake(300, 400);
+ });
+
+ it(@"should properly calculate the center between points", ^{
+ CGPoint center = CGPointCenterOfPoints(first, second);
+ expect(@(center.x)).to(equal(@200));
+ expect(@(center.y)).to(equal(@300));
+ });
+ it(@"should properly calculate the distance between points", ^{
+ CGFloat distance = CGPointDistanceBetweenPoints(first, second);
+ expect(@(distance)).to(beCloseTo(@282.8427).within(0.0001));
+ });
+ });
+ context(@"For two negative points", ^{
+ beforeEach(^{
+ first = CGPointMake(-100, -200);
+ second = CGPointMake(-300, -400);
+ });
+
+ it(@"should properly calculate the center between points", ^{
+ CGPoint center = CGPointCenterOfPoints(first, second);
+ expect(@(center.x)).to(equal(@(-200)));
+ expect(@(center.y)).to(equal(@(-300)));
+ });
+ it(@"should properly calculate the distance between points", ^{
+ CGFloat distance = CGPointDistanceBetweenPoints(first, second);
+ expect(@(distance)).to(beCloseTo(@282.8427).within(0.0001));
+ });
+ });
+ context(@"For one positive and one negative point", ^{
+ beforeEach(^{
+ first = CGPointMake(100, 200);
+ second = CGPointMake(-300, -400);
+ });
+
+ it(@"should properly calculate the center between points", ^{
+ CGPoint center = CGPointCenterOfPoints(first, second);
+ expect(@(center.x)).to(equal(@(-100)));
+ expect(@(center.y)).to(equal(@(-100)));
+ });
+ it(@"should properly calculate the distance between points", ^{
+ CGFloat distance = CGPointDistanceBetweenPoints(first, second);
+ expect(@(distance)).to(beCloseTo(@721.1103).within(0.0001));
+ });
+ });
+});
+
+QuickSpecEnd \ No newline at end of file
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/DispatchTimerSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/DispatchTimerSpec.m
new file mode 100644
index 000000000..771d2c4bb
--- /dev/null
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/DispatchTimerSpec.m
@@ -0,0 +1,47 @@
+//
+// DispatchTimerSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 7/1/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "dispatch_timer.h"
+
+QuickSpecBegin(DispatchTimerSpec)
+
+describe(@"dispatch_timer Tests", ^{
+ context(@"Creating", ^{
+ it(@"should be successful within specified time", ^{
+ waitUntilTimeout(4, ^(void (^done)(void)) {
+ __block double currentTime = [[NSDate date] timeIntervalSince1970];
+ dispatch_create_timer(2.5, false, ^{
+ double difference = [[NSDate date] timeIntervalSince1970] - currentTime;
+ expect(@(difference)).to(beCloseTo(@2.5).within(0.1));
+ done();
+ });
+ });
+ });
+
+ it(@"should be cancellable and not fire", ^{
+ __block dispatch_source_t timer;
+ waitUntilTimeout(2, ^(void (^done)(void)) {
+ timer = dispatch_create_timer(2.5, false, ^{
+ fail();
+ });
+ [NSThread sleepForTimeInterval:0.5];
+ dispatch_stop_timer(timer);
+ done();
+ });
+ expect(@(dispatch_source_testcancel(timer))).to(beGreaterThan(@0));
+ });
+ });
+});
+
+QuickSpecEnd \ No newline at end of file
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLPinchGestureSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLPinchGestureSpec.m
new file mode 100644
index 000000000..99293ac8c
--- /dev/null
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLPinchGestureSpec.m
@@ -0,0 +1,182 @@
+//
+// SDLPinchGestureSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 7/1/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "SDLPinchGesture.h"
+#import "SDLTouchCoord.h"
+#import "SDLTouchEvent.h"
+
+QuickSpecBegin(SDLPinchGestureSpec)
+
+describe(@"SDLPinchGesture Tests", ^{
+ context(@"SDLPinchGestureZero", ^{
+ __block SDLPinchGesture* pinchGesture = [[SDLPinchGesture alloc] init];;
+
+ it(@"should correctly initialize", ^{
+ expect(pinchGesture.firstTouch).to(beNil());
+ expect(pinchGesture.secondTouch).to(beNil());
+ expect(@(pinchGesture.distance)).to(equal(@0));
+ expect(@(CGPointEqualToPoint(pinchGesture.center, CGPointZero))).to(beTruthy());
+ });
+
+ it(@"should not be a valid SDLPinchGesture", ^{
+ expect(@(pinchGesture.isValid)).to(beFalsy());
+ });
+ });
+
+ context(@"SDLPinchGestureMake", ^{
+ __block SDLPinchGesture* pinchGesture;
+ __block unsigned long timeStamp = [[NSDate date] timeIntervalSince1970] * 1000;
+ __block unsigned long secondTimeStamp = timeStamp + 1000;
+
+ beforeEach(^{
+ SDLTouchCoord* firstCoord = [[SDLTouchCoord alloc] init];
+ firstCoord.x = @100;
+ firstCoord.y = @200;
+
+ SDLTouchEvent* firstTouchEvent = [[SDLTouchEvent alloc] init];
+ firstTouchEvent.touchEventId = @0;
+ firstTouchEvent.coord = [NSMutableArray arrayWithObject:firstCoord];
+ firstTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(timeStamp)];
+
+ SDLTouch* firstTouch = [[SDLTouch alloc] initWithTouchEvent:firstTouchEvent];
+
+ SDLTouchCoord* secondCoord = [[SDLTouchCoord alloc] init];
+ secondCoord.x = @200;
+ secondCoord.y = @300;
+
+ SDLTouchEvent* secondTouchEvent = [[SDLTouchEvent alloc] init];
+ secondTouchEvent.touchEventId = @1;
+ secondTouchEvent.coord = [NSMutableArray arrayWithObject:secondCoord];
+ secondTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondTimeStamp)];
+
+ SDLTouch* secondTouch = [[SDLTouch alloc] initWithTouchEvent:secondTouchEvent];
+
+ pinchGesture = [[SDLPinchGesture alloc] initWithFirstTouch:firstTouch
+ secondTouch:secondTouch];
+ });
+
+ it(@"should correctly initialize", ^{
+ expect(@(pinchGesture.firstTouch.identifier)).to(equal(@(SDLTouchIdentifierFirstFinger)));
+ expect(@(pinchGesture.firstTouch.location.x)).to(equal(@100));
+ expect(@(pinchGesture.firstTouch.location.y)).to(equal(@200));
+ expect(@(pinchGesture.firstTouch.timeStamp)).to(equal(@(timeStamp)));
+
+ expect(@(pinchGesture.secondTouch.identifier)).to(equal(@(SDLTouchIdentifierSecondFinger)));
+ expect(@(pinchGesture.secondTouch.location.x)).to(equal(@200));
+ expect(@(pinchGesture.secondTouch.location.y)).to(equal(@300));
+ expect(@(pinchGesture.secondTouch.timeStamp)).to(equal(@(secondTimeStamp)));
+
+ expect(@(pinchGesture.distance)).to(beCloseTo(@141.4213).within(0.0001));
+ expect(@(pinchGesture.center.x)).to(equal(@150));
+ expect(@(pinchGesture.center.y)).to(equal(@250));
+ });
+
+ it(@"should be a valid SDLPinchGesture", ^{
+ expect(@(pinchGesture.isValid)).to(beTruthy());
+ });
+ });
+
+ context(@"updating SDLPinchGesture", ^{
+ __block SDLPinchGesture* pinchGesture;
+ __block unsigned long timeStamp = [[NSDate date] timeIntervalSince1970] * 1000;
+ __block unsigned long secondTimeStamp = timeStamp + 1000;
+ __block unsigned long newTimeStamp = timeStamp + 1000;
+
+ __block SDLTouch* newFirstTouch;
+ __block SDLTouch* newSecondTouch;
+
+ beforeEach(^{
+ SDLTouchCoord* firstCoord = [[SDLTouchCoord alloc] init];
+ firstCoord.x = @100;
+ firstCoord.y = @200;
+
+ SDLTouchEvent* firstTouchEvent = [[SDLTouchEvent alloc] init];
+ firstTouchEvent.touchEventId = @0;
+ firstTouchEvent.coord = [NSMutableArray arrayWithObject:firstCoord];
+ firstTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(timeStamp)];
+
+ SDLTouch* firstTouch = [[SDLTouch alloc] initWithTouchEvent:firstTouchEvent];
+
+ SDLTouchCoord* secondCoord = [[SDLTouchCoord alloc] init];
+ secondCoord.x = @200;
+ secondCoord.y = @300;
+
+ SDLTouchEvent* secondTouchEvent = [[SDLTouchEvent alloc] init];
+ secondTouchEvent.touchEventId = @1;
+ secondTouchEvent.coord = [NSMutableArray arrayWithObject:secondCoord];
+ secondTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondTimeStamp)];
+
+ SDLTouch* secondTouch = [[SDLTouch alloc] initWithTouchEvent:secondTouchEvent];
+
+ pinchGesture = [[SDLPinchGesture alloc] initWithFirstTouch:firstTouch
+ secondTouch:secondTouch];
+
+ SDLTouchCoord* newCoord = [[SDLTouchCoord alloc] init];
+ newCoord.x = @150;
+ newCoord.y = @250;
+
+ SDLTouchEvent* newFirstTouchEvent = [[SDLTouchEvent alloc] init];
+ newFirstTouchEvent.touchEventId = @0;
+ newFirstTouchEvent.coord = [NSMutableArray arrayWithObject:newCoord];
+ newFirstTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(newTimeStamp)];
+
+ SDLTouchEvent* newSecondTouchEvent = [[SDLTouchEvent alloc] init];
+ newSecondTouchEvent.touchEventId = @1;
+ newSecondTouchEvent.coord = [NSMutableArray arrayWithObject:newCoord];
+ newSecondTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(newTimeStamp)];
+
+ newFirstTouch = [[SDLTouch alloc] initWithTouchEvent:newFirstTouchEvent];
+ newSecondTouch = [[SDLTouch alloc] initWithTouchEvent:newSecondTouchEvent];
+ });
+
+ it(@"should update first point correctly", ^{
+ pinchGesture.firstTouch = newFirstTouch;
+
+ expect(@(pinchGesture.firstTouch.identifier)).to(equal(@(SDLTouchIdentifierFirstFinger)));
+ expect(@(pinchGesture.firstTouch.location.x)).to(equal(@150));
+ expect(@(pinchGesture.firstTouch.location.y)).to(equal(@250));
+ expect(@(pinchGesture.firstTouch.timeStamp)).to(equal(@(newTimeStamp)));
+
+ expect(@(pinchGesture.secondTouch.identifier)).to(equal(@(SDLTouchIdentifierSecondFinger)));
+ expect(@(pinchGesture.secondTouch.location.x)).to(equal(@200));
+ expect(@(pinchGesture.secondTouch.location.y)).to(equal(@300));
+ expect(@(pinchGesture.secondTouch.timeStamp)).to(equal(@(secondTimeStamp)));
+
+ expect(@(pinchGesture.distance)).to(beCloseTo(@(70.7107)).within(0.0001));
+ expect(@(pinchGesture.center.x)).to(equal(@175));
+ expect(@(pinchGesture.center.y)).to(equal(@275));
+
+ });
+
+ it(@"should update second point correctly", ^{
+ pinchGesture.secondTouch = newSecondTouch;
+
+ expect(@(pinchGesture.firstTouch.identifier)).to(equal(@(SDLTouchIdentifierFirstFinger)));
+ expect(@(pinchGesture.firstTouch.location.x)).to(equal(@100));
+ expect(@(pinchGesture.firstTouch.location.y)).to(equal(@200));
+ expect(@(pinchGesture.firstTouch.timeStamp)).to(equal(@(timeStamp)));
+
+ expect(@(pinchGesture.secondTouch.identifier)).to(equal(@(SDLTouchIdentifierSecondFinger)));
+ expect(@(pinchGesture.secondTouch.location.x)).to(equal(@150));
+ expect(@(pinchGesture.secondTouch.location.y)).to(equal(@250));
+ expect(@(pinchGesture.secondTouch.timeStamp)).to(equal(@(newTimeStamp)));
+
+ expect(@(pinchGesture.distance)).to(beCloseTo(@70.7107).within(0.0001));
+ expect(@(pinchGesture.center.x)).to(equal(@125));
+ expect(@(pinchGesture.center.y)).to(equal(@225));
+ });
+ });
+});
+
+QuickSpecEnd \ No newline at end of file
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
new file mode 100644
index 000000000..21639b6b7
--- /dev/null
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
@@ -0,0 +1,609 @@
+//
+// SDLTouchManagerSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 6/17/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "SDLOnTouchEvent.h"
+#import "SDLTouchCoord.h"
+#import "SDLTouchEvent.h"
+#import "SDLTouchManager.h"
+#import "SDLTouchType.h"
+
+QuickSpecBegin(SDLTouchManagerSpec)
+
+describe(@"SDLTouchManager Tests", ^{
+
+ __block SDLTouchManager* touchManager;
+
+ context(@"initializing", ^{
+ it(@"should correctly have default properties", ^{
+ SDLTouchManager* touchManager = [[SDLTouchManager alloc] init];
+ expect(touchManager.touchEventDelegate).to(beNil());
+ expect(@(touchManager.tapDistanceThreshold)).to(equal(@50));
+ expect(@(touchManager.tapTimeThreshold)).to(beCloseTo(@0.4).within(0.0001));
+ expect(@(touchManager.movementTimeThreshold)).to(beCloseTo(@0.05).within(0.0001));
+ expect(@(touchManager.isTouchEnabled)).to(beTruthy());
+ });
+
+ });
+
+ describe(@"touch events", ^{
+ typedef void (^DelegateCallbackBlock)(NSInvocation* invocation);
+
+ __block id delegateMock;
+ __block CGPoint controlPoint;
+ __block BOOL didCallSingleTap;
+ __block BOOL didCallDoubleTap;
+ __block BOOL didCallBeginPan;
+ __block BOOL didCallMovePan;
+ __block BOOL didCallEndPan;
+ __block BOOL didCallBeginPinch;
+ __block BOOL didCallMovePinch;
+ __block BOOL didCallEndPinch;
+
+ __block DelegateCallbackBlock singleTapTests;
+ __block DelegateCallbackBlock doubleTapTests;
+ __block DelegateCallbackBlock panStartTests;
+ __block DelegateCallbackBlock panMoveTests;
+ __block DelegateCallbackBlock panEndTests;
+ __block DelegateCallbackBlock pinchStartTests;
+ __block DelegateCallbackBlock pinchMoveTests;
+ __block DelegateCallbackBlock pinchEndTests;
+
+ __block void (^performTouchEvent)(SDLTouchManager* touchManager, SDLOnTouchEvent* onTouchEvent) = ^(SDLTouchManager* touchManager, SDLOnTouchEvent* onTouchEvent) {
+ SEL onOnTouchEvent = NSSelectorFromString(@"onOnTouchEvent:");
+ ((void (*)(id, SEL, id))[touchManager methodForSelector:onOnTouchEvent])(touchManager, onOnTouchEvent, onTouchEvent);
+ };
+
+ beforeEach(^{
+ touchManager = [[SDLTouchManager alloc] init];
+ delegateMock = OCMProtocolMock(@protocol(SDLTouchManagerDelegate));
+ touchManager.touchEventDelegate = delegateMock;
+ controlPoint = CGPointMake(100, 200);
+
+ didCallSingleTap = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallSingleTap = YES;
+
+ singleTapTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] didReceiveSingleTapAtPoint:CGPointZero];
+
+ singleTapTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallDoubleTap = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallDoubleTap = YES;
+
+ doubleTapTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] didReceiveDoubleTapAtPoint:CGPointZero];
+
+ doubleTapTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallBeginPan = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallBeginPan = YES;
+
+ panStartTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] panningDidStartAtPoint:CGPointZero];
+
+ panStartTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallMovePan = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallMovePan = YES;
+
+ panMoveTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] didReceivePanningFromPoint:CGPointZero toPoint:CGPointZero];
+
+ panMoveTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallEndPan = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallEndPan = YES;
+
+ panEndTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] panningDidEndAtPoint:CGPointZero];
+
+ panEndTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallBeginPinch = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallBeginPinch = YES;
+
+ pinchStartTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] pinchDidStartAtCenterPoint:CGPointZero];
+
+ pinchStartTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallMovePinch = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallMovePinch = YES;
+
+ pinchMoveTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] didReceivePinchAtCenterPoint:CGPointZero withScale:0];
+
+ pinchMoveTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+
+ didCallEndPinch = NO;
+ [[[[delegateMock stub] andDo:^(NSInvocation* invocation) {
+ didCallEndPinch = YES;
+
+ pinchEndTests(invocation);
+ }] ignoringNonObjectArgs] touchManager:[OCMArg any] pinchDidEndAtCenterPoint:CGPointZero];
+
+ pinchEndTests = ^(NSInvocation* invocation) {
+ fail();
+ };
+ });
+
+ describe(@"single finger", ^{
+ __block SDLTouchCoord* firstTouchCoord;
+ __block NSUInteger firstTouchTimeStamp;
+
+ __block SDLOnTouchEvent* firstOnTouchEventStart;
+ __block SDLOnTouchEvent* firstOnTouchEventEnd;
+
+ beforeEach(^{
+ firstTouchCoord = [[SDLTouchCoord alloc] init];
+ firstTouchCoord.x = @(controlPoint.x);
+ firstTouchCoord.y = @(controlPoint.y);
+
+ firstTouchTimeStamp = [[NSDate date] timeIntervalSince1970] * 1000.0;
+
+ SDLTouchEvent* touchEvent = [[SDLTouchEvent alloc] init];
+ touchEvent.touchEventId = @0;
+ touchEvent.coord = [NSMutableArray arrayWithObject:firstTouchCoord];
+ touchEvent.timeStamp = [NSMutableArray arrayWithObject:@(firstTouchTimeStamp)];
+
+ firstOnTouchEventStart = [[SDLOnTouchEvent alloc] init];
+ firstOnTouchEventStart.type = SDLTouchType.BEGIN;
+ firstOnTouchEventStart.event = [NSMutableArray arrayWithObject:touchEvent];
+
+ firstOnTouchEventEnd = [[SDLOnTouchEvent alloc] init];
+ firstOnTouchEventEnd.type = SDLTouchType.END;
+ firstOnTouchEventEnd.event = [NSMutableArray arrayWithObject:touchEvent];
+ });
+
+ describe(@"when receiving a single tap", ^{
+ it(@"should correctly handle a single tap", ^{
+
+ singleTapTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, controlPoint))).to(beTruthy());
+ };
+
+ performTouchEvent(touchManager, firstOnTouchEventStart);
+
+ performTouchEvent(touchManager, firstOnTouchEventEnd);
+
+ expect(@(didCallSingleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallDoubleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ });
+ });
+
+ describe(@"when receiving a double tap", ^{
+ __block CGPoint averagePoint;
+
+ __block SDLTouchEvent* secondTouchEvent;
+
+ __block SDLOnTouchEvent* secondOnTouchEventStart;
+ __block SDLOnTouchEvent* secondOnTouchEventEnd;
+
+ beforeEach(^{
+ secondOnTouchEventStart = [[SDLOnTouchEvent alloc] init];
+ secondOnTouchEventStart.type = SDLTouchType.BEGIN;
+
+ secondOnTouchEventEnd = [[SDLOnTouchEvent alloc] init];
+ secondOnTouchEventEnd.type = SDLTouchType.END;
+
+ secondTouchEvent = [[SDLTouchEvent alloc] init];
+ secondTouchEvent.touchEventId = @0;
+ NSUInteger secondTouchTimeStamp = firstTouchTimeStamp + (touchManager.tapTimeThreshold - 0.1) * 1000;
+ secondTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondTouchTimeStamp)];
+ });
+
+ context(@"near the same point", ^{
+ beforeEach(^{
+ SDLTouchCoord* touchCoord = [[SDLTouchCoord alloc] init];
+ touchCoord.x = @(firstTouchCoord.x.floatValue + touchManager.tapDistanceThreshold);
+ touchCoord.y = @(firstTouchCoord.y.floatValue + touchManager.tapDistanceThreshold);
+
+ secondTouchEvent.coord = [NSMutableArray arrayWithObject:touchCoord];
+
+ secondOnTouchEventStart.event = [NSMutableArray arrayWithObject:secondTouchEvent];
+
+ secondOnTouchEventEnd.event = [NSMutableArray arrayWithObject:secondTouchEvent];
+
+ averagePoint = CGPointMake((firstTouchCoord.x.floatValue + touchCoord.x.floatValue) / 2.0f,
+ (firstTouchCoord.y.floatValue + touchCoord.y.floatValue) / 2.0f);
+ });
+
+ it(@"should issue delegate callbacks", ^{
+ doubleTapTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, averagePoint))).to(beTruthy());
+ };
+
+ performTouchEvent(touchManager, firstOnTouchEventStart);
+ performTouchEvent(touchManager, firstOnTouchEventEnd);
+ performTouchEvent(touchManager, secondOnTouchEventStart);
+ performTouchEvent(touchManager, secondOnTouchEventEnd);
+
+ expect(@(didCallSingleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallDoubleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallBeginPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ });
+ });
+
+ context(@"not near the same point", ^{
+ beforeEach(^{
+ SDLTouchCoord* touchCoord = [[SDLTouchCoord alloc] init];
+ touchCoord.x = @(firstTouchCoord.x.floatValue + touchManager.tapDistanceThreshold + 1);
+ touchCoord.y = @(firstTouchCoord.y.floatValue + touchManager.tapDistanceThreshold + 1);
+
+ secondTouchEvent.coord = [NSMutableArray arrayWithObject:touchCoord];
+
+ secondOnTouchEventStart.event = [NSMutableArray arrayWithObject:secondTouchEvent];
+
+ secondOnTouchEventEnd.event = [NSMutableArray arrayWithObject:secondTouchEvent];
+ });
+
+ it(@"should should not issue delegate callbacks", ^{
+ performTouchEvent(touchManager, firstOnTouchEventStart);
+ performTouchEvent(touchManager, firstOnTouchEventEnd);
+ performTouchEvent(touchManager, secondOnTouchEventStart);
+ performTouchEvent(touchManager, secondOnTouchEventEnd);
+
+ expect(@(didCallSingleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallDoubleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ });
+ });
+ });
+ });
+ context(@"when receiving a pan", ^{
+ __block CGPoint panStartPoint;
+ __block CGPoint panMovePoint;
+ __block CGPoint panSecondMovePoint;
+ __block CGPoint panEndPoint;
+
+ __block CGFloat distanceMoveX = 10;
+ __block CGFloat distanceMoveY = 20;
+
+ __block SDLOnTouchEvent* panStartOnTouchEvent;
+ __block SDLOnTouchEvent* panMoveOnTouchEvent;
+ __block SDLOnTouchEvent* panSecondMoveOnTouchEvent;
+ __block SDLOnTouchEvent* panEndOnTouchEvent;
+
+ beforeEach(^{
+ // Finger touch down
+ panStartPoint = controlPoint;
+
+ SDLTouchCoord* panStartTouchCoord = [[SDLTouchCoord alloc] init];
+ panStartTouchCoord.x = @(panStartPoint.x);
+ panStartTouchCoord.y = @(panStartPoint.y);
+
+ CGFloat movementTimeThresholdOffset = (touchManager.movementTimeThreshold + .01) * 1000;
+
+ NSUInteger panStartTimeStamp = ([[NSDate date] timeIntervalSince1970] * 1000) + movementTimeThresholdOffset;
+
+ SDLTouchEvent* panStartTouchEvent = [[SDLTouchEvent alloc] init];
+ panStartTouchEvent.coord = [NSMutableArray arrayWithObject:panStartTouchCoord];
+ panStartTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(panStartTimeStamp)];
+
+ panStartOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ panStartOnTouchEvent.event = [NSMutableArray arrayWithObject:panStartTouchEvent];
+ panStartOnTouchEvent.type = SDLTouchType.BEGIN;
+
+ // Finger Move
+ panMovePoint = CGPointMake(panStartPoint.x + distanceMoveX, panStartPoint.y + distanceMoveY);
+
+ SDLTouchCoord* panMoveTouchCoord = [[SDLTouchCoord alloc] init];
+ panMoveTouchCoord.x = @(panMovePoint.x);
+ panMoveTouchCoord.y = @(panMovePoint.y);
+
+ NSUInteger panMoveTimeStamp = panStartTimeStamp + movementTimeThresholdOffset;
+
+ SDLTouchEvent* panMoveTouchEvent = [[SDLTouchEvent alloc] init];
+ panMoveTouchEvent.coord = [NSMutableArray arrayWithObject:panMoveTouchCoord];
+ panMoveTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(panMoveTimeStamp)];
+
+ panMoveOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ panMoveOnTouchEvent.event = [NSMutableArray arrayWithObject:panMoveTouchEvent];
+ panMoveOnTouchEvent.type = SDLTouchType.MOVE;
+
+ // Finger Move
+ panSecondMovePoint = CGPointMake(panMovePoint.x + distanceMoveX, panMovePoint.y + distanceMoveY);
+
+ SDLTouchCoord* panSecondMoveTouchCoord = [[SDLTouchCoord alloc] init];
+ panSecondMoveTouchCoord.x = @(panSecondMovePoint.x);
+ panSecondMoveTouchCoord.y = @(panSecondMovePoint.y);
+
+ NSUInteger panSecondMoveTimeStamp = panMoveTimeStamp + movementTimeThresholdOffset;
+
+ SDLTouchEvent* panSecondMoveTouchEvent = [[SDLTouchEvent alloc] init];
+ panSecondMoveTouchEvent.coord = [NSMutableArray arrayWithObject:panSecondMoveTouchCoord];
+ panSecondMoveTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(panSecondMoveTimeStamp)];
+
+ panSecondMoveOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ panSecondMoveOnTouchEvent.event = [NSMutableArray arrayWithObject:panSecondMoveTouchEvent];
+ panSecondMoveOnTouchEvent.type = SDLTouchType.MOVE;
+
+ // Finger End
+ panEndPoint = CGPointMake(panSecondMovePoint.x, panSecondMovePoint.y);
+
+ SDLTouchCoord* panEndTouchCoord = [[SDLTouchCoord alloc] init];
+ panEndTouchCoord.x = @(panEndPoint.x);
+ panEndTouchCoord.y = @(panEndPoint.y);
+
+ NSUInteger panEndTimeStamp = panSecondMoveTimeStamp + movementTimeThresholdOffset;
+
+ SDLTouchEvent* panEndTouchEvent = [[SDLTouchEvent alloc] init];
+ panEndTouchEvent.coord = [NSMutableArray arrayWithObject:panEndTouchCoord];
+ panEndTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(panEndTimeStamp)];
+
+ panEndOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ panEndOnTouchEvent.event = [NSMutableArray arrayWithObject:panEndTouchEvent];
+ panEndOnTouchEvent.type = SDLTouchType.END;
+ });
+
+ it(@"should correctly give all pan callbacks", ^{
+ panStartTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, panMovePoint))).to(beTruthy());
+ };
+
+ panMoveTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint startPoint;
+ CGPoint endPoint;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&startPoint atIndex:3];
+ [invocation getArgument:&endPoint atIndex:4];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(startPoint, panMovePoint))).to(beTruthy());
+ expect(@(CGPointEqualToPoint(endPoint, panSecondMovePoint))).to(beTruthy());
+ };
+
+ panEndTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, panEndPoint))).to(beTruthy());
+ };
+
+ performTouchEvent(touchManager, panStartOnTouchEvent);
+ performTouchEvent(touchManager, panMoveOnTouchEvent);
+ performTouchEvent(touchManager, panSecondMoveOnTouchEvent);
+ performTouchEvent(touchManager, panEndOnTouchEvent);
+
+ expect(@(didCallSingleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallDoubleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallMovePan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallEndPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallBeginPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+
+ });
+ });
+ context(@"when receiving a pinch", ^{
+
+ __block CGPoint pinchStartCenter;
+ __block CGPoint pinchMoveCenter;
+ __block CGFloat pinchMoveScale;
+ __block CGPoint pinchEndCenter;
+
+ __block SDLOnTouchEvent* pinchStartFirstFingerOnTouchEvent;
+ __block SDLOnTouchEvent* pinchStartSecondFingerOnTouchEvent;
+ __block SDLOnTouchEvent* pinchMoveSecondFingerOnTouchEvent;
+ __block SDLOnTouchEvent* pinchEndSecondFingerOnTouchEvent;
+
+ beforeEach(^{
+ // First finger touch down
+ SDLTouchCoord* firstFingerTouchCoord = [[SDLTouchCoord alloc] init];
+ firstFingerTouchCoord.x = @(controlPoint.x);
+ firstFingerTouchCoord.y = @(controlPoint.y);
+
+ NSUInteger firstFingerTimeStamp = [[NSDate date] timeIntervalSince1970] * 1000;
+
+ SDLTouchEvent* firstFingerTouchEvent = [[SDLTouchEvent alloc] init];
+ firstFingerTouchEvent.coord = [NSMutableArray arrayWithObject:firstFingerTouchCoord];
+ firstFingerTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(firstFingerTimeStamp)];
+
+ pinchStartFirstFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ pinchStartFirstFingerOnTouchEvent.event = [NSMutableArray arrayWithObject:firstFingerTouchEvent];
+ pinchStartFirstFingerOnTouchEvent.type = SDLTouchType.BEGIN;
+
+ // Second finger touch down
+ SDLTouchCoord* secondFingerTouchCoord = [[SDLTouchCoord alloc] init];
+ secondFingerTouchCoord.x = @(firstFingerTouchCoord.x.floatValue + 100);
+ secondFingerTouchCoord.y = @(firstFingerTouchCoord.y.floatValue + 100);
+
+ NSUInteger secondFingerTimeStamp = firstFingerTimeStamp;
+
+ SDLTouchEvent* secondFingerTouchEvent = [[SDLTouchEvent alloc] init];
+ secondFingerTouchEvent.touchEventId = @1;
+ secondFingerTouchEvent.coord = [NSMutableArray arrayWithObject:secondFingerTouchCoord];
+ secondFingerTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondFingerTimeStamp)];
+
+ pinchStartSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ pinchStartSecondFingerOnTouchEvent.event = [NSMutableArray arrayWithObject:secondFingerTouchEvent];
+ pinchStartSecondFingerOnTouchEvent.type = SDLTouchType.BEGIN;
+
+ pinchStartCenter = CGPointMake((firstFingerTouchCoord.x.floatValue + secondFingerTouchCoord.x.floatValue) / 2.0f,
+ (firstFingerTouchCoord.y.floatValue + secondFingerTouchCoord.y.floatValue) / 2.0f);
+
+ CGFloat pinchStartDistance = hypotf(firstFingerTouchCoord.x.floatValue - secondFingerTouchCoord.x.floatValue,
+ firstFingerTouchCoord.y.floatValue - secondFingerTouchCoord.y.floatValue);
+
+ // Second finger move
+ SDLTouchCoord* secondFingerMoveTouchCoord = [[SDLTouchCoord alloc] init];
+ secondFingerMoveTouchCoord.x = @(secondFingerTouchCoord.x.floatValue - 50);
+ secondFingerMoveTouchCoord.y = @(secondFingerTouchCoord.y.floatValue - 40);
+
+ NSUInteger secondFingerMoveTimeStamp = secondFingerTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
+
+ SDLTouchEvent* secondFingerMoveTouchEvent = [[SDLTouchEvent alloc] init];
+ secondFingerMoveTouchEvent.touchEventId = @1;
+ secondFingerMoveTouchEvent.coord = [NSMutableArray arrayWithObject:secondFingerMoveTouchCoord];
+ secondFingerMoveTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondFingerMoveTimeStamp)];
+
+ pinchMoveSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ pinchMoveSecondFingerOnTouchEvent.event = [NSMutableArray arrayWithObject:secondFingerMoveTouchEvent];
+ pinchMoveSecondFingerOnTouchEvent.type = SDLTouchType.MOVE;
+
+ pinchMoveCenter = CGPointMake((firstFingerTouchCoord.x.floatValue + secondFingerMoveTouchCoord.x.floatValue) / 2.0f,
+ (firstFingerTouchCoord.y.floatValue + secondFingerMoveTouchCoord.y.floatValue) / 2.0f);
+
+ CGFloat pinchMoveDistance = hypotf(firstFingerTouchCoord.x.floatValue - secondFingerMoveTouchCoord.x.floatValue,
+ firstFingerTouchCoord.y.floatValue - secondFingerMoveTouchCoord.y.floatValue);
+
+ pinchMoveScale = pinchMoveDistance / pinchStartDistance;
+
+ // Second finger end
+ SDLTouchCoord* secondFingerEndTouchCoord = secondFingerMoveTouchCoord;
+
+ NSUInteger secondFingerEndTimeStamp = secondFingerMoveTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
+
+ SDLTouchEvent* secondFingerEndTouchEvent = [[SDLTouchEvent alloc] init];
+ secondFingerEndTouchEvent.touchEventId = @1;
+ secondFingerEndTouchEvent.coord = [NSMutableArray arrayWithObject:secondFingerEndTouchCoord];
+ secondFingerEndTouchEvent.timeStamp = [NSMutableArray arrayWithObject:@(secondFingerEndTimeStamp)];
+
+ pinchEndSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
+ pinchEndSecondFingerOnTouchEvent.event = [NSMutableArray arrayWithObject:secondFingerEndTouchEvent];
+ pinchEndSecondFingerOnTouchEvent.type = SDLTouchType.END;
+
+ pinchEndCenter = CGPointMake((firstFingerTouchCoord.x.floatValue + secondFingerEndTouchCoord.x.floatValue) / 2.0f,
+ (firstFingerTouchCoord.y.floatValue + secondFingerEndTouchCoord.y.floatValue) / 2.0f);
+ });
+
+ it(@"should correctly give all pinch callback", ^{
+ pinchStartTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, pinchStartCenter))).to(beTruthy());
+ };
+
+ pinchMoveTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+ CGFloat scale;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+ [invocation getArgument:&scale atIndex:4];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, pinchMoveCenter))).to(beTruthy());
+ expect(@(scale)).to(beCloseTo(@(pinchMoveScale)).within(0.0001));
+ };
+
+ pinchEndTests = ^(NSInvocation* invocation) {
+ __unsafe_unretained SDLTouchManager* touchManagerCallback;
+
+ CGPoint point;
+
+ [invocation getArgument:&touchManagerCallback atIndex:2];
+ [invocation getArgument:&point atIndex:3];
+
+ expect(touchManagerCallback).to(equal(touchManager));
+ expect(@(CGPointEqualToPoint(point, pinchEndCenter))).to(beTruthy());
+ };
+
+ performTouchEvent(touchManager, pinchStartFirstFingerOnTouchEvent);
+ performTouchEvent(touchManager, pinchStartSecondFingerOnTouchEvent);
+ performTouchEvent(touchManager, pinchMoveSecondFingerOnTouchEvent);
+ performTouchEvent(touchManager, pinchEndSecondFingerOnTouchEvent);
+
+ expect(@(didCallSingleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallDoubleTap)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallMovePan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallEndPan)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beFalsy());
+ expect(@(didCallBeginPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallMovePinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ expect(@(didCallEndPinch)).withTimeout(touchManager.tapTimeThreshold + 0.1).toEventually(beTruthy());
+ });
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchSpec.m
new file mode 100644
index 000000000..c629cd72e
--- /dev/null
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchSpec.m
@@ -0,0 +1,107 @@
+//
+// SDLTouchSpecs.m
+// SmartDeviceLink-iOS
+//
+// Created by Muller, Alexander (A.) on 7/1/16.
+// Copyright © 2016 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "SDLTouchEvent.h"
+#import "SDLTouchCoord.h"
+#import "SDLTouch.h"
+
+QuickSpecBegin(SDLTouchSpec)
+
+describe(@"SDLTouch Tests", ^{
+ context(@"SDLTouchZero", ^{
+ __block SDLTouch* touch = [[SDLTouch alloc] init];
+
+ it(@"should correctly initialize", ^{
+ expect(@(touch.identifier)).to(equal(@(-1)));
+ expect(@(CGPointEqualToPoint(touch.location, CGPointZero))).to(beTruthy());
+ expect(@(touch.timeStamp)).to(equal(@0));
+ });
+
+ it(@"should not equal First Finger Identifier", ^{
+ expect(@(touch.isFirstFinger)).to(beFalsy());
+ });
+
+ it(@"should not equal Second Finger Identifier", ^{
+ expect(@(touch.isSecondFinger)).to(beFalsy());
+ });
+ });
+
+ context(@"For First Finger Identifiers", ^{
+ __block unsigned long timeStamp = [[NSDate date] timeIntervalSince1970] * 1000;
+ __block SDLTouch* touch;
+
+ beforeSuite(^{
+ SDLTouchCoord* coord = [[SDLTouchCoord alloc] init];
+ coord.x = @100;
+ coord.y = @200;
+
+ SDLTouchEvent* touchEvent = [[SDLTouchEvent alloc] init];
+ touchEvent.touchEventId = @0;
+ touchEvent.coord = [NSMutableArray arrayWithObject:coord];
+ touchEvent.timeStamp = [NSMutableArray arrayWithObject:@(timeStamp)];
+
+ touch = [[SDLTouch alloc] initWithTouchEvent:touchEvent];
+ });
+
+ it(@"should correctly make a SDLTouch struct", ^{
+ expect(@(touch.identifier)).to(equal(@(SDLTouchIdentifierFirstFinger)));
+ expect(@(touch.location.x)).to(equal(@100));
+ expect(@(touch.location.y)).to(equal(@200));
+ expect(@(touch.timeStamp)).to(equal(@(timeStamp)));
+ });
+
+ it(@"should equal First Finger Identifier", ^{
+ expect(@(touch.isFirstFinger)).to(beTruthy());
+ });
+
+ it(@"should not equal Second Finger Identifier", ^{
+ expect(@(touch.isSecondFinger)).to(beFalsy());
+ });
+ });
+
+ context(@"For Second Finger Identifiers", ^{
+ __block unsigned long timeStamp = [[NSDate date] timeIntervalSince1970] * 1000;
+ __block SDLTouch* touch;
+
+ beforeSuite(^{
+ SDLTouchCoord* coord = [[SDLTouchCoord alloc] init];
+ coord.x = @100;
+ coord.y = @200;
+
+ SDLTouchEvent* touchEvent = [[SDLTouchEvent alloc] init];
+ touchEvent.touchEventId = @1;
+ touchEvent.coord = [NSMutableArray arrayWithObject:coord];
+ touchEvent.timeStamp = [NSMutableArray arrayWithObject:@(timeStamp)];
+
+ touch = [[SDLTouch alloc] initWithTouchEvent:touchEvent];
+ });
+
+ it(@"should correctly make a SDLTouch struct", ^{
+ expect(@(touch.identifier)).to(equal(@(SDLTouchIdentifierSecondFinger)));
+ expect(@(touch.location.x)).to(equal(@100));
+ expect(@(touch.location.y)).to(equal(@200));
+ expect(@(touch.timeStamp)).to(equal(@(timeStamp)));
+ });
+
+ it(@"should equal First Finger Identifier", ^{
+ expect(@(touch.isFirstFinger)).to(beFalsy());
+ });
+
+ it(@"should not equal Second Finger Identifier", ^{
+ expect(@(touch.isSecondFinger)).to(beTruthy());
+ });
+ });
+});
+
+QuickSpecEnd \ No newline at end of file