summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2017-09-28 14:04:33 -0400
committerJoel Fischer <joeljfischer@gmail.com>2017-09-28 14:04:33 -0400
commitd34a92bd185b928a30401269621189b713220737 (patch)
tree0aca1debbd7b5fd00eba07275e2a721dd2fee4e1
parenteca3589a66ef012919871865c1c9139e25454891 (diff)
downloadsdl_ios-d34a92bd185b928a30401269621189b713220737.tar.gz
Integration for haptic manager into the SMM
* Interface tweaks to SDLHapticHitTester, now just takes a point instead of a touch * SMM configuration has a window property that, if set, will create the haptic manager in the SMM * When the SMM receives video capabilities, it will check the `hapticSpatialDataSupported` property and enable / disable the haptic manager’s sending of RPCs based on it * TouchManager now takes an optional haptic hit tester to check view locations * TouchManagerDelegate now has view passthrough on many delegate methods
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj22
-rw-r--r--SmartDeviceLink/SDLHapticHitTester.h6
-rw-r--r--SmartDeviceLink/SDLHapticInterface.h9
-rw-r--r--SmartDeviceLink/SDLHapticManager.h2
-rw-r--r--SmartDeviceLink/SDLHapticManager.m22
-rw-r--r--SmartDeviceLink/SDLStreamingMediaConfiguration.h14
-rw-r--r--SmartDeviceLink/SDLStreamingMediaConfiguration.m9
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.h6
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.m21
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.h6
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.m4
-rw-r--r--SmartDeviceLink/SDLTouchManager.h26
-rw-r--r--SmartDeviceLink/SDLTouchManager.m45
-rw-r--r--SmartDeviceLink/SDLTouchManagerDelegate.h122
14 files changed, 193 insertions, 121 deletions
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index 4e56793ab..ba8356223 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -231,11 +231,6 @@
1680B11C1A9CD7AD00DBD79E /* SDLProtocolMessageAssemblerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1680B1101A9CD7AD00DBD79E /* SDLProtocolMessageAssemblerSpec.m */; };
1680B11D1A9CD7AD00DBD79E /* SDLProtocolMessageDisassemblerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1680B1111A9CD7AD00DBD79E /* SDLProtocolMessageDisassemblerSpec.m */; };
1680B11E1A9CD7AD00DBD79E /* SDLProtocolReceivedMessageRouterSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1680B1121A9CD7AD00DBD79E /* SDLProtocolReceivedMessageRouterSpec.m */; };
- 1FF7DAB61F75B27300B46C30 /* SDLHapticInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB51F75B27300B46C30 /* SDLHapticInterface.h */; };
- 1FF7DAB81F75B28E00B46C30 /* SDLHapticHitTester.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB71F75B28E00B46C30 /* SDLHapticHitTester.h */; };
- 1FF7DABA1F75B2A800B46C30 /* SDLHapticManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB91F75B2A800B46C30 /* SDLHapticManager.h */; };
- 1FF7DABC1F75B2BF00B46C30 /* SDLHapticManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF7DABB1F75B2BF00B46C30 /* SDLHapticManager.m */; };
- 1FF7DAC01F75CF6C00B46C30 /* SDLHapticManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF7DABF1F75CF6C00B46C30 /* SDLHapticManagerSpec.m */; };
1E4920B11F6A6443008F2CC3 /* SDLRadioState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5AD05F1F207AB10029B8AF /* SDLRadioState.m */; };
1E4920B21F6A6455008F2CC3 /* SDLGetInteriorVehicleDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5AD08B1F20BC320029B8AF /* SDLGetInteriorVehicleDataResponse.m */; };
1E4920B31F6A6463008F2CC3 /* SDLOnInteriorVehicleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5AD0971F20C0FB0029B8AF /* SDLOnInteriorVehicleData.m */; };
@@ -297,6 +292,11 @@
1EE8C45D1F387D1C00FDC2CF /* SDLGetInteriorVehicleDataResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE8C45C1F387D1C00FDC2CF /* SDLGetInteriorVehicleDataResponseSpec.m */; };
1EE8C45F1F3884FF00FDC2CF /* SDLSetInteriorVehicleDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE8C45E1F3884FF00FDC2CF /* SDLSetInteriorVehicleDataSpec.m */; };
1EE8C4611F38865B00FDC2CF /* SDLSetInteriorVehicleDataResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE8C4601F38865B00FDC2CF /* SDLSetInteriorVehicleDataResponseSpec.m */; };
+ 1FF7DAB61F75B27300B46C30 /* SDLHapticInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB51F75B27300B46C30 /* SDLHapticInterface.h */; };
+ 1FF7DAB81F75B28E00B46C30 /* SDLHapticHitTester.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB71F75B28E00B46C30 /* SDLHapticHitTester.h */; };
+ 1FF7DABA1F75B2A800B46C30 /* SDLHapticManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB91F75B2A800B46C30 /* SDLHapticManager.h */; };
+ 1FF7DABC1F75B2BF00B46C30 /* SDLHapticManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF7DABB1F75B2BF00B46C30 /* SDLHapticManager.m */; };
+ 1FF7DAC01F75CF6C00B46C30 /* SDLHapticManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF7DABF1F75CF6C00B46C30 /* SDLHapticManagerSpec.m */; };
332A914F1CED9CC60043824C /* SDLAppInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 332A913D1CED87F80043824C /* SDLAppInfo.m */; };
332A91501CED9CF10043824C /* SDLAppInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 332A913C1CED87F80043824C /* SDLAppInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
5D00AC671F140F0A004000D9 /* SDLSystemCapabilityType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D00AC651F140F0A004000D9 /* SDLSystemCapabilityType.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1418,11 +1418,6 @@
1680B1101A9CD7AD00DBD79E /* SDLProtocolMessageAssemblerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLProtocolMessageAssemblerSpec.m; sourceTree = "<group>"; };
1680B1111A9CD7AD00DBD79E /* SDLProtocolMessageDisassemblerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLProtocolMessageDisassemblerSpec.m; sourceTree = "<group>"; };
1680B1121A9CD7AD00DBD79E /* SDLProtocolReceivedMessageRouterSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLProtocolReceivedMessageRouterSpec.m; sourceTree = "<group>"; };
- 1FF7DAB51F75B27300B46C30 /* SDLHapticInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticInterface.h; sourceTree = "<group>"; };
- 1FF7DAB71F75B28E00B46C30 /* SDLHapticHitTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticHitTester.h; sourceTree = "<group>"; };
- 1FF7DAB91F75B2A800B46C30 /* SDLHapticManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticManager.h; sourceTree = "<group>"; };
- 1FF7DABB1F75B2BF00B46C30 /* SDLHapticManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticManager.m; sourceTree = "<group>"; };
- 1FF7DABF1F75CF6C00B46C30 /* SDLHapticManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLHapticManagerSpec.m; path = ProxySpecs/SDLHapticManagerSpec.m; sourceTree = "<group>"; };
1E5AD0321F1F3AA30029B8AF /* SDLRemoteControlCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLRemoteControlCapabilities.h; sourceTree = "<group>"; };
1E5AD0331F1F3AA30029B8AF /* SDLRemoteControlCapabilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLRemoteControlCapabilities.m; sourceTree = "<group>"; };
1E5AD0361F1F4E390029B8AF /* SDLClimateControlCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLClimateControlCapabilities.h; sourceTree = "<group>"; };
@@ -1484,6 +1479,11 @@
1EE8C45C1F387D1C00FDC2CF /* SDLGetInteriorVehicleDataResponseSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLGetInteriorVehicleDataResponseSpec.m; sourceTree = "<group>"; };
1EE8C45E1F3884FF00FDC2CF /* SDLSetInteriorVehicleDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSetInteriorVehicleDataSpec.m; sourceTree = "<group>"; };
1EE8C4601F38865B00FDC2CF /* SDLSetInteriorVehicleDataResponseSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSetInteriorVehicleDataResponseSpec.m; sourceTree = "<group>"; };
+ 1FF7DAB51F75B27300B46C30 /* SDLHapticInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticInterface.h; sourceTree = "<group>"; };
+ 1FF7DAB71F75B28E00B46C30 /* SDLHapticHitTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticHitTester.h; sourceTree = "<group>"; };
+ 1FF7DAB91F75B2A800B46C30 /* SDLHapticManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticManager.h; sourceTree = "<group>"; };
+ 1FF7DABB1F75B2BF00B46C30 /* SDLHapticManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticManager.m; sourceTree = "<group>"; };
+ 1FF7DABF1F75CF6C00B46C30 /* SDLHapticManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLHapticManagerSpec.m; path = ProxySpecs/SDLHapticManagerSpec.m; sourceTree = "<group>"; };
332A913C1CED87F80043824C /* SDLAppInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLAppInfo.h; sourceTree = "<group>"; };
332A913D1CED87F80043824C /* SDLAppInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLAppInfo.m; sourceTree = "<group>"; };
5D00AC651F140F0A004000D9 /* SDLSystemCapabilityType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSystemCapabilityType.h; sourceTree = "<group>"; };
@@ -3608,7 +3608,6 @@
children = (
97E26DEA1E807AD70074A3C7 /* SDLMutableDataQueue.h */,
97E26DEB1E807AD70074A3C7 /* SDLMutableDataQueue.m */,
- DAC5724C1D0FE3B60004288B /* Touches */,
E9C32B831AB20B2900F283AF /* @categories */,
5D5934F91A851A8000687FB9 /* Prioritized Objects */,
5D61FAD21A84238A00846EE7 /* SDLHexUtility.h */,
@@ -4408,6 +4407,7 @@
DA8966E71E56937100413EAB /* Streaming */ = {
isa = PBXGroup;
children = (
+ DAC5724C1D0FE3B60004288B /* Touches */,
DA8966F01E56970C00413EAB /* Utilities */,
DAA41D521DF66B1100BC7337 /* Video Encoding */,
DA8966E81E56938C00413EAB /* Lifecycle */,
diff --git a/SmartDeviceLink/SDLHapticHitTester.h b/SmartDeviceLink/SDLHapticHitTester.h
index 7678ccf28..8345d23a4 100644
--- a/SmartDeviceLink/SDLHapticHitTester.h
+++ b/SmartDeviceLink/SDLHapticHitTester.h
@@ -16,10 +16,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Determines which view was selected based on SDLTouch object. If no view gets matched null value will be returned.
- @param touch SDLTouch which has touch coordinates
- @return matched UIView object or null
+ @param point Point to check for a view
+ @return point UIView object or nil
*/
-- (nullable UIView *)viewForSDLTouch:(SDLTouch *)touch;
+- (nullable UIView *)viewForPoint:(CGPoint)point;
@end
diff --git a/SmartDeviceLink/SDLHapticInterface.h b/SmartDeviceLink/SDLHapticInterface.h
index 987f10e7c..2b8c3fa83 100644
--- a/SmartDeviceLink/SDLHapticInterface.h
+++ b/SmartDeviceLink/SDLHapticInterface.h
@@ -15,12 +15,19 @@ NS_ASSUME_NONNULL_BEGIN
@protocol SDLHapticInterface <NSObject>
/**
+ Whether or not this will attempt to send haptic RPCs.
+
+ @note Defaults to NO.
+ */
+@property (nonatomic, assign) BOOL enableHapticDataRequests;
+
+/**
Initializes haptic interface. After initializing the application must call updateInterfaceLayout to process the UIWindow. Application must update later view changes in the window by sending SDLDidUpdateProjectionView notification.
@param window UIWindow to be stored in haptic interface
@param connectionManager Object of a class that implements ConnectionManagerType. This is used for RPC communication.
*/
-- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager;
+- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager;
/**
updateInterfaceLayout crawls through the view hierarchy, updates and keep tracks of views to be reported through Haptic RPC. This function is automatically called when SDLDidUpdateProjectionView notification is sent by the application.
diff --git a/SmartDeviceLink/SDLHapticManager.h b/SmartDeviceLink/SDLHapticManager.h
index 96ab95a1a..785234594 100644
--- a/SmartDeviceLink/SDLHapticManager.h
+++ b/SmartDeviceLink/SDLHapticManager.h
@@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLHapticManager : NSObject <SDLHapticInterface, SDLHapticHitTester>
+@property (nonatomic, assign) BOOL enableHapticDataRequests;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLHapticManager.m b/SmartDeviceLink/SDLHapticManager.m
index 95c69454e..d51ce3d69 100644
--- a/SmartDeviceLink/SDLHapticManager.m
+++ b/SmartDeviceLink/SDLHapticManager.m
@@ -45,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
_projectionWindow = window;
_connectionManager = connectionManager;
+ _enableHapticDataRequests = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_projectionViewUpdated:) name:SDLDidUpdateProjectionView object:nil];
return self;
@@ -59,7 +60,7 @@ NS_ASSUME_NONNULL_BEGIN
if (preferredViewIndex != NSNotFound && self.focusableViews.count > 1) {
[self.focusableViews exchangeObjectAtIndex:preferredViewIndex withObjectAtIndex:0];
}
-
+
[self sdl_sendHapticRPC];
}
@@ -79,21 +80,18 @@ NS_ASSUME_NONNULL_BEGIN
}]];
BOOL isButton = [currentView isKindOfClass:[UIButton class]];
- //if current view is focusable and it doesn't have any focusable sub views then add the cuurent view and return
if ((currentView.canBecomeFocused || isButton) && focusableSubviews.count == 0) {
+ //if current view is focusable and it doesn't have any focusable sub views then add the cuurent view and return
[self.focusableViews addObject:currentView];
return;
- }
- // if current view has focusable sub views parse them recursively
- else if (currentView.subviews.count > 0) {
+ } else if (currentView.subviews.count > 0) {
+ // if current view has focusable sub views parse them recursively
NSArray<UIView *> *subviews = currentView.subviews;
for (UIView *childView in subviews) {
[self sdl_parseViewHierarchy:childView];
}
- }
- //else just return
- else {
+ } else {
return;
}
}
@@ -102,6 +100,10 @@ NS_ASSUME_NONNULL_BEGIN
Iterates through the focusable views, extracts rectangular parameters, creates Haptic RPC request and sends it
*/
- (void)sdl_sendHapticRPC {
+ if (!self.enableHapticDataRequests) {
+ return;
+ }
+
NSMutableArray<SDLHapticRect *> *hapticRects = [[NSMutableArray alloc] init];
for (UIView *view in self.focusableViews) {
@@ -119,12 +121,12 @@ NS_ASSUME_NONNULL_BEGIN
}
#pragma mark SDLHapticHitTester functions
-- (nullable UIView *)viewForSDLTouch:(SDLTouch *)touch {
+- (nullable UIView *)viewForPoint:(CGPoint)point {
UIView *selectedView = nil;
for (UIView *view in self.focusableViews) {
//Convert the absolute location to local location and check if that falls within view boundary
- CGPoint localPoint = [view convertPoint:touch.location fromView:self.projectionWindow];
+ CGPoint localPoint = [view convertPoint:point fromView:self.projectionWindow];
if ([view pointInside:localPoint withEvent:nil]) {
if (selectedView != nil) {
selectedView = nil;
diff --git a/SmartDeviceLink/SDLStreamingMediaConfiguration.h b/SmartDeviceLink/SDLStreamingMediaConfiguration.h
index e1bbb881a..fb4ccd888 100644
--- a/SmartDeviceLink/SDLStreamingMediaConfiguration.h
+++ b/SmartDeviceLink/SDLStreamingMediaConfiguration.h
@@ -39,6 +39,17 @@ NS_ASSUME_NONNULL_BEGIN
@property (weak, nonatomic, nullable) id<SDLStreamingMediaManagerDataSource> dataSource;
/**
+ Set the window your video streaming content is within.
+
+ Activates the haptic view parser when set. If the window contains `UIView` based views, these will be discovered and automatically sent to the head unit if it uses a haptic interface. Whether or not it supports the haptic interace, this library will also use that information to attempt to return the touched view to you in `SDLTouchManagerDelegate`.
+
+ @warning Apps using views outside of the `UIView` heirarchy (such as OpenGL) are currently unsupported. If you app uses partial views in the heirarchy, only those views will be discovered. Your OpenGL views will not be discoverable to a haptic interface head unit and you will have to manually make these views discoverable via the `SDLSendHapticData` RPC request.
+
+ @warning This is a weak property and it's therefore your job to hold a strong reference to this window.
+ */
+@property (weak, nonatomic, nullable) UIWindow *window;
+
+/**
Create an insecure video streaming configuration. No security managers will be provided and the encryption flag will be set to None. If you'd like custom video encoder settings, you can set the property manually.
@return The configuration
@@ -51,9 +62,10 @@ NS_ASSUME_NONNULL_BEGIN
@param securityManagers The security managers to use or nil for none.
@param encryptionFlag The maximum encrpytion supported. If the connected head unit supports less than set here, it will still connect, but if it supports more than set here, it will not connect.
@param videoSettings Custom video encoder settings to be used in video streaming.
+ @param window The UIWindow you are running the content that is being streamed on, to use for haptics if needed and possible (only works for UIViews)
@return The configuration
*/
-- (instancetype)initWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *_Nullable)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(NSDictionary<NSString *, id> *_Nullable)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource;
+- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource window:(nullable UIWindow *)window;
/**
Create a secure configuration for each of the security managers provided.
diff --git a/SmartDeviceLink/SDLStreamingMediaConfiguration.m b/SmartDeviceLink/SDLStreamingMediaConfiguration.m
index 93bcf7ebc..d3293bd5a 100644
--- a/SmartDeviceLink/SDLStreamingMediaConfiguration.m
+++ b/SmartDeviceLink/SDLStreamingMediaConfiguration.m
@@ -16,14 +16,14 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLStreamingMediaConfiguration
- (instancetype)init {
- return [self initWithSecurityManagers:nil encryptionFlag:SDLStreamingEncryptionFlagNone videoSettings:nil dataSource:nil];
+ return [self initWithSecurityManagers:nil encryptionFlag:SDLStreamingEncryptionFlagNone videoSettings:nil dataSource:nil window:nil];
}
+ (instancetype)insecureConfiguration {
return [[self alloc] init];
}
-- (instancetype)initWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *_Nullable)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(NSDictionary<NSString *, id> *_Nullable)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource {
+- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *,id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource window:(nullable UIWindow *)window {
self = [super init];
if (!self) {
return nil;
@@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
_maximumDesiredEncryption = encryptionFlag;
_customVideoEncoderSettings = videoSettings;
_dataSource = dataSource;
+ _window = window;
return self;
}
@@ -41,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
NSAssert(securityManagers.count > 0, @"A secure streaming media configuration requires security managers to be passed.");
SDLStreamingEncryptionFlag encryptionFlag = SDLStreamingEncryptionFlagAuthenticateAndEncrypt;
- return [self initWithSecurityManagers:securityManagers encryptionFlag:encryptionFlag videoSettings:nil dataSource:nil];
+ return [self initWithSecurityManagers:securityManagers encryptionFlag:encryptionFlag videoSettings:nil dataSource:nil window:nil];
}
+ (instancetype)secureConfigurationWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *)securityManagers {
@@ -51,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark NSCopying
- (id)copyWithZone:(nullable NSZone *)zone {
- return [[self.class allocWithZone:zone] initWithSecurityManagers:_securityManagers encryptionFlag:_maximumDesiredEncryption videoSettings:_customVideoEncoderSettings dataSource:_dataSource];
+ return [[self.class allocWithZone:zone] initWithSecurityManagers:_securityManagers encryptionFlag:_maximumDesiredEncryption videoSettings:_customVideoEncoderSettings dataSource:_dataSource window:_window];
}
@end
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
index 89da07993..ef8cb57c9 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
@@ -21,6 +21,7 @@
@class SDLTouchManager;
@class SDLVideoStreamingFormat;
+@protocol SDLHapticInterface;
@protocol SDLStreamingMediaManagerDataSource;
NS_ASSUME_NONNULL_BEGIN
@@ -64,6 +65,11 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown;
@property (nonatomic, strong, readonly) SDLTouchManager *touchManager;
/**
+ A haptic interface that can be updated to reparse views within the window you've provided. Send a `SDLDidUpdateProjectionView` notification or call the `updateInterfaceLayout` method to reparse. The "output" of this haptic interface occurs in the `touchManager` property where it will call the delegate.
+ */
+@property (nonatomic, strong, readonly, nullable) id<SDLHapticInterface> hapticInterface;
+
+/**
A data source for the streaming manager's preferred resolutions and preferred formats.
*/
@property (weak, nonatomic, nullable) id<SDLStreamingMediaManagerDataSource> dataSource;
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
index ecbbf88d8..a3c46a9d4 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
@@ -19,6 +19,7 @@
#import "SDLGetSystemCapability.h"
#import "SDLGetSystemCapabilityResponse.h"
#import "SDLGlobals.h"
+#import "SDLHapticManager.h"
#import "SDLHMICapabilities.h"
#import "SDLImageResolution.h"
#import "SDLLogMacros.h"
@@ -103,6 +104,10 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
SDLLogV(@"Creating StreamingLifecycleManager");
_connectionManager = connectionManager;
+ if (configuration.window != nil) {
+ _hapticInterface = [[SDLHapticManager alloc] initWithWindow:configuration.window connectionManager:_connectionManager];
+ }
+
_videoEncoderSettings = configuration.customVideoEncoderSettings ?: SDLH264VideoEncoder.defaultVideoEncoderSettings;
_requestedEncryptionType = configuration.maximumDesiredEncryption;
_dataSource = configuration.dataSource;
@@ -111,7 +116,8 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
_preferredFormatIndex = 0;
_preferredResolutionIndex = 0;
- _touchManager = [[SDLTouchManager alloc] init];
+// __weak typeof(_hapticInterface) weakHaptic = _hapticInterface;
+ _touchManager = [[SDLTouchManager alloc] initWithHitTester:_hapticInterface];
SDLAppState *initialState = SDLAppStateInactive;
switch ([[UIApplication sharedApplication] applicationState]) {
@@ -163,14 +169,23 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
weakSelf.preferredResolutions = [weakSelf.dataSource resolutionFromHeadUnitPreferredResolution:weakSelf.preferredResolutions.firstObject];
}
- SDLLogD(@"Got specialized video capabilites, preferred formats: %@, resolutions: %@", weakSelf.preferredFormats, weakSelf.preferredResolutions);
+ if (weakSelf.hapticInterface != nil) {
+ weakSelf.hapticInterface.enableHapticDataRequests = capability.hapticSpatialDataSupported.boolValue;
+ }
+
+ SDLLogD(@"Got specialized video capabilites, preferred formats: %@, resolutions: %@ haptics enabled %@", weakSelf.preferredFormats, weakSelf.preferredResolutions, (capability.hapticSpatialDataSupported.boolValue ? @"YES" : @"NO"));
} else {
// If we can't get capabilities, we're assuming it's H264 RAW at whatever the display capabilities said in the RAIR. We also aren't going to call the data source because they have no options.
SDLVideoStreamingFormat *format = [[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH264 protocol:SDLVideoStreamingProtocolRAW];
SDLImageResolution *resolution = [[SDLImageResolution alloc] initWithWidth:weakSelf.screenSize.width height:weakSelf.screenSize.height];
weakSelf.preferredFormats = @[format];
weakSelf.preferredResolutions = @[resolution];
- SDLLogD(@"Using generic video capabilites, preferred formats: %@, resolutions: %@", weakSelf.preferredFormats, weakSelf.preferredResolutions);
+
+ if (weakSelf.hapticInterface != nil) {
+ weakSelf.hapticInterface.enableHapticDataRequests = NO;
+ }
+
+ SDLLogD(@"Using generic video capabilites, preferred formats: %@, resolutions: %@, haptics disabled", weakSelf.preferredFormats, weakSelf.preferredResolutions);
}
[weakSelf sdl_startVideoSession];
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h
index 571d4320f..b3cc34ec1 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaManager.h
@@ -16,6 +16,7 @@
@class SDLTouchManager;
@class SDLVideoStreamingFormat;
+@protocol SDLHapticInterface;
@protocol SDLConnectionManagerType;
NS_ASSUME_NONNULL_BEGIN
@@ -30,6 +31,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, readonly) SDLTouchManager *touchManager;
/**
+ A haptic interface that can be updated to reparse views within the window you've provided. Send a `SDLDidUpdateProjectionView` notification or call the `updateInterfaceLayout` method to reparse. The "output" of this haptic interface occurs in the `touchManager` property where it will call the delegate.
+ */
+@property (nonatomic, strong, readonly, nullable) id<SDLHapticInterface> hapticInterface;
+
+/**
* Whether or not video streaming is supported
*
* @see SDLRegisterAppInterface SDLDisplayCapabilities
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m
index 31f69946d..87a277398 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaManager.m
@@ -67,6 +67,10 @@ NS_ASSUME_NONNULL_BEGIN
return self.lifecycleManager.touchManager;
}
+- (nullable id<SDLHapticInterface>)hapticInterface {
+ return self.lifecycleManager.hapticInterface;
+}
+
- (BOOL)isStreamingSupported {
return self.lifecycleManager.isStreamingSupported;
}
diff --git a/SmartDeviceLink/SDLTouchManager.h b/SmartDeviceLink/SDLTouchManager.h
index c81f9e17a..8cf417a2c 100644
--- a/SmartDeviceLink/SDLTouchManager.h
+++ b/SmartDeviceLink/SDLTouchManager.h
@@ -8,10 +8,11 @@
#import <UIKit/UIKit.h>
-#import "SDLTouchManagerDelegate.h"
-
#import "SDLTouchType.h"
+@protocol SDLHapticHitTester;
+@protocol SDLTouchManagerDelegate;
+
@class SDLTouch;
NS_ASSUME_NONNULL_BEGIN
@@ -21,6 +22,9 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
@interface SDLTouchManager : NSObject
+/**
+ Notified of processed touches such as pinches, pans, and taps
+ */
@property (nonatomic, weak, nullable) id<SDLTouchManagerDelegate> touchEventDelegate;
/**
@@ -30,11 +34,9 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
@property (copy, nonatomic, nullable) SDLTouchEventHandler touchEventHandler;
/**
- * @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.
+ Distance between two taps on the screen, in the head unit's coordinate system, used for registering double-tap callbacks.
+
+ @note Defaults to 50 px.
*/
@property (nonatomic, assign) CGFloat tapDistanceThreshold;
@@ -72,6 +74,16 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
*/
- (void)cancelPendingTouches;
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Initialize a touch manager with a hit tester if available
+
+ @param hitTester The hit tester to be used to correlate a point with a view
+ @return The initialized touch manager
+ */
+- (instancetype)initWithHitTester:(nullable id<SDLHapticHitTester>)hitTester;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLTouchManager.m b/SmartDeviceLink/SDLTouchManager.m
index c1f92f2ff..799f930d7 100644
--- a/SmartDeviceLink/SDLTouchManager.m
+++ b/SmartDeviceLink/SDLTouchManager.m
@@ -11,6 +11,7 @@
#import "CGPoint_Util.h"
#import "dispatch_timer.h"
+#import "SDLHapticHitTester.h"
#import "SDLLogMacros.h"
#import "SDLNotificationConstants.h"
#import "SDLOnTouchEvent.h"
@@ -20,6 +21,7 @@
#import "SDLTouch.h"
#import "SDLTouchCoord.h"
#import "SDLTouchEvent.h"
+#import "SDLTouchManagerDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@@ -75,16 +77,22 @@ static NSUInteger const MaximumNumberOfTouches = 2;
*/
@property (nonatomic, assign) SDLPerformingTouchType performingTouchType;
+/**
+ A hit tester that allows us to check for a view based on coordinates, if available.
+ */
+@property (nonatomic, weak, nullable) id<SDLHapticHitTester> hitTester;
+
@end
@implementation SDLTouchManager
-- (instancetype)init {
+- (instancetype)initWithHitTester:(nullable id<SDLHapticHitTester>)hitTester {
self = [super init];
if (!self) {
return nil;
}
+ _hitTester = hitTester;
_movementTimeThreshold = 0.05f;
_tapTimeThreshold = 0.4f;
_tapDistanceThreshold = 50.0f;
@@ -156,8 +164,9 @@ static NSUInteger const MaximumNumberOfTouches = 2;
_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];
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:pinchDidStartInView:atCenterPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:self.currentPinchGesture.center] : nil;
+ [self.touchEventDelegate touchManager:self pinchDidStartInView:hitView atCenterPoint:self.currentPinchGesture.center];
}
} break;
}
@@ -195,9 +204,9 @@ static NSUInteger const MaximumNumberOfTouches = 2;
} break;
case SDLPerformingTouchTypeSingleTouch: {
_performingTouchType = SDLPerformingTouchTypePanningTouch;
- if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidStartAtPoint:)]) {
- [self.touchEventDelegate touchManager:self
- panningDidStartAtPoint:touch.location];
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidStartInView:atPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:touch.location] : nil;
+ [self.touchEventDelegate touchManager:self panningDidStartInView:hitView atPoint:touch.location];
}
} break;
case SDLPerformingTouchTypePanningTouch: {
@@ -223,17 +232,17 @@ static NSUInteger const MaximumNumberOfTouches = 2;
case SDLPerformingTouchTypeMultiTouch: {
[self sdl_setMultiTouchFingerTouchForTouch:touch];
if (self.currentPinchGesture.isValid) {
- if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:pinchDidEndAtCenterPoint:)]) {
- [self.touchEventDelegate touchManager:self
- pinchDidEndAtCenterPoint:self.currentPinchGesture.center];
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:pinchDidEndInView:atCenterPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:self.currentPinchGesture.center] : nil;
+ [self.touchEventDelegate touchManager:self pinchDidEndInView:hitView atCenterPoint:self.currentPinchGesture.center];
}
self.currentPinchGesture = nil;
}
} break;
case SDLPerformingTouchTypePanningTouch: {
- if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidEndAtPoint:)]) {
- [self.touchEventDelegate touchManager:self
- panningDidEndAtPoint:touch.location];
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidEndInView:atPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:touch.location] : nil;
+ [self.touchEventDelegate touchManager:self panningDidEndInView:hitView atPoint:touch.location];
}
} break;
case SDLPerformingTouchTypeSingleTouch: {
@@ -252,9 +261,9 @@ static NSUInteger const MaximumNumberOfTouches = 2;
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];
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveDoubleTapForView:atPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:centerPoint] : nil;
+ [self.touchEventDelegate touchManager:self didReceiveDoubleTapForView:hitView atPoint:centerPoint];
}
}
@@ -335,9 +344,9 @@ static NSUInteger const MaximumNumberOfTouches = 2;
typeof(weakSelf) strongSelf = weakSelf;
strongSelf.singleTapTouch = nil;
[strongSelf sdl_cancelSingleTapTimer];
- if ([strongSelf.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveSingleTapAtPoint:)]) {
- [strongSelf.touchEventDelegate touchManager:strongSelf
- didReceiveSingleTapAtPoint:point];
+ if ([strongSelf.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveSingleTapForView:atPoint:)]) {
+ UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:point] : nil;
+ [strongSelf.touchEventDelegate touchManager:strongSelf didReceiveSingleTapForView:hitView atPoint:point];
}
});
}
diff --git a/SmartDeviceLink/SDLTouchManagerDelegate.h b/SmartDeviceLink/SDLTouchManagerDelegate.h
index bb3b7a9fd..29f53bc02 100644
--- a/SmartDeviceLink/SDLTouchManagerDelegate.h
+++ b/SmartDeviceLink/SDLTouchManagerDelegate.h
@@ -17,77 +17,66 @@ NS_ASSUME_NONNULL_BEGIN
@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.
+ A single tap was received
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under the touch if it could be determined
+ @param point The point at which the touch occurred in the head unit's coordinate system
*/
-- (void)touchManager:(SDLTouchManager *)manager didReceiveSingleTapAtPoint:(CGPoint)point;
+- (void)touchManager:(SDLTouchManager *)manager didReceiveSingleTapForView:(UIView *_Nullable)view atPoint:(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.
+ A double tap was received
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under the touch if it could be determined
+ @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;
+- (void)touchManager:(SDLTouchManager *)manager didReceiveDoubleTapForView:(UIView *_Nullable)view atPoint:(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.
+ Panning started
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under where the panning started if it could be determined
+ @param point Location of the panning start point in the head unit's coordinate system.
*/
-- (void)touchManager:(SDLTouchManager *)manager panningDidStartAtPoint:(CGPoint)point;
+- (void)touchManager:(SDLTouchManager *)manager panningDidStartInView:(UIView *_Nullable)view atPoint:(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.
+ Panning moved between points
+
+ @param manager The 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.
+ Panning ended
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under where the panning ended if it could be determined
+ @param point Location of the panning's end point in the head unit's coordinate system
*/
-- (void)touchManager:(SDLTouchManager *)manager panningDidEndAtPoint:(CGPoint)point;
+- (void)touchManager:(SDLTouchManager *)manager panningDidEndInView:(UIView *_Nullable)view atPoint:(CGPoint)point;
/**
- * @abstract
- * Panning canceled.
- * @param manager
- * Current initalized SDLTouchManager issuing the callback.
- * @param point
- * Location of the panning's end point in the head unit's coordinate system.
+ Panning canceled
+
+ @param manager The SDLTouchManager issuing the callback
+ @param point Location of the panning's end point in the head unit's coordinate system
*/
- (void)touchManager:(SDLTouchManager *)manager panningCanceledAtPoint:(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.
+ Pinch did start
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under the center of the pinch start
+ @param point Center point of the pinch in the head unit's coordinate system
*/
-- (void)touchManager:(SDLTouchManager *)manager pinchDidStartAtCenterPoint:(CGPoint)point;
+- (void)touchManager:(SDLTouchManager *)manager pinchDidStartInView:(UIView *_Nullable)view atCenterPoint:(CGPoint)point;
/**
* @abstract
@@ -102,22 +91,29 @@ NS_ASSUME_NONNULL_BEGIN
- (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.
+ Pinch moved and changed scale
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under the center of the pinch
+ @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 pinchDidEndAtCenterPoint:(CGPoint)point;
+- (void)touchManager:(SDLTouchManager *)manager didReceivePinchInView:(UIView *_Nullable)view atCenterPoint:(CGPoint)point withScale:(CGFloat)scale;
/**
- * @abstract
- * Pinch canceled.
- * @param manager
- * Current initalized SDLTouchManager issuing the callback.
- * @param point
- * Center point of the pinch in the head unit's coordinate system.
+ Pinch did end
+
+ @param manager The SDLTouchManager issuing the callback
+ @param view The view under the center of the pinch
+ @param point Center point of the pinch in the head unit's coordinate system
+ */
+- (void)touchManager:(SDLTouchManager *)manager pinchDidEndInView:(UIView *_Nullable)view atCenterPoint:(CGPoint)point;
+
+/**
+ Pinch canceled
+
+ @param manager The SDLTouchManager issuing the callback
+ @param point Center point of the pinch in the head unit's coordinate system
*/
- (void)touchManager:(SDLTouchManager *)manager pinchCanceledAtCenterPoint:(CGPoint)point;