summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicoleYarroch <nicole@livio.io>2017-10-18 09:03:02 -0400
committerNicoleYarroch <nicole@livio.io>2017-10-18 09:03:02 -0400
commit11d51cf85353b9cf5590576df3ede99b7a60cf64 (patch)
tree8c3b36f818ac64c030784b2ecdde0aa5499e4560
parentecaad9766b6322e36eab046986c3717232003112 (diff)
parent33b596fec70b3f1152cc84cf9aeafbfeca0b046e (diff)
downloadsdl_ios-11d51cf85353b9cf5590576df3ede99b7a60cf64.tar.gz
Merge branch 'release/5.0.0' into example_app/expanded_example_app_5.0.0
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj40
-rw-r--r--SmartDeviceLink/SDLFocusableItemHitTester.h (renamed from SmartDeviceLink/SDLHapticHitTester.h)2
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocator.h (renamed from SmartDeviceLink/SDLHapticManager.h)6
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocator.m (renamed from SmartDeviceLink/SDLHapticManager.m)6
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocatorType.h (renamed from SmartDeviceLink/SDLHapticInterface.h)2
-rw-r--r--SmartDeviceLink/SDLIAPTransport.m246
-rw-r--r--SmartDeviceLink/SDLLifecycleManager.m22
-rw-r--r--SmartDeviceLink/SDLNames.m4
-rw-r--r--SmartDeviceLink/SDLRadioControlData.h2
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.h4
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.m97
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.h4
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.m4
-rw-r--r--SmartDeviceLink/SDLTouchManager.m6
-rw-r--r--SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m28
-rw-r--r--SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m826
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m2
17 files changed, 680 insertions, 621 deletions
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index 13c032e56..666d636c3 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -292,10 +292,10 @@
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 */; };
+ 1FF7DAB61F75B27300B46C30 /* SDLFocusableItemLocatorType.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB51F75B27300B46C30 /* SDLFocusableItemLocatorType.h */; };
+ 1FF7DAB81F75B28E00B46C30 /* SDLFocusableItemHitTester.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB71F75B28E00B46C30 /* SDLFocusableItemHitTester.h */; };
+ 1FF7DABA1F75B2A800B46C30 /* SDLFocusableItemLocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FF7DAB91F75B2A800B46C30 /* SDLFocusableItemLocator.h */; };
+ 1FF7DABC1F75B2BF00B46C30 /* SDLFocusableItemLocator.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF7DABB1F75B2BF00B46C30 /* SDLFocusableItemLocator.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, ); }; };
@@ -1489,10 +1489,10 @@
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>"; };
+ 1FF7DAB51F75B27300B46C30 /* SDLFocusableItemLocatorType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLFocusableItemLocatorType.h; sourceTree = "<group>"; };
+ 1FF7DAB71F75B28E00B46C30 /* SDLFocusableItemHitTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLFocusableItemHitTester.h; sourceTree = "<group>"; };
+ 1FF7DAB91F75B2A800B46C30 /* SDLFocusableItemLocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLFocusableItemLocator.h; sourceTree = "<group>"; };
+ 1FF7DABB1F75B2BF00B46C30 /* SDLFocusableItemLocator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLFocusableItemLocator.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>"; };
@@ -3036,8 +3036,6 @@
5D61FB641A84238B00846EE7 /* SDLProxy.m */,
5D61FB651A84238B00846EE7 /* SDLProxyFactory.h */,
5D61FB661A84238B00846EE7 /* SDLProxyFactory.m */,
- 1FF7DAB91F75B2A800B46C30 /* SDLHapticManager.h */,
- 1FF7DABB1F75B2BF00B46C30 /* SDLHapticManager.m */,
);
name = Proxy;
sourceTree = "<group>";
@@ -3718,8 +3716,6 @@
isa = PBXGroup;
children = (
5D61FB671A84238B00846EE7 /* SDLProxyListener.h */,
- 1FF7DAB71F75B28E00B46C30 /* SDLHapticHitTester.h */,
- 1FF7DAB51F75B27300B46C30 /* SDLHapticInterface.h */,
);
name = "@protocols";
sourceTree = "<group>";
@@ -4158,6 +4154,17 @@
name = "Control Frame Payloads";
sourceTree = "<group>";
};
+ 5DA5918E1F96820F003264C3 /* Focus / Haptic */ = {
+ isa = PBXGroup;
+ children = (
+ 1FF7DAB71F75B28E00B46C30 /* SDLFocusableItemHitTester.h */,
+ 1FF7DAB51F75B27300B46C30 /* SDLFocusableItemLocatorType.h */,
+ 1FF7DAB91F75B2A800B46C30 /* SDLFocusableItemLocator.h */,
+ 1FF7DABB1F75B2BF00B46C30 /* SDLFocusableItemLocator.m */,
+ );
+ name = "Focus / Haptic";
+ sourceTree = "<group>";
+ };
5DAE06711BDEC68700F9B498 /* Developer API Tests */ = {
isa = PBXGroup;
children = (
@@ -4457,6 +4464,7 @@
DA8966E71E56937100413EAB /* Streaming */ = {
isa = PBXGroup;
children = (
+ 5DA5918E1F96820F003264C3 /* Focus / Haptic */,
DAC5724C1D0FE3B60004288B /* Touches */,
DA8966F01E56970C00413EAB /* Utilities */,
DAA41D521DF66B1100BC7337 /* Video Encoding */,
@@ -4584,7 +4592,7 @@
5D61FE0D1A84238C00846EE7 /* SDLVrCapabilities.h in Headers */,
5DBF06271E64A91D00A5CF03 /* SDLLogFileModule.h in Headers */,
5D61FC531A84238C00846EE7 /* SDLButtonEventMode.h in Headers */,
- 1FF7DAB61F75B27300B46C30 /* SDLHapticInterface.h in Headers */,
+ 1FF7DAB61F75B27300B46C30 /* SDLFocusableItemLocatorType.h in Headers */,
5D61FC781A84238C00846EE7 /* SDLDeleteFileResponse.h in Headers */,
5DA240001F325621009C0313 /* SDLStreamingMediaConfiguration.h in Headers */,
5D61FC5F1A84238C00846EE7 /* SDLCharacterSet.h in Headers */,
@@ -4723,7 +4731,7 @@
5DB996601F28C6ED002D8795 /* SDLControlFramePayloadVideoStartServiceAck.h in Headers */,
5DCF76F51ACDBAD300BB647B /* SDLSendLocation.h in Headers */,
5D61FC9E1A84238C00846EE7 /* SDLEncodedSyncPData.h in Headers */,
- 1FF7DABA1F75B2A800B46C30 /* SDLHapticManager.h in Headers */,
+ 1FF7DABA1F75B2A800B46C30 /* SDLFocusableItemLocator.h in Headers */,
5D61FC291A84238C00846EE7 /* SDLAbstractProtocol.h in Headers */,
5D61FDE11A84238C00846EE7 /* SDLTurn.h in Headers */,
5D61FC801A84238C00846EE7 /* SDLDeleteSubMenuResponse.h in Headers */,
@@ -4787,7 +4795,7 @@
5D61FC5D1A84238C00846EE7 /* SDLChangeRegistrationResponse.h in Headers */,
5D61FDCD1A84238C00846EE7 /* SDLTimerMode.h in Headers */,
E9C32B961AB20BA200F283AF /* SDLTimer.h in Headers */,
- 1FF7DAB81F75B28E00B46C30 /* SDLHapticHitTester.h in Headers */,
+ 1FF7DAB81F75B28E00B46C30 /* SDLFocusableItemHitTester.h in Headers */,
5D61FC3D1A84238C00846EE7 /* SDLAlertResponse.h in Headers */,
5D61FDAD1A84238C00846EE7 /* SDLSubscribeButton.h in Headers */,
5D8204261BCEA8A600D0A41B /* SDLPermissionManager.h in Headers */,
@@ -5429,7 +5437,7 @@
5D61FCA41A84238C00846EE7 /* SDLEndAudioPassThru.m in Sources */,
5D8B17541AC9E11B006A6E1C /* SDLDialNumberResponse.m in Sources */,
DA6223BE1E7B088200878689 /* CVPixelBufferRef+SDLUtil.m in Sources */,
- 1FF7DABC1F75B2BF00B46C30 /* SDLHapticManager.m in Sources */,
+ 1FF7DABC1F75B2BF00B46C30 /* SDLFocusableItemLocator.m in Sources */,
EED5CA021F4D18EC00F04000 /* SDLRAWH264Packetizer.m in Sources */,
5D61FC851A84238C00846EE7 /* SDLDeviceLevelStatus.m in Sources */,
5D9FDA981F2A7D3F00A495C8 /* emhashmap.c in Sources */,
diff --git a/SmartDeviceLink/SDLHapticHitTester.h b/SmartDeviceLink/SDLFocusableItemHitTester.h
index 8345d23a4..fe5080500 100644
--- a/SmartDeviceLink/SDLHapticHitTester.h
+++ b/SmartDeviceLink/SDLFocusableItemHitTester.h
@@ -11,7 +11,7 @@
NS_ASSUME_NONNULL_BEGIN
-@protocol SDLHapticHitTester <NSObject>
+@protocol SDLFocusableItemHitTester <NSObject>
/**
Determines which view was selected based on SDLTouch object. If no view gets matched null value will be returned.
diff --git a/SmartDeviceLink/SDLHapticManager.h b/SmartDeviceLink/SDLFocusableItemLocator.h
index 785234594..377b72571 100644
--- a/SmartDeviceLink/SDLHapticManager.h
+++ b/SmartDeviceLink/SDLFocusableItemLocator.h
@@ -7,12 +7,12 @@
#import <UIKit/UIKit.h>
-#import "SDLHapticInterface.h"
-#import "SDLHapticHitTester.h"
+#import "SDLFocusableItemLocatorType.h"
+#import "SDLFocusableItemHitTester.h"
NS_ASSUME_NONNULL_BEGIN
-@interface SDLHapticManager : NSObject <SDLHapticInterface, SDLHapticHitTester>
+@interface SDLFocusableItemLocator : NSObject <SDLFocusableItemLocatorType, SDLFocusableItemHitTester>
@property (nonatomic, assign) BOOL enableHapticDataRequests;
diff --git a/SmartDeviceLink/SDLHapticManager.m b/SmartDeviceLink/SDLFocusableItemLocator.m
index c055bc81a..b6107d686 100644
--- a/SmartDeviceLink/SDLHapticManager.m
+++ b/SmartDeviceLink/SDLFocusableItemLocator.m
@@ -7,7 +7,7 @@
#import <Foundation/Foundation.h>
-#import "SDLHapticManager.h"
+#import "SDLFocusableItemLocator.h"
#import "SDLNotificationConstants.h"
#import "SDLRectangle.h"
#import "SDLHapticRect.h"
@@ -16,7 +16,7 @@
NS_ASSUME_NONNULL_BEGIN
-@interface SDLHapticManager()
+@interface SDLFocusableItemLocator()
/**
The projection window associated with the Haptic Manager
@@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
@end
-@implementation SDLHapticManager
+@implementation SDLFocusableItemLocator
- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager{
self = [super init];
diff --git a/SmartDeviceLink/SDLHapticInterface.h b/SmartDeviceLink/SDLFocusableItemLocatorType.h
index 2b8c3fa83..dc4d9488b 100644
--- a/SmartDeviceLink/SDLHapticInterface.h
+++ b/SmartDeviceLink/SDLFocusableItemLocatorType.h
@@ -12,7 +12,7 @@
NS_ASSUME_NONNULL_BEGIN
-@protocol SDLHapticInterface <NSObject>
+@protocol SDLFocusableItemLocatorType <NSObject>
/**
Whether or not this will attempt to send haptic RPCs.
diff --git a/SmartDeviceLink/SDLIAPTransport.m b/SmartDeviceLink/SDLIAPTransport.m
index c077d05fa..a0474f32e 100644
--- a/SmartDeviceLink/SDLIAPTransport.m
+++ b/SmartDeviceLink/SDLIAPTransport.m
@@ -42,6 +42,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
@implementation SDLIAPTransport
- (instancetype)init {
+ SDLLogV(@"SDLIAPTransport Init");
if (self = [super init]) {
_alreadyDestructed = NO;
_sessionSetupInProgress = NO;
@@ -49,95 +50,137 @@ int const ProtocolIndexTimeoutSeconds = 20;
_controlSession = nil;
_retryCounter = 0;
_protocolIndexTimer = nil;
-
+
+ // Get notifications if an accessory connects in future
[self sdl_startEventListening];
+
+ // Wait for setup to complete before scanning for accessories
}
+
+ return self;
+}
- SDLLogV(@"SDLIAPTransport Init");
+#pragma mark - Background Task
- return self;
+/**
+ * Starts a background task that allows the app to search for accessories and while the app is in the background.
+ */
+- (void)sdl_backgroundTaskStart {
+ if (self.backgroundTaskId != UIBackgroundTaskInvalid) {
+ return;
+ }
+
+ SDLLogD(@"Starting background task");
+ self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:BackgroundTaskName expirationHandler:^{
+ SDLLogD(@"Background task expired");
+ [self sdl_backgroundTaskEnd];
+ }];
}
+/**
+ * Cleans up a background task when it is stopped.
+ */
+- (void)sdl_backgroundTaskEnd {
+ if (self.backgroundTaskId == UIBackgroundTaskInvalid) {
+ return;
+ }
+
+ SDLLogD(@"Ending background task");
+ [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
+ self.backgroundTaskId = UIBackgroundTaskInvalid;
+}
-#pragma mark - Notification Subscriptions
+#pragma mark - Notifications
+#pragma mark Subscription
+
+/**
+ * Registers for system notifications about connected accessories and the app life cycle.
+ */
- (void)sdl_startEventListening {
- SDLLogV(@"SDLIAPTransport Listening For Events");
+ SDLLogV(@"SDLIAPTransport started listening for events");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_accessoryConnected:)
name:EAAccessoryDidConnectNotification
object:nil];
-
+
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_accessoryDisconnected:)
name:EAAccessoryDidDisconnectNotification
object:nil];
-
+
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
-
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(sdl_applicationDidEnterBackground:)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
}
+/**
+ * Unsubscribes to notifications.
+ */
- (void)sdl_stopEventListening {
- SDLLogV(@"SDLIAPTransport Stopped Listening For Events");
+ SDLLogV(@"SDLIAPTransport stopped listening for events");
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-- (void)setSessionSetupInProgress:(BOOL)inProgress{
- _sessionSetupInProgress = inProgress;
- if (!inProgress){
- // End the background task here to catch all cases
- [self sdl_backgroundTaskEnd];
- }
-}
-
-- (void)sdl_backgroundTaskStart {
- if (self.backgroundTaskId != UIBackgroundTaskInvalid) {
- return;
- }
-
- self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:BackgroundTaskName expirationHandler:^{
- [self sdl_backgroundTaskEnd];
- }];
-}
-
-- (void)sdl_backgroundTaskEnd {
- if (self.backgroundTaskId == UIBackgroundTaskInvalid) {
- return;
- }
-
- [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
- self.backgroundTaskId = UIBackgroundTaskInvalid;
-}
-#pragma mark - EAAccessory Notifications
+#pragma mark EAAccessory Notifications
+/**
+ * Handles a notification sent by the system when a new accessory has been detected by attempting to connect to the new accessory.
+ *
+ * @param notification Contains information about the connected accessory
+ */
- (void)sdl_accessoryConnected:(NSNotification *)notification {
EAAccessory *accessory = notification.userInfo[EAAccessoryKey];
- SDLLogD(@"Accessory Connected (%@), Opening in %0.03fs", notification.userInfo[EAAccessoryKey], self.retryDelay);
- [self sdl_backgroundTaskStart];
-
+
+ double retryDelay = self.retryDelay;
+ SDLLogD(@"Accessory Connected (%@), Opening in %0.03fs", notification.userInfo[EAAccessoryKey], retryDelay);
+
+ if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
+ SDLLogD(@"Accessory connected while app is in background. Starting background task.");
+ [self sdl_backgroundTaskStart];
+ }
+
self.retryCounter = 0;
-
- [self performSelector:@selector(sdl_connect:) withObject:accessory afterDelay:self.retryDelay];
+ [self performSelector:@selector(sdl_connect:) withObject:accessory afterDelay:retryDelay];
}
+/**
+ * Handles a notification sent by the system when an accessory has been disconnected by cleaning up after the disconnected device. Only check for the data session, the control session is handled separately
+ *
+ * @param notification Contains information about the connected accessory
+ */
- (void)sdl_accessoryDisconnected:(NSNotification *)notification {
- // Only check for the data session, the control session is handled separately
EAAccessory *accessory = [notification.userInfo objectForKey:EAAccessoryKey];
if (accessory.connectionID != self.session.accessory.connectionID) {
- SDLLogD(@"Accessory Disconnected Event (%@)", accessory);
+ SDLLogD(@"Accessory disconnected event (%@)", accessory);
}
if ([accessory.serialNumber isEqualToString:self.session.accessory.serialNumber]) {
+ SDLLogD(@"Connected accessory disconnected event");
+ self.retryCounter = 0;
self.sessionSetupInProgress = NO;
[self disconnect];
[self.delegate onTransportDisconnected];
}
}
+#pragma mark App Lifecycle Notifications
+
+/**
+ * Handles a notification sent by the system when the app enters the foreground.
+ *
+ * If the app is still searching for an accessory, a background task will be started so the app can still search for and/or connect with an accessory while it is in the background.
+ *
+ * @param notification Notification
+ */
- (void)sdl_applicationWillEnterForeground:(NSNotification *)notification {
SDLLogV(@"App foregrounded, attempting connection");
[self sdl_backgroundTaskEnd];
@@ -145,6 +188,15 @@ int const ProtocolIndexTimeoutSeconds = 20;
[self connect];
}
+/**
+ * Handles a notification sent by the system when the app enters the background.
+ *
+ * @param notification Notification
+ */
+- (void)sdl_applicationDidEnterBackground:(NSNotification *)notification {
+ SDLLogV(@"App backgrounded, starting background task");
+ [self sdl_backgroundTaskStart];
+}
#pragma mark - Stream Lifecycle
@@ -153,9 +205,9 @@ int const ProtocolIndexTimeoutSeconds = 20;
}
/**
- Start the connection process by connecting to a specific accessory, or if none is specified, to scan for an accessory.
-
- @param accessory The accessory to attempt connection with or nil to scan for accessories.
+ * Starts the process to connect to an accessory. If no accessory specified, scans for a valid accessory.
+ *
+ * @param accessory The accessory to attempt connection with or nil to scan for accessories.
*/
- (void)sdl_connect:(nullable EAAccessory *)accessory {
if (!self.session && !self.sessionSetupInProgress) {
@@ -172,10 +224,12 @@ int const ProtocolIndexTimeoutSeconds = 20;
}
}
+/**
+ * Cleans up after a disconnected accessory by closing any open input streams.
+ */
- (void)disconnect {
- SDLLogD(@"IAP disconnecting data session");
- // Stop event listening here so that even if the transport is disconnected by the proxy
- // we unregister for accessory local notifications
+ SDLLogD(@"Disconnecting IAP data session");
+ // Stop event listening here so that even if the transport is disconnected by the proxy we unregister for accessory local notifications
[self sdl_stopEventListening];
if (self.controlSession != nil) {
[self.controlSession stop];
@@ -192,14 +246,13 @@ int const ProtocolIndexTimeoutSeconds = 20;
#pragma mark - Creating Session Streams
/**
- Attempt to connect an accessory using the control or legacy protocols, then return whether or not we've generated an IAP session.
-
- @param accessory The accessory to attempt a connection with
- @return Whether or not we succesfully created a session.
+ * Attempt to connect an accessory using the control or legacy protocols, then return whether or not we've generated an IAP session.
+ *
+ * @param accessory The accessory to attempt a connection with
+ * @return Whether or not we succesfully created a session.
*/
- (BOOL)sdl_connectAccessory:(EAAccessory *)accessory {
BOOL connecting = NO;
-
if ([accessory supportsProtocol:MultiSessionProtocolString] && SDL_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9")) {
[self sdl_createIAPDataSessionWithAccessory:accessory forProtocol:MultiSessionProtocolString];
connecting = YES;
@@ -210,27 +263,27 @@ int const ProtocolIndexTimeoutSeconds = 20;
[self sdl_createIAPDataSessionWithAccessory:accessory forProtocol:LegacyProtocolString];
connecting = YES;
}
-
return connecting;
}
/**
- Attept to establish a session with an accessory, or if nil is passed, to scan for one.
-
- @param accessory The accessory to try to establish a session with, or nil to scan all connected accessories.
+ * Attept to establish a session with an accessory, or if nil is passed, to scan for one.
+ *
+ * @param accessory The accessory to try to establish a session with, or nil to scan all connected accessories.
*/
- (void)sdl_establishSessionWithAccessory:(nullable EAAccessory *)accessory {
SDLLogD(@"Attempting to connect");
if (self.retryCounter < CreateSessionRetries) {
// We should be attempting to connect
self.retryCounter++;
+
EAAccessory *sdlAccessory = accessory;
// If we are being called from sdl_connectAccessory, the EAAccessoryDidConnectNotification will contain the SDL accessory to connect to and we can connect without searching the accessory manager's connected accessory list. Otherwise, we fall through to a search.
if (sdlAccessory != nil && [self sdl_connectAccessory:sdlAccessory]) {
// Connection underway, exit
return;
}
-
+
// Determine if we can start a multi-app session or a legacy (single-app) session
if ((sdlAccessory = [EAAccessoryManager findAccessoryForProtocol:MultiSessionProtocolString]) && SDL_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9")) {
[self sdl_createIAPDataSessionWithAccessory:sdlAccessory forProtocol:MultiSessionProtocolString];
@@ -243,7 +296,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
SDLLogV(@"No accessory supporting SDL was found, dismissing setup");
self.sessionSetupInProgress = NO;
}
-
+
} else {
// We are beyond the number of retries allowed
SDLLogW(@"Surpassed allowed retry attempts");
@@ -254,20 +307,20 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (void)sdl_createIAPControlSessionWithAccessory:(EAAccessory *)accessory {
SDLLogD(@"Starting IAP control session (%@)", accessory);
self.controlSession = [[SDLIAPSession alloc] initWithAccessory:accessory forProtocol:ControlProtocolString];
-
+
if (self.controlSession) {
self.controlSession.delegate = self;
-
+
if (self.protocolIndexTimer == nil) {
self.protocolIndexTimer = [[SDLTimer alloc] initWithDuration:ProtocolIndexTimeoutSeconds repeat:NO];
} else {
[self.protocolIndexTimer cancel];
}
-
+
__weak typeof(self) weakSelf = self;
void (^elapsedBlock)(void) = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
-
+
SDLLogW(@"Control session timeout");
[strongSelf.controlSession stop];
strongSelf.controlSession.streamDelegate = nil;
@@ -275,13 +328,13 @@ int const ProtocolIndexTimeoutSeconds = 20;
[strongSelf sdl_retryEstablishSession];
};
self.protocolIndexTimer.elapsedBlock = elapsedBlock;
-
- SDLStreamDelegate *controlStreamDelegate = [SDLStreamDelegate new];
- self.controlSession.streamDelegate = controlStreamDelegate;
+
+ SDLStreamDelegate *controlStreamDelegate = [[SDLStreamDelegate alloc] init];
controlStreamDelegate.streamHasBytesHandler = [self sdl_controlStreamHasBytesHandlerForAccessory:accessory];
controlStreamDelegate.streamEndHandler = [self sdl_controlStreamEndedHandler];
controlStreamDelegate.streamErrorHandler = [self sdl_controlStreamErroredHandler];
-
+ self.controlSession.streamDelegate = controlStreamDelegate;
+
if (![self.controlSession start]) {
SDLLogW(@"Control session failed to setup (%@)", accessory);
self.controlSession.streamDelegate = nil;
@@ -299,13 +352,13 @@ int const ProtocolIndexTimeoutSeconds = 20;
self.session = [[SDLIAPSession alloc] initWithAccessory:accessory forProtocol:protocol];
if (self.session) {
self.session.delegate = self;
-
+
SDLStreamDelegate *ioStreamDelegate = [[SDLStreamDelegate alloc] init];
self.session.streamDelegate = ioStreamDelegate;
ioStreamDelegate.streamHasBytesHandler = [self sdl_dataStreamHasBytesHandler];
ioStreamDelegate.streamEndHandler = [self sdl_dataStreamEndedHandler];
ioStreamDelegate.streamErrorHandler = [self sdl_dataStreamErroredHandler];
-
+
if (![self.session start]) {
SDLLogW(@"Data session failed to setup (%@)", accessory);
self.session.streamDelegate = nil;
@@ -326,7 +379,9 @@ int const ProtocolIndexTimeoutSeconds = 20;
self.session.delegate = nil;
self.session = nil;
}
- // No accessory to use this time, search connected accessories
+
+ // Search connected accessories
+ self.retryCounter = 0;
[self sdl_connect:nil];
}
@@ -337,7 +392,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
SDLLogD(@"Control Session Established");
[self.protocolIndexTimer start];
}
-
+
// Data Session Opened
if (![ControlProtocolString isEqualToString:session.protocol]) {
self.sessionSetupInProgress = NO;
@@ -365,7 +420,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
if (self.session == nil || !self.session.accessory.connected) {
return;
}
-
+
[self.session sendData:data];
}
@@ -375,11 +430,11 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamEndHandler)sdl_controlStreamEndedHandler {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSStream *stream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogD(@"Control stream ended");
-
+
// End events come in pairs, only perform this once per set.
if (strongSelf.controlSession != nil) {
[strongSelf.protocolIndexTimer cancel];
@@ -393,23 +448,23 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamHasBytesHandler)sdl_controlStreamHasBytesHandlerForAccessory:(EAAccessory *)accessory {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSInputStream *istream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogV(@"Control stream received data");
-
+
// Read in the stream a single byte at a time
uint8_t buf[1];
NSUInteger len = [istream read:buf maxLength:1];
if (len <= 0) {
return;
}
-
+
// If we have data from the stream
// Determine protocol string of the data session, then create that data session
NSString *indexedProtocolString = [NSString stringWithFormat:@"%@%@", IndexedProtocolStringPrefix, @(buf[0])];
SDLLogD(@"Control Stream will switch to protocol %@", indexedProtocolString);
-
+
// Destroy the control session
[strongSelf.protocolIndexTimer cancel];
dispatch_sync(dispatch_get_main_queue(), ^{
@@ -417,9 +472,10 @@ int const ProtocolIndexTimeoutSeconds = 20;
strongSelf.controlSession.streamDelegate = nil;
strongSelf.controlSession = nil;
});
-
+
if (accessory.isConnected) {
dispatch_async(dispatch_get_main_queue(), ^{
+ self.retryCounter = 0;
[strongSelf sdl_createIAPDataSessionWithAccessory:accessory forProtocol:indexedProtocolString];
});
}
@@ -428,11 +484,11 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamErrorHandler)sdl_controlStreamErroredHandler {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSStream *stream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogE(@"Control stream error");
-
+
[strongSelf.protocolIndexTimer cancel];
[strongSelf.controlSession stop];
strongSelf.controlSession.streamDelegate = nil;
@@ -446,7 +502,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamEndHandler)sdl_dataStreamEndedHandler {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSStream *stream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogD(@"Data stream ended");
@@ -464,18 +520,18 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamHasBytesHandler)sdl_dataStreamHasBytesHandler {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSInputStream *istream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
-
+
uint8_t buf[[[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeRPC]];
while (istream.streamStatus == NSStreamStatusOpen && istream.hasBytesAvailable) {
// It is necessary to check the stream status and whether there are bytes available because the dataStreamHasBytesHandler is executed on the IO thread and the accessory disconnect notification arrives on the main thread, causing data to be passed to the delegate while the main thread is tearing down the transport.
-
+
NSInteger bytesRead = [istream read:buf maxLength:[[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeRPC]];
NSData *dataIn = [NSData dataWithBytes:buf length:bytesRead];
SDLLogBytes(dataIn, SDLLogBytesDirectionReceive);
-
+
if (bytesRead > 0) {
[strongSelf.delegate onDataReceived:dataIn];
} else {
@@ -487,7 +543,7 @@ int const ProtocolIndexTimeoutSeconds = 20;
- (SDLStreamErrorHandler)sdl_dataStreamErroredHandler {
__weak typeof(self) weakSelf = self;
-
+
return ^(NSStream *stream) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogE(@"Data stream error");
@@ -506,37 +562,37 @@ int const ProtocolIndexTimeoutSeconds = 20;
const double MinRetrySeconds = 1.5;
const double MaxRetrySeconds = 9.5;
double RetryRangeSeconds = MaxRetrySeconds - MinRetrySeconds;
-
+
static double appDelaySeconds = 0;
-
+
// HAX: This pull the app name and hashes it in an attempt to provide a more even distribution of retry delays. The evidence that this does so is anecdotal. A more ideal solution would be to use a list of known, installed SDL apps on the phone to try and deterministically generate an even delay.
if (appDelaySeconds == 0) {
NSString *appName = [[NSProcessInfo processInfo] processName];
if (appName == nil) {
appName = @"noname";
}
-
+
// Run the app name through an md5 hasher
const char *ptr = [appName UTF8String];
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(ptr, (unsigned int)strlen(ptr), md5Buffer);
-
+
// Generate a string of the hex hash
NSMutableString *output = [NSMutableString stringWithString:@"0x"];
for (int i = 0; i < 8; i++) {
[output appendFormat:@"%02X", md5Buffer[i]];
}
-
+
// Transform the string into a number between 0 and 1
unsigned long long firstHalf;
NSScanner *pScanner = [NSScanner scannerWithString:output];
[pScanner scanHexLongLong:&firstHalf];
double hashBasedValueInRange0to1 = ((double)firstHalf) / 0xffffffffffffffff;
-
+
// Transform the number into a number between min and max
appDelaySeconds = ((RetryRangeSeconds * hashBasedValueInRange0to1) + MinRetrySeconds);
}
-
+
return appDelaySeconds;
}
diff --git a/SmartDeviceLink/SDLLifecycleManager.m b/SmartDeviceLink/SDLLifecycleManager.m
index 6a70e6675..6025e72ab 100644
--- a/SmartDeviceLink/SDLLifecycleManager.m
+++ b/SmartDeviceLink/SDLLifecycleManager.m
@@ -71,7 +71,6 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
// Private properties
@property (copy, nonatomic) SDLManagerReadyBlock readyHandler;
-@property (assign, nonatomic) BOOL firstHMINonNoneOccurred;
@end
@@ -105,7 +104,6 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
_notificationDispatcher = [[SDLNotificationDispatcher alloc] init];
_responseDispatcher = [[SDLResponseDispatcher alloc] initWithNotificationDispatcher:_notificationDispatcher];
_registerResponse = nil;
- _firstHMINonNoneOccurred = NO;
// Managers
_fileManager = [[SDLFileManager alloc] initWithConnectionManager:self];
@@ -184,6 +182,10 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
self.proxy = [SDLProxyFactory buildSDLProxyWithListener:self.notificationDispatcher];
}
#pragma clang diagnostic pop
+
+ if (self.streamManager != nil) {
+ [self.streamManager startWithProtocol:self.proxy.protocol];
+ }
}
- (void)didEnterStateStopped {
@@ -208,7 +210,6 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
self.hmiLevel = nil;
self.audioStreamingState = nil;
self.systemContext = nil;
-
self.proxy = nil;
// Due to a race condition internally with EAStream, we cannot immediately attempt to restart the proxy, as we will randomly crash.
@@ -442,15 +443,6 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
return YES;
}
-- (void)sdl_onFirstHMINonNone {
- // If we are a nav / projection app and desire to stream, we need to be in HMI background, limited, or full and perform additional setup when that occurs
- if (self.streamManager == nil) {
- return;
- }
-
- [self.streamManager startWithProtocol:self.proxy.protocol];
-}
-
#pragma mark SDL notification observers
@@ -461,6 +453,7 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
- (void)transportDidDisconnect {
SDLLogD(@"Transport Disconnected");
+
if (self.lifecycleState == SDLLifecycleStateUnregistering || self.lifecycleState == SDLLifecycleStateStopped) {
[self.lifecycleStateMachine transitionToState:SDLLifecycleStateStopped];
} else {
@@ -485,11 +478,6 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
SDLLogD(@"HMI level changed from %@ to %@", oldHMILevel, self.hmiLevel);
- if (!self.firstHMINonNoneOccurred && ![self.hmiLevel isEqualToEnum:SDLHMILevelNone]) {
- self.firstHMINonNoneOccurred = YES;
- [self sdl_onFirstHMINonNone];
- }
-
if ([self.lifecycleStateMachine isCurrentState:SDLLifecycleStateSettingUpHMI]) {
[self.lifecycleStateMachine transitionToState:SDLLifecycleStateReady];
}
diff --git a/SmartDeviceLink/SDLNames.m b/SmartDeviceLink/SDLNames.m
index a3cd5c758..c2fec2b75 100644
--- a/SmartDeviceLink/SDLNames.m
+++ b/SmartDeviceLink/SDLNames.m
@@ -508,8 +508,8 @@ SDLName const SDLNameUTCYear = @"utcYear";
SDLName const SDLNameValue = @"value";
SDLName const SDLNameVDOP = @"vdop";
SDLName const SDLNameVehicleType = @"vehicleType";
-SDLName const SDLNameVideoCodec = @"videoCodec";
-SDLName const SDLNameVideoProtocol = @"videoProtocol";
+SDLName const SDLNameVideoCodec = @"codec";
+SDLName const SDLNameVideoProtocol = @"protocol";
SDLName const SDLNameVideoStreaming = @"videoStreaming";
SDLName const SDLNameVideoStreamingCapability = @"videoStreamingCapability";
SDLName const SDLNameVentilationMode = @"ventilationMode";
diff --git a/SmartDeviceLink/SDLRadioControlData.h b/SmartDeviceLink/SDLRadioControlData.h
index 693aa4272..f9ff2fd28 100644
--- a/SmartDeviceLink/SDLRadioControlData.h
+++ b/SmartDeviceLink/SDLRadioControlData.h
@@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nullable, strong, nonatomic) NSNumber<SDLInt> *signalChangeThreshold;
/**
- * @abstract True if the radio is on, false is the radio is off
+ * @abstract True if the radio is on, false is the radio is off. When the radio is disabled, no data other than radioEnable is included in a GetInteriorVehicleData response
*
* Boolean value
*/
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
index ef8cb57c9..cdd611200 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
@@ -21,7 +21,7 @@
@class SDLTouchManager;
@class SDLVideoStreamingFormat;
-@protocol SDLHapticInterface;
+@protocol SDLFocusableItemLocatorType;
@protocol SDLStreamingMediaManagerDataSource;
NS_ASSUME_NONNULL_BEGIN
@@ -67,7 +67,7 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown;
/**
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;
+@property (nonatomic, strong, readonly, nullable) id<SDLFocusableItemLocatorType> focusableItemManager;
/**
A data source for the streaming manager's preferred resolutions and preferred formats.
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
index 0d7ca7a01..9e37dd472 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
@@ -19,7 +19,7 @@
#import "SDLGetSystemCapability.h"
#import "SDLGetSystemCapabilityResponse.h"
#import "SDLGlobals.h"
-#import "SDLHapticManager.h"
+#import "SDLFocusableItemLocator.h"
#import "SDLHMICapabilities.h"
#import "SDLImageResolution.h"
#import "SDLLogMacros.h"
@@ -105,9 +105,9 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
_connectionManager = connectionManager;
if (configuration.window != nil) {
- _hapticInterface = [[SDLHapticManager alloc] initWithWindow:configuration.window connectionManager:_connectionManager];
+ _focusableItemManager = [[SDLFocusableItemLocator alloc] initWithWindow:configuration.window connectionManager:_connectionManager];
}
- _touchManager = [[SDLTouchManager alloc] initWithHitTester:(id)_hapticInterface];
+ _touchManager = [[SDLTouchManager alloc] initWithHitTester:(id)_focusableItemManager];
_videoEncoderSettings = configuration.customVideoEncoderSettings ?: SDLH264VideoEncoder.defaultVideoEncoderSettings;
_requestedEncryptionType = configuration.maximumDesiredEncryption;
@@ -150,44 +150,6 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
if (![self.protocol.protocolDelegateTable containsObject:self]) {
[self.protocol.protocolDelegateTable addObject:self];
}
-
- SDLLogD(@"Requesting video capabilities");
- __weak typeof(self) weakSelf = self;
- [self sdl_requestVideoCapabilities:^(SDLVideoStreamingCapability * _Nullable capability) {
- SDLLogD(@"Received video capability response");
- SDLLogV(@"%@", capability);
- if (capability != nil) {
- // If we got a response, get our preferred formats and resolutions
- weakSelf.preferredFormats = capability.supportedFormats;
- weakSelf.preferredResolutions = @[capability.preferredResolution];
-
- if (weakSelf.dataSource != nil) {
- SDLLogV(@"Calling data source for modified preferred formats and resolutions");
- weakSelf.preferredFormats = [weakSelf.dataSource preferredVideoFormatOrderFromHeadUnitPreferredOrder:weakSelf.preferredFormats];
- weakSelf.preferredResolutions = [weakSelf.dataSource resolutionFromHeadUnitPreferredResolution:weakSelf.preferredResolutions.firstObject];
- }
-
- 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];
-
- 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];
- }];
}
- (void)stop {
@@ -196,6 +158,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
[self sdl_stopVideoSession];
self.restartVideoStream = NO;
+ [self.audioStreamStateMachine transitionToState:SDLAudioStreamStateStopped];
[self.videoStreamStateMachine transitionToState:SDLVideoStreamStateStopped];
}
@@ -344,7 +307,43 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
SDLLogD(@"Video stream starting");
self.restartVideoStream = NO;
- [self sdl_sendVideoStartService];
+ __weak typeof(self) weakSelf = self;
+ [self sdl_requestVideoCapabilities:^(SDLVideoStreamingCapability * _Nullable capability) {
+ SDLLogD(@"Received video capability response");
+ SDLLogV(@"Capability: %@", capability);
+
+ if (capability != nil) {
+ // If we got a response, get our preferred formats and resolutions
+ weakSelf.preferredFormats = capability.supportedFormats;
+ weakSelf.preferredResolutions = @[capability.preferredResolution];
+
+ if (weakSelf.dataSource != nil) {
+ SDLLogV(@"Calling data source for modified preferred formats and resolutions");
+ weakSelf.preferredFormats = [weakSelf.dataSource preferredVideoFormatOrderFromHeadUnitPreferredOrder:weakSelf.preferredFormats];
+ weakSelf.preferredResolutions = [weakSelf.dataSource resolutionFromHeadUnitPreferredResolution:weakSelf.preferredResolutions.firstObject];
+ }
+
+ if (weakSelf.focusableItemManager != nil) {
+ weakSelf.focusableItemManager.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];
+
+ if (weakSelf.focusableItemManager != nil) {
+ weakSelf.focusableItemManager.enableHapticDataRequests = NO;
+ }
+
+ SDLLogD(@"Using generic video capabilites, preferred formats: %@, resolutions: %@, haptics disabled", weakSelf.preferredFormats, weakSelf.preferredResolutions);
+ }
+
+ [self sdl_sendVideoStartService];
+ }];
}
- (void)didEnterStateVideoStreamReady {
@@ -608,24 +607,26 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
- (void)sdl_startVideoSession {
SDLLogV(@"Attempting to start video session");
+
if (!self.isStreamingSupported) {
+ SDLLogV(@"Streaming is not supported. Video start service request will not be sent.");
return;
}
if (self.shouldRestartVideoStream && [self.videoStreamStateMachine isCurrentState:SDLVideoStreamStateReady]) {
+ SDLLogV(@"Video needs to be restarted. Stopping video stream.");
[self sdl_stopVideoSession];
return;
}
if ([self.videoStreamStateMachine isCurrentState:SDLVideoStreamStateStopped]
- && self.isHmiStateVideoStreamCapable
- && self.isAppStateVideoStreamCapable) {
+ && self.isHmiStateVideoStreamCapable) {
[self.videoStreamStateMachine transitionToState:SDLVideoStreamStateStarting];
} else {
- SDLLogE(@"Unable to start video stream\n"
- "State: %@\n"
- "HMI state: %@\n"
- "App state: %@", self.videoStreamStateMachine.currentState, self.hmiLevel, self.appStateMachine.currentState);
+ SDLLogE(@"Unable to send video start service request\n"
+ "Video State must be in state STOPPED: %@\n"
+ "HMI state must be LIMITED or FULL: %@\n",
+ self.videoStreamStateMachine.currentState, self.hmiLevel);
}
}
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h
index b3cc34ec1..07d06d1fb 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaManager.h
@@ -16,7 +16,7 @@
@class SDLTouchManager;
@class SDLVideoStreamingFormat;
-@protocol SDLHapticInterface;
+@protocol SDLFocusableItemLocatorType;
@protocol SDLConnectionManagerType;
NS_ASSUME_NONNULL_BEGIN
@@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
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;
+@property (nonatomic, strong, readonly, nullable) id<SDLFocusableItemLocatorType> focusableItemManager;
/**
* Whether or not video streaming is supported
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m
index 87a277398..c9688ea8a 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaManager.m
@@ -67,8 +67,8 @@ NS_ASSUME_NONNULL_BEGIN
return self.lifecycleManager.touchManager;
}
-- (nullable id<SDLHapticInterface>)hapticInterface {
- return self.lifecycleManager.hapticInterface;
+- (nullable id<SDLFocusableItemLocatorType>)focusableItemManager {
+ return self.lifecycleManager.focusableItemManager;
}
- (BOOL)isStreamingSupported {
diff --git a/SmartDeviceLink/SDLTouchManager.m b/SmartDeviceLink/SDLTouchManager.m
index 799f930d7..4c9417961 100644
--- a/SmartDeviceLink/SDLTouchManager.m
+++ b/SmartDeviceLink/SDLTouchManager.m
@@ -11,7 +11,7 @@
#import "CGPoint_Util.h"
#import "dispatch_timer.h"
-#import "SDLHapticHitTester.h"
+#import "SDLFocusableItemHitTester.h"
#import "SDLLogMacros.h"
#import "SDLNotificationConstants.h"
#import "SDLOnTouchEvent.h"
@@ -80,13 +80,13 @@ static NSUInteger const MaximumNumberOfTouches = 2;
/**
A hit tester that allows us to check for a view based on coordinates, if available.
*/
-@property (nonatomic, weak, nullable) id<SDLHapticHitTester> hitTester;
+@property (nonatomic, weak, nullable) id<SDLFocusableItemHitTester> hitTester;
@end
@implementation SDLTouchManager
-- (instancetype)initWithHitTester:(nullable id<SDLHapticHitTester>)hitTester {
+- (instancetype)initWithHitTester:(nullable id<SDLFocusableItemHitTester>)hitTester {
self = [super init];
if (!self) {
return nil;
diff --git a/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m b/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
index 28bc1d4c9..d3a3656ef 100644
--- a/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
+++ b/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
@@ -9,7 +9,7 @@
#import <Nimble/Nimble.h>
#import <OCMock/OCMock.h>
-#import "SDLHapticManager.h"
+#import "SDLFocusableItemLocator.h"
#import "SDLSendHapticData.h"
#import "SDLManager.h"
#import "SDLTouchCoord.h"
@@ -33,7 +33,7 @@ describe(@"the haptic manager", ^{
__block UIWindow *uiWindow;
__block UIViewController *uiViewController;
- __block SDLHapticManager *hapticManager;
+ __block SDLFocusableItemLocator *hapticManager;
__block SDLSendHapticData* sentHapticRequest;
__block id sdlLifecycleManager = OCMClassMock([SDLLifecycleManager class]);
@@ -64,7 +64,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
[uiWindow insertSubview:textField1 aboveSubview:uiWindow];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = NO;
[hapticManager updateInterfaceLayout];
});
@@ -78,7 +78,7 @@ describe(@"the haptic manager", ^{
context(@"when initialized with no focusable view", ^{
beforeEach(^{
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
[hapticManager updateInterfaceLayout];
});
@@ -94,7 +94,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
[uiWindow insertSubview:textField1 aboveSubview:uiWindow];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -121,7 +121,7 @@ describe(@"the haptic manager", ^{
UIButton *button = [[UIButton alloc] initWithFrame:viewRect1];
[uiWindow addSubview:button];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -144,7 +144,7 @@ describe(@"the haptic manager", ^{
context(@"when initialized with no views and then updated with two additional views", ^{
beforeEach(^{
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
@@ -192,7 +192,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[textField addSubview:textField2];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -230,7 +230,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[button addSubview:textField2];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -265,7 +265,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
@@ -296,7 +296,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
[uiViewController.view addSubview:textField1];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
@@ -335,7 +335,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:CGRectMake(201, 201, 50, 50)];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -357,7 +357,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:CGRectMake(126, 126, 50, 50)];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -373,7 +373,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:CGRectMake(101, 101, 50, 50)];
[uiWindow insertSubview:textField1 aboveSubview:uiWindow];
- hapticManager = [[SDLHapticManager alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
diff --git a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
index 93ec5eca7..d20ed828a 100644
--- a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
@@ -17,8 +17,8 @@
#import "SDLGetSystemCapability.h"
#import "SDLGetSystemCapabilityResponse.h"
#import "SDLGlobals.h"
-#import "SDLHapticInterface.h"
-#import "SDLHapticManager.h"
+#import "SDLFocusableItemLocatorType.h"
+#import "SDLFocusableItemLocator.h"
#import "SDLHMILevel.h"
#import "SDLImageResolution.h"
#import "SDLNotificationConstants.h"
@@ -50,30 +50,30 @@ describe(@"the streaming media manager", ^{
__block SDLFakeStreamingManagerDataSource *testDataSource = [[SDLFakeStreamingManagerDataSource alloc] init];
__block NSString *someBackgroundTitleString = nil;
__block TestConnectionManager *testConnectionManager = nil;
-
+
__block void (^sendNotificationForHMILevel)(SDLHMILevel hmiLevel) = ^(SDLHMILevel hmiLevel) {
SDLOnHMIStatus *hmiStatus = [[SDLOnHMIStatus alloc] init];
hmiStatus.hmiLevel = hmiLevel;
SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:self rpcNotification:hmiStatus];
[[NSNotificationCenter defaultCenter] postNotification:notification];
-
+
[NSThread sleepForTimeInterval:0.3];
};
-
+
beforeEach(^{
testConfiguration.customVideoEncoderSettings = @{
- (__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate : @1
- };
+ (__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate : @1
+ };
testConfiguration.dataSource = testDataSource;
testConfiguration.window = testWindow;
someBackgroundTitleString = @"Open Test App";
testConnectionManager = [[TestConnectionManager alloc] init];
streamingLifecycleManager = [[SDLStreamingMediaLifecycleManager alloc] initWithConnectionManager:testConnectionManager configuration:testConfiguration];
});
-
+
it(@"should initialize properties", ^{
expect(streamingLifecycleManager.touchManager).toNot(beNil());
- expect(streamingLifecycleManager.hapticInterface).toNot(beNil());
+ expect(streamingLifecycleManager.focusableItemManager).toNot(beNil());
expect(@(streamingLifecycleManager.isStreamingSupported)).to(equal(@NO));
expect(@(streamingLifecycleManager.isVideoConnected)).to(equal(@NO));
expect(@(streamingLifecycleManager.isAudioConnected)).to(equal(@NO));
@@ -94,20 +94,20 @@ describe(@"the streaming media manager", ^{
expect(streamingLifecycleManager.preferredFormatIndex).to(equal(0));
expect(streamingLifecycleManager.preferredResolutionIndex).to(equal(0));
});
-
+
describe(@"when started", ^{
__block BOOL readyHandlerSuccess = NO;
__block NSError *readyHandlerError = nil;
-
+
__block id protocolMock = OCMClassMock([SDLAbstractProtocol class]);
-
+
beforeEach(^{
readyHandlerSuccess = NO;
readyHandlerError = nil;
-
+
[streamingLifecycleManager startWithProtocol:protocolMock];
});
-
+
it(@"should be ready to stream", ^{
expect(@(streamingLifecycleManager.isStreamingSupported)).to(equal(@NO));
expect(@(streamingLifecycleManager.isVideoConnected)).to(equal(@NO));
@@ -122,63 +122,56 @@ describe(@"the streaming media manager", ^{
expect(streamingLifecycleManager.currentVideoStreamState).to(match(SDLVideoStreamStateStopped));
});
- it(@"should send out a video capabilities request", ^{
- expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLGetSystemCapability class]));
-
- SDLGetSystemCapability *getCapability = (SDLGetSystemCapability *)testConnectionManager.receivedRequests.lastObject;
- expect(getCapability.systemCapabilityType).to(equal(SDLSystemCapabilityTypeVideoStreaming));
- });
-
describe(@"after receiving a register app interface notification", ^{
__block SDLRegisterAppInterfaceResponse *someRegisterAppInterfaceResponse = nil;
__block SDLDisplayCapabilities *someDisplayCapabilities = nil;
__block SDLScreenParams *someScreenParams = nil;
__block SDLImageResolution *someImageResolution = nil;
-
+
beforeEach(^{
someImageResolution = [[SDLImageResolution alloc] init];
someImageResolution.resolutionWidth = @(600);
someImageResolution.resolutionHeight = @(100);
-
+
someScreenParams = [[SDLScreenParams alloc] init];
someScreenParams.resolution = someImageResolution;
});
-
+
context(@"that does not support graphics", ^{
beforeEach(^{
someDisplayCapabilities = [[SDLDisplayCapabilities alloc] init];
someDisplayCapabilities.graphicSupported = @NO;
-
+
someDisplayCapabilities.screenParams = someScreenParams;
-
+
someRegisterAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
someRegisterAppInterfaceResponse.displayCapabilities = someDisplayCapabilities;
SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:someRegisterAppInterfaceResponse];
-
+
[[NSNotificationCenter defaultCenter] postNotification:notification];
[NSThread sleepForTimeInterval:0.1];
});
-
+
it(@"should not support streaming", ^{
expect(@(streamingLifecycleManager.isStreamingSupported)).to(equal(@NO));
});
});
-
+
context(@"that supports graphics", ^{
beforeEach(^{
someDisplayCapabilities = [[SDLDisplayCapabilities alloc] init];
someDisplayCapabilities.graphicSupported = @YES;
-
+
someDisplayCapabilities.screenParams = someScreenParams;
-
+
someRegisterAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
someRegisterAppInterfaceResponse.displayCapabilities = someDisplayCapabilities;
SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:someRegisterAppInterfaceResponse];
-
+
[[NSNotificationCenter defaultCenter] postNotification:notification];
[NSThread sleepForTimeInterval:0.1];
});
-
+
it(@"should support streaming", ^{
expect(@(streamingLifecycleManager.isStreamingSupported)).to(equal(@YES));
expect(@(CGSizeEqualToSize(streamingLifecycleManager.screenSize, CGSizeMake(600, 100)))).to(equal(@YES));
@@ -186,491 +179,504 @@ describe(@"the streaming media manager", ^{
});
});
- describe(@"after sending GetSystemCapabilities", ^{
- context(@"and receiving an error response", ^{
- // This happens if the HU doesn't understand GetSystemCapabilities
- beforeEach(^{
- SDLGenericResponse *genericResponse = [[SDLGenericResponse alloc] init];
- genericResponse.resultCode = SDLResultInvalidData;
+ describe(@"if the app state is active", ^{
+ __block id streamStub = nil;
- [testConnectionManager respondToLastRequestWithResponse:genericResponse];
- });
+ beforeEach(^{
+ streamStub = OCMPartialMock(streamingLifecycleManager);
- it(@"should have correct format and resolution", ^{
- expect(streamingLifecycleManager.preferredFormats).to(haveCount(1));
- expect(streamingLifecycleManager.preferredFormats.firstObject.codec).to(equal(SDLVideoStreamingCodecH264));
- expect(streamingLifecycleManager.preferredFormats.firstObject.protocol).to(equal(SDLVideoStreamingProtocolRAW));
+ OCMStub([streamStub isStreamingSupported]).andReturn(YES);
- expect(streamingLifecycleManager.preferredResolutions).to(haveCount(1));
- expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionWidth).to(equal(0));
- expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionHeight).to(equal(0));
- });
+ [streamingLifecycleManager.appStateMachine setToState:SDLAppStateActive fromOldState:nil callEnterTransition:NO];
});
- context(@"and receiving a response", ^{
- __block SDLImageResolution *resolution = nil;
- __block int32_t maxBitrate = 0;
- __block NSArray<SDLVideoStreamingFormat *> *testFormats = nil;
- __block BOOL testHapticsSupported = NO;
-
+ describe(@"and both streams are open", ^{
beforeEach(^{
- SDLGetSystemCapabilityResponse *response = [[SDLGetSystemCapabilityResponse alloc] init];
- response.success = @YES;
- response.systemCapability = [[SDLSystemCapability alloc] init];
- response.systemCapability.systemCapabilityType = SDLSystemCapabilityTypeVideoStreaming;
-
- resolution = [[SDLImageResolution alloc] initWithWidth:42 height:69];
- maxBitrate = 12345;
- testFormats = @[[[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH265 protocol:SDLVideoStreamingProtocolRTMP], [[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH264 protocol:SDLVideoStreamingProtocolRTP]];
- testHapticsSupported = YES;
- response.systemCapability.videoStreamingCapability = [[SDLVideoStreamingCapability alloc] initWithPreferredResolution:resolution maxBitrate:maxBitrate supportedFormats:testFormats hapticDataSupported:testHapticsSupported];
- [testConnectionManager respondToLastRequestWithResponse:response];
- });
-
- it(@"should have set correct data", ^{
- // Correct formats should be retrieved from the data source
- expect(streamingLifecycleManager.preferredResolutions).to(haveCount(1));
- expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionWidth).to(equal(resolution.resolutionWidth));
- expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionHeight).to(equal(resolution.resolutionHeight));
-
- expect(streamingLifecycleManager.preferredFormats).to(haveCount(streamingLifecycleManager.supportedFormats.count + 1));
- expect(streamingLifecycleManager.preferredFormats.firstObject.codec).to(equal(testDataSource.extraFormat.codec));
- expect(streamingLifecycleManager.preferredFormats.firstObject.protocol).to(equal(testDataSource.extraFormat.protocol));
-
- // The haptic manager should be enabled
- expect(streamingLifecycleManager.hapticInterface.enableHapticDataRequests).to(equal(YES));
+ [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateReady fromOldState:nil callEnterTransition:NO];
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateReady fromOldState:nil callEnterTransition:NO];
});
- describe(@"if the app state is active", ^{
- __block id streamStub = nil;
-
+ describe(@"and the hmi state is limited", ^{
beforeEach(^{
- streamStub = OCMPartialMock(streamingLifecycleManager);
-
- OCMStub([streamStub isStreamingSupported]).andReturn(YES);
-
- [streamingLifecycleManager.appStateMachine setToState:SDLAppStateActive fromOldState:nil callEnterTransition:NO];
+ streamingLifecycleManager.hmiLevel = SDLHMILevelLimited;
});
- describe(@"and both streams are open", ^{
- beforeEach(^{
- [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateReady fromOldState:nil callEnterTransition:NO];
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateReady fromOldState:nil callEnterTransition:NO];
+ describe(@"and the hmi state changes to", ^{
+ context(@"none", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelNone);
+ });
+
+ it(@"should close only the video stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
+ });
});
- describe(@"and the hmi state is limited", ^{
+ context(@"background", ^{
beforeEach(^{
- streamingLifecycleManager.hmiLevel = SDLHMILevelLimited;
+ sendNotificationForHMILevel(SDLHMILevelBackground);
});
- describe(@"and the hmi state changes to", ^{
- context(@"none", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelNone);
- });
-
- it(@"should close only the video stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
- });
- });
-
- context(@"background", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelBackground);
- });
-
- it(@"should close only the video stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
- });
- });
-
- context(@"limited", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelLimited);
- });
-
- it(@"should not close either stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
- });
- });
-
- context(@"full", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelFull);
- });
-
- it(@"should not close either stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
- });
- });
+ it(@"should close only the video stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
+ });
+ });
+
+ context(@"limited", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelLimited);
});
- describe(@"and the app state changes to", ^{
- context(@"inactive", ^{
- beforeEach(^{
- [streamingLifecycleManager.appStateMachine setToState:SDLAppStateInactive fromOldState:nil callEnterTransition:YES];
- });
-
- it(@"should flag to restart the video stream", ^{
- expect(@(streamingLifecycleManager.shouldRestartVideoStream)).to(equal(@YES));
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
- });
- });
+ it(@"should not close either stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
});
});
- describe(@"and the hmi state is full", ^{
+ context(@"full", ^{
beforeEach(^{
- streamingLifecycleManager.hmiLevel = SDLHMILevelFull;
+ sendNotificationForHMILevel(SDLHMILevelFull);
});
- context(@"and hmi state changes to none", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelNone);
- });
-
- it(@"should close only the video stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
- });
+ it(@"should not close either stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
});
+ });
+ });
- context(@"and hmi state changes to background", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelBackground);
- });
+ describe(@"and the app state changes to", ^{
+ context(@"inactive", ^{
+ beforeEach(^{
+ [streamingLifecycleManager.appStateMachine setToState:SDLAppStateInactive fromOldState:nil callEnterTransition:YES];
+ });
- it(@"should close only the video stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
- });
+ it(@"should flag to restart the video stream", ^{
+ expect(@(streamingLifecycleManager.shouldRestartVideoStream)).to(equal(@YES));
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
});
+ });
+ });
+ });
- context(@"and hmi state changes to limited", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelLimited);
- });
+ describe(@"and the hmi state is full", ^{
+ beforeEach(^{
+ streamingLifecycleManager.hmiLevel = SDLHMILevelFull;
+ });
- it(@"should not close either stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
- });
- });
+ context(@"and hmi state changes to none", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelNone);
+ });
- context(@"and hmi state changes to full", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelFull);
- });
+ it(@"should close only the video stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
+ });
+ });
- it(@"should not close either stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
- });
- });
+ context(@"and hmi state changes to background", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelBackground);
+ });
+
+ it(@"should close only the video stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown));
});
});
- describe(@"and both streams are closed", ^{
+ context(@"and hmi state changes to limited", ^{
beforeEach(^{
- [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateStopped fromOldState:nil callEnterTransition:NO];
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStopped fromOldState:nil callEnterTransition:NO];
+ sendNotificationForHMILevel(SDLHMILevelLimited);
});
- describe(@"and the hmi state is none", ^{
- beforeEach(^{
- streamingLifecycleManager.hmiLevel = SDLHMILevelNone;
- });
+ it(@"should not close either stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ });
+ });
- context(@"and hmi state changes to none", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelNone);
- });
+ context(@"and hmi state changes to full", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelFull);
+ });
- it(@"should only start the audio stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
- });
- });
+ it(@"should not close either stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ });
+ });
+ });
+ });
- context(@"and hmi state changes to background", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelBackground);
- });
+ describe(@"and both streams are closed", ^{
+ beforeEach(^{
+ [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateStopped fromOldState:nil callEnterTransition:NO];
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStopped fromOldState:nil callEnterTransition:NO];
+ });
- it(@"should only start the audio stream", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
- });
- });
-
- context(@"and hmi state changes to limited", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelLimited);
- });
-
- it(@"should start both streams", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStarting));
- });
- });
-
- context(@"and hmi state changes to full", ^{
- beforeEach(^{
- sendNotificationForHMILevel(SDLHMILevelFull);
- });
-
- it(@"should start both streams", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStarting));
- });
-
- it(@"should have decided upon the correct preferred format and resolution", ^{
- SDLVideoStreamingFormat *preferredFormat = streamingLifecycleManager.preferredFormats[streamingLifecycleManager.preferredFormatIndex];
- expect(preferredFormat.codec).to(equal(SDLVideoStreamingCodecH264));
- expect(preferredFormat.protocol).to(equal(SDLVideoStreamingProtocolRTP));
-
- SDLImageResolution *preferredResolution = streamingLifecycleManager.preferredResolutions[streamingLifecycleManager.preferredResolutionIndex];
- expect(preferredResolution.resolutionHeight).to(equal(@69));
- expect(preferredResolution.resolutionWidth).to(equal(@42));
- });
- });
+ describe(@"and the hmi state is none", ^{
+ beforeEach(^{
+ streamingLifecycleManager.hmiLevel = SDLHMILevelNone;
+ });
+
+ context(@"and hmi state changes to none", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelNone);
+ });
+
+ it(@"should only start the audio stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ });
+ });
+
+ context(@"and hmi state changes to background", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelBackground);
+ });
+
+ it(@"should only start the audio stream", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ });
+ });
+
+ context(@"and hmi state changes to limited", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelLimited);
+ });
+
+ it(@"should start both streams", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStarting));
+ });
+ });
+
+ context(@"and hmi state changes to full", ^{
+ beforeEach(^{
+ sendNotificationForHMILevel(SDLHMILevelFull);
+ });
+
+ it(@"should start both streams", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStarting));
});
});
});
});
});
- describe(@"after receiving a Video Start ACK", ^{
- __block SDLProtocolHeader *testVideoHeader = nil;
- __block SDLProtocolMessage *testVideoMessage = nil;
- __block SDLControlFramePayloadVideoStartServiceAck *testVideoStartServicePayload = nil;
- __block int64_t testMTU = 789456;
- __block int32_t testVideoHeight = 42;
- __block int32_t testVideoWidth = 32;
- __block SDLVideoStreamingCodec testVideoCodec = SDLVideoStreamingCodecH264;
- __block SDLVideoStreamingProtocol testVideoProtocol = SDLVideoStreamingProtocolRTP;
-
+ describe(@"sending a video capabilities request", ^{
beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:YES];
+ });
- testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testVideoHeader.frameType = SDLFrameTypeSingle;
- testVideoHeader.frameData = SDLFrameInfoStartServiceACK;
- testVideoHeader.encrypted = YES;
- testVideoHeader.serviceType = SDLServiceTypeVideo;
+ it(@"should send out a video capabilities request", ^{
+ expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLGetSystemCapability class]));
+
+ SDLGetSystemCapability *getCapability = (SDLGetSystemCapability *)testConnectionManager.receivedRequests.lastObject;
+ expect(getCapability.systemCapabilityType).to(equal(SDLSystemCapabilityTypeVideoStreaming));
});
- context(@"with data", ^{
- beforeEach(^{
- testVideoStartServicePayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:testVideoHeight width:testVideoWidth protocol:testVideoProtocol codec:testVideoCodec];
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartServicePayload.data];
- [streamingLifecycleManager handleProtocolStartServiceACKMessage:testVideoMessage];
+ describe(@"after sending GetSystemCapabilities", ^{
+ context(@"and receiving an error response", ^{
+ // This happens if the HU doesn't understand GetSystemCapabilities
+ beforeEach(^{
+ SDLGenericResponse *genericResponse = [[SDLGenericResponse alloc] init];
+ genericResponse.resultCode = SDLResultInvalidData;
+
+ [testConnectionManager respondToLastRequestWithResponse:genericResponse];
+ });
+
+ it(@"should have correct format and resolution", ^{
+ expect(streamingLifecycleManager.preferredFormats).to(haveCount(1));
+ expect(streamingLifecycleManager.preferredFormats.firstObject.codec).to(equal(SDLVideoStreamingCodecH264));
+ expect(streamingLifecycleManager.preferredFormats.firstObject.protocol).to(equal(SDLVideoStreamingProtocolRAW));
+
+ expect(streamingLifecycleManager.preferredResolutions).to(haveCount(1));
+ expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionWidth).to(equal(0));
+ expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionHeight).to(equal(0));
+ });
});
- it(@"should have set all the right properties", ^{
- expect([[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeVideo]).to(equal(testMTU));
- expect(CGSizeEqualToSize(streamingLifecycleManager.screenSize, CGSizeMake(testVideoWidth, testVideoHeight))).to(equal(YES));
- expect(streamingLifecycleManager.videoEncrypted).to(equal(YES));
- expect(streamingLifecycleManager.videoFormat).to(equal([[SDLVideoStreamingFormat alloc] initWithCodec:testVideoCodec protocol:testVideoProtocol]));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ context(@"and receiving a response", ^{
+ __block SDLImageResolution *resolution = nil;
+ __block int32_t maxBitrate = 0;
+ __block NSArray<SDLVideoStreamingFormat *> *testFormats = nil;
+ __block BOOL testHapticsSupported = NO;
+
+ beforeEach(^{
+ SDLGetSystemCapabilityResponse *response = [[SDLGetSystemCapabilityResponse alloc] init];
+ response.success = @YES;
+ response.systemCapability = [[SDLSystemCapability alloc] init];
+ response.systemCapability.systemCapabilityType = SDLSystemCapabilityTypeVideoStreaming;
+
+ resolution = [[SDLImageResolution alloc] initWithWidth:42 height:69];
+ maxBitrate = 12345;
+ testFormats = @[[[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH265 protocol:SDLVideoStreamingProtocolRTMP], [[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH264 protocol:SDLVideoStreamingProtocolRTP]];
+ testHapticsSupported = YES;
+ response.systemCapability.videoStreamingCapability = [[SDLVideoStreamingCapability alloc] initWithPreferredResolution:resolution maxBitrate:maxBitrate supportedFormats:testFormats hapticDataSupported:testHapticsSupported];
+ [testConnectionManager respondToLastRequestWithResponse:response];
+ });
+
+ it(@"should have correct data from the data source", ^{
+ // Correct formats should be retrieved from the data source
+ expect(streamingLifecycleManager.preferredResolutions).to(haveCount(1));
+ expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionWidth).to(equal(resolution.resolutionWidth));
+ expect(streamingLifecycleManager.preferredResolutions.firstObject.resolutionHeight).to(equal(resolution.resolutionHeight));
+
+ expect(streamingLifecycleManager.preferredFormats).to(haveCount(streamingLifecycleManager.supportedFormats.count + 1));
+ expect(streamingLifecycleManager.preferredFormats.firstObject.codec).to(equal(testDataSource.extraFormat.codec));
+ expect(streamingLifecycleManager.preferredFormats.firstObject.protocol).to(equal(testDataSource.extraFormat.protocol));
+
+ // The haptic manager should be enabled
+ expect(streamingLifecycleManager.focusableItemManager.enableHapticDataRequests).to(equal(YES));
+ });
+
+ it(@"should have decided upon the correct preferred format and resolution", ^{
+ SDLVideoStreamingFormat *preferredFormat = streamingLifecycleManager.preferredFormats[streamingLifecycleManager.preferredFormatIndex];
+ expect(preferredFormat.codec).to(equal(SDLVideoStreamingCodecH264));
+ expect(preferredFormat.protocol).to(equal(SDLVideoStreamingProtocolRTP));
+
+ SDLImageResolution *preferredResolution = streamingLifecycleManager.preferredResolutions[streamingLifecycleManager.preferredResolutionIndex];
+ expect(preferredResolution.resolutionHeight).to(equal(@69));
+ expect(preferredResolution.resolutionWidth).to(equal(@42));
+ });
});
});
- context(@"with missing data", ^{
+ describe(@"after receiving a Video Start ACK", ^{
+ __block SDLProtocolHeader *testVideoHeader = nil;
+ __block SDLProtocolMessage *testVideoMessage = nil;
+ __block SDLControlFramePayloadVideoStartServiceAck *testVideoStartServicePayload = nil;
+ __block int64_t testMTU = 789456;
+ __block int32_t testVideoHeight = 42;
+ __block int32_t testVideoWidth = 32;
+ __block SDLVideoStreamingCodec testVideoCodec = SDLVideoStreamingCodecH264;
+ __block SDLVideoStreamingProtocol testVideoProtocol = SDLVideoStreamingProtocolRTP;
+
beforeEach(^{
- testVideoStartServicePayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:testVideoHeight width:testVideoWidth protocol:nil codec:nil];
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartServicePayload.data];
- [streamingLifecycleManager handleProtocolStartServiceACKMessage:testVideoMessage];
- });
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
- it(@"should fall back correctly", ^{
- expect(CGSizeEqualToSize(streamingLifecycleManager.screenSize, CGSizeMake(testVideoWidth, testVideoHeight))).to(equal(YES));
- expect(streamingLifecycleManager.videoFormat).to(equal([[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH264 protocol:SDLVideoStreamingProtocolRAW]));
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testVideoHeader.frameType = SDLFrameTypeSingle;
+ testVideoHeader.frameData = SDLFrameInfoStartServiceACK;
+ testVideoHeader.encrypted = YES;
+ testVideoHeader.serviceType = SDLServiceTypeVideo;
});
- });
- });
- describe(@"after receiving a Video Start NAK", ^{
- __block SDLProtocolHeader *testVideoHeader = nil;
- __block SDLProtocolMessage *testVideoMessage = nil;
- __block SDLControlFramePayloadNak *testVideoStartNakPayload = nil;
+ context(@"with data", ^{
+ beforeEach(^{
+ testVideoStartServicePayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:testVideoHeight width:testVideoWidth protocol:testVideoProtocol codec:testVideoCodec];
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartServicePayload.data];
+ [streamingLifecycleManager handleProtocolStartServiceACKMessage:testVideoMessage];
+ });
+
+ it(@"should have set all the right properties", ^{
+ expect([[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeVideo]).to(equal(testMTU));
+ expect(CGSizeEqualToSize(streamingLifecycleManager.screenSize, CGSizeMake(testVideoWidth, testVideoHeight))).to(equal(YES));
+ expect(streamingLifecycleManager.videoEncrypted).to(equal(YES));
+ expect(streamingLifecycleManager.videoFormat).to(equal([[SDLVideoStreamingFormat alloc] initWithCodec:testVideoCodec protocol:testVideoProtocol]));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ });
+ });
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ context(@"with missing data", ^{
+ beforeEach(^{
+ testVideoStartServicePayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:testVideoHeight width:testVideoWidth protocol:nil codec:nil];
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartServicePayload.data];
+ [streamingLifecycleManager handleProtocolStartServiceACKMessage:testVideoMessage];
+ });
- testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testVideoHeader.frameType = SDLFrameTypeSingle;
- testVideoHeader.frameData = SDLFrameInfoStartServiceACK;
- testVideoHeader.encrypted = YES;
- testVideoHeader.serviceType = SDLServiceTypeVideo;
+ it(@"should fall back correctly", ^{
+ expect(CGSizeEqualToSize(streamingLifecycleManager.screenSize, CGSizeMake(testVideoWidth, testVideoHeight))).to(equal(YES));
+ expect(streamingLifecycleManager.videoFormat).to(equal([[SDLVideoStreamingFormat alloc] initWithCodec:SDLVideoStreamingCodecH264 protocol:SDLVideoStreamingProtocolRAW]));
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateReady));
+ });
+ });
});
- context(@"with data", ^{
+ describe(@"after receiving a Video Start NAK", ^{
+ __block SDLProtocolHeader *testVideoHeader = nil;
+ __block SDLProtocolMessage *testVideoMessage = nil;
+ __block SDLControlFramePayloadNak *testVideoStartNakPayload = nil;
+
beforeEach(^{
- testVideoStartNakPayload = [[SDLControlFramePayloadNak alloc] initWithRejectedParams:@[[NSString stringWithUTF8String:SDLControlFrameHeightKey], [NSString stringWithUTF8String:SDLControlFrameVideoCodecKey]]];
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartNakPayload.data];
- [streamingLifecycleManager handleProtocolStartServiceNAKMessage:testVideoMessage];
- });
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
- it(@"should have retried with new properties", ^{
- expect(streamingLifecycleManager.preferredResolutionIndex).to(equal(1));
- expect(streamingLifecycleManager.preferredFormatIndex).to(equal(1));
+ testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testVideoHeader.frameType = SDLFrameTypeSingle;
+ testVideoHeader.frameData = SDLFrameInfoStartServiceACK;
+ testVideoHeader.encrypted = YES;
+ testVideoHeader.serviceType = SDLServiceTypeVideo;
});
- });
- context(@"with missing data", ^{
- beforeEach(^{
- testVideoStartNakPayload = [[SDLControlFramePayloadNak alloc] initWithRejectedParams:nil];
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartNakPayload.data];
- [streamingLifecycleManager handleProtocolStartServiceNAKMessage:testVideoMessage];
+ context(@"with data", ^{
+ beforeEach(^{
+ testVideoStartNakPayload = [[SDLControlFramePayloadNak alloc] initWithRejectedParams:@[[NSString stringWithUTF8String:SDLControlFrameHeightKey], [NSString stringWithUTF8String:SDLControlFrameVideoCodecKey]]];
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartNakPayload.data];
+ [streamingLifecycleManager handleProtocolStartServiceNAKMessage:testVideoMessage];
+ });
+
+ it(@"should have retried with new properties", ^{
+ expect(streamingLifecycleManager.preferredResolutionIndex).to(equal(1));
+ expect(streamingLifecycleManager.preferredFormatIndex).to(equal(1));
+ });
});
- it(@"should end the service", ^{
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ context(@"with missing data", ^{
+ beforeEach(^{
+ testVideoStartNakPayload = [[SDLControlFramePayloadNak alloc] initWithRejectedParams:nil];
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:testVideoStartNakPayload.data];
+ [streamingLifecycleManager handleProtocolStartServiceNAKMessage:testVideoMessage];
+ });
+
+ it(@"should end the service", ^{
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ });
});
});
- });
- describe(@"after receiving a video end ACK", ^{
- __block SDLProtocolHeader *testVideoHeader = nil;
- __block SDLProtocolMessage *testVideoMessage = nil;
+ describe(@"after receiving a video end ACK", ^{
+ __block SDLProtocolHeader *testVideoHeader = nil;
+ __block SDLProtocolMessage *testVideoMessage = nil;
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testVideoHeader.frameType = SDLFrameTypeSingle;
- testVideoHeader.frameData = SDLFrameInfoEndServiceACK;
- testVideoHeader.encrypted = NO;
- testVideoHeader.serviceType = SDLServiceTypeVideo;
+ testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testVideoHeader.frameType = SDLFrameTypeSingle;
+ testVideoHeader.frameData = SDLFrameInfoEndServiceACK;
+ testVideoHeader.encrypted = NO;
+ testVideoHeader.serviceType = SDLServiceTypeVideo;
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:nil];
- [streamingLifecycleManager handleProtocolEndServiceACKMessage:testVideoMessage];
- });
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:nil];
+ [streamingLifecycleManager handleProtocolEndServiceACKMessage:testVideoMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ it(@"should have set all the right properties", ^{
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ });
});
- });
- describe(@"after receiving a video end NAK", ^{
- __block SDLProtocolHeader *testVideoHeader = nil;
- __block SDLProtocolMessage *testVideoMessage = nil;
+ describe(@"after receiving a video end NAK", ^{
+ __block SDLProtocolHeader *testVideoHeader = nil;
+ __block SDLProtocolMessage *testVideoMessage = nil;
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLVideoStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testVideoHeader.frameType = SDLFrameTypeSingle;
- testVideoHeader.frameData = SDLFrameInfoEndServiceNACK;
- testVideoHeader.encrypted = NO;
- testVideoHeader.serviceType = SDLServiceTypeVideo;
+ testVideoHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testVideoHeader.frameType = SDLFrameTypeSingle;
+ testVideoHeader.frameData = SDLFrameInfoEndServiceNACK;
+ testVideoHeader.encrypted = NO;
+ testVideoHeader.serviceType = SDLServiceTypeVideo;
- testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:nil];
- [streamingLifecycleManager handleProtocolEndServiceNAKMessage:testVideoMessage];
- });
+ testVideoMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testVideoHeader andPayload:nil];
+ [streamingLifecycleManager handleProtocolEndServiceNAKMessage:testVideoMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ it(@"should have set all the right properties", ^{
+ expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped));
+ });
});
- });
- describe(@"after receiving an Audio Start ACK", ^{
- __block SDLProtocolHeader *testAudioHeader = nil;
- __block SDLProtocolMessage *testAudioMessage = nil;
- __block SDLControlFramePayloadAudioStartServiceAck *testAudioStartServicePayload = nil;
- __block int64_t testMTU = 786579;
+ describe(@"after receiving an Audio Start ACK", ^{
+ __block SDLProtocolHeader *testAudioHeader = nil;
+ __block SDLProtocolMessage *testAudioMessage = nil;
+ __block SDLControlFramePayloadAudioStartServiceAck *testAudioStartServicePayload = nil;
+ __block int64_t testMTU = 786579;
- beforeEach(^{
- [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.audioStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testAudioHeader.frameType = SDLFrameTypeSingle;
- testAudioHeader.frameData = SDLFrameInfoStartServiceACK;
- testAudioHeader.encrypted = YES;
- testAudioHeader.serviceType = SDLServiceTypeAudio;
+ testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testAudioHeader.frameType = SDLFrameTypeSingle;
+ testAudioHeader.frameData = SDLFrameInfoStartServiceACK;
+ testAudioHeader.encrypted = YES;
+ testAudioHeader.serviceType = SDLServiceTypeAudio;
- testAudioStartServicePayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithMTU:testMTU];
- testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:testAudioStartServicePayload.data];
- [streamingLifecycleManager handleProtocolStartServiceACKMessage:testAudioMessage];
- });
+ testAudioStartServicePayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithMTU:testMTU];
+ testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:testAudioStartServicePayload.data];
+ [streamingLifecycleManager handleProtocolStartServiceACKMessage:testAudioMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect([[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeAudio]).to(equal(testMTU));
- expect(streamingLifecycleManager.audioEncrypted).to(equal(YES));
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ it(@"should have set all the right properties", ^{
+ expect([[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeAudio]).to(equal(testMTU));
+ expect(streamingLifecycleManager.audioEncrypted).to(equal(YES));
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady));
+ });
});
- });
- describe(@"after receiving an Audio Start NAK", ^{
- __block SDLProtocolHeader *testAudioHeader = nil;
- __block SDLProtocolMessage *testAudioMessage = nil;
+ describe(@"after receiving an Audio Start NAK", ^{
+ __block SDLProtocolHeader *testAudioHeader = nil;
+ __block SDLProtocolMessage *testAudioMessage = nil;
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testAudioHeader.frameType = SDLFrameTypeSingle;
- testAudioHeader.frameData = SDLFrameInfoStartServiceNACK;
- testAudioHeader.encrypted = NO;
- testAudioHeader.serviceType = SDLServiceTypeAudio;
+ testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testAudioHeader.frameType = SDLFrameTypeSingle;
+ testAudioHeader.frameData = SDLFrameInfoStartServiceNACK;
+ testAudioHeader.encrypted = NO;
+ testAudioHeader.serviceType = SDLServiceTypeAudio;
- testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
- [streamingLifecycleManager handleProtocolEndServiceACKMessage:testAudioMessage];
- });
+ testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
+ [streamingLifecycleManager handleProtocolEndServiceACKMessage:testAudioMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ it(@"should have set all the right properties", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ });
});
- });
- describe(@"after receiving a audio end ACK", ^{
- __block SDLProtocolHeader *testAudioHeader = nil;
- __block SDLProtocolMessage *testAudioMessage = nil;
+ describe(@"after receiving a audio end ACK", ^{
+ __block SDLProtocolHeader *testAudioHeader = nil;
+ __block SDLProtocolMessage *testAudioMessage = nil;
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testAudioHeader.frameType = SDLFrameTypeSingle;
- testAudioHeader.frameData = SDLFrameInfoEndServiceACK;
- testAudioHeader.encrypted = NO;
- testAudioHeader.serviceType = SDLServiceTypeAudio;
+ testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testAudioHeader.frameType = SDLFrameTypeSingle;
+ testAudioHeader.frameData = SDLFrameInfoEndServiceACK;
+ testAudioHeader.encrypted = NO;
+ testAudioHeader.serviceType = SDLServiceTypeAudio;
- testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
- [streamingLifecycleManager handleProtocolEndServiceACKMessage:testAudioMessage];
- });
+ testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
+ [streamingLifecycleManager handleProtocolEndServiceACKMessage:testAudioMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ it(@"should have set all the right properties", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ });
});
- });
- describe(@"after receiving a audio end NAK", ^{
- __block SDLProtocolHeader *testAudioHeader = nil;
- __block SDLProtocolMessage *testAudioMessage = nil;
+ describe(@"after receiving a audio end NAK", ^{
+ __block SDLProtocolHeader *testAudioHeader = nil;
+ __block SDLProtocolMessage *testAudioMessage = nil;
- beforeEach(^{
- [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
+ beforeEach(^{
+ [streamingLifecycleManager.videoStreamStateMachine setToState:SDLAudioStreamStateStarting fromOldState:nil callEnterTransition:NO];
- testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testAudioHeader.frameType = SDLFrameTypeSingle;
- testAudioHeader.frameData = SDLFrameInfoEndServiceNACK;
- testAudioHeader.encrypted = NO;
- testAudioHeader.serviceType = SDLServiceTypeAudio;
+ testAudioHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testAudioHeader.frameType = SDLFrameTypeSingle;
+ testAudioHeader.frameData = SDLFrameInfoEndServiceNACK;
+ testAudioHeader.encrypted = NO;
+ testAudioHeader.serviceType = SDLServiceTypeAudio;
- testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
- [streamingLifecycleManager handleProtocolEndServiceNAKMessage:testAudioMessage];
- });
+ testAudioMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testAudioHeader andPayload:nil];
+ [streamingLifecycleManager handleProtocolEndServiceNAKMessage:testAudioMessage];
+ });
- it(@"should have set all the right properties", ^{
- expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ it(@"should have set all the right properties", ^{
+ expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped));
+ });
});
});
});
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
index a36c213ae..43a2f6fab 100644
--- a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
@@ -13,7 +13,7 @@
#import <OCMock/OCMock.h>
#import "SDLNotificationConstants.h"
-#import "SDLHapticManager.h"
+#import "SDLFocusableItemLocator.h"
#import "SDLOnTouchEvent.h"
#import "SDLPinchGesture.h"
#import "SDLRPCNotificationNotification.h"