summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2018-01-08 12:10:02 -0500
committerGitHub <noreply@github.com>2018-01-08 12:10:02 -0500
commit6432ecb656cfe81974ff52eac002ac1d94f202bc (patch)
tree18c1022b41d5d679d32172bf71f9b5aa9a6bc52e
parentb7c427d8ed32bc0cfc37c84fc8f852a577a598d3 (diff)
parente3bc79dae7e757094d6c14ddb78c71e89d54b4fc (diff)
downloadsdl_ios-6432ecb656cfe81974ff52eac002ac1d94f202bc.tar.gz
Merge pull request #799 from smartdevicelink/feature/issue_794_CarWindow
CarWindow - Automatic Video Streaming
-rw-r--r--SmartDeviceLink-iOS.podspec1
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj32
-rw-r--r--SmartDeviceLink.podspec1
-rwxr-xr-xSmartDeviceLink/SDLCarWindow.h38
-rwxr-xr-xSmartDeviceLink/SDLCarWindow.m237
-rw-r--r--SmartDeviceLink/SDLCarWindowViewController.h18
-rw-r--r--SmartDeviceLink/SDLCarWindowViewController.m56
-rw-r--r--SmartDeviceLink/SDLFocusableItemHitTester.h2
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocator.h5
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocator.m25
-rw-r--r--SmartDeviceLink/SDLFocusableItemLocatorType.h15
-rw-r--r--SmartDeviceLink/SDLH264VideoEncoder.m9
-rw-r--r--SmartDeviceLink/SDLLifecycleManager.m6
-rw-r--r--SmartDeviceLink/SDLLockScreenManager.m10
-rw-r--r--SmartDeviceLink/SDLLockScreenPresenter.h6
-rw-r--r--SmartDeviceLink/SDLLockScreenPresenter.m106
-rw-r--r--SmartDeviceLink/SDLLockScreenViewController.m7
-rw-r--r--SmartDeviceLink/SDLLogFileModuleMap.m2
-rwxr-xr-xSmartDeviceLink/SDLScreenshotViewController.h22
-rwxr-xr-xSmartDeviceLink/SDLScreenshotViewController.m48
-rw-r--r--SmartDeviceLink/SDLStreamingMediaConfiguration.h69
-rw-r--r--SmartDeviceLink/SDLStreamingMediaConfiguration.m34
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.h3
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.m65
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.h5
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.m8
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManagerConstants.h5
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManagerConstants.m5
-rw-r--r--SmartDeviceLink/SDLTouchManager.h16
-rw-r--r--SmartDeviceLink/SDLTouchManager.m77
-rw-r--r--SmartDeviceLink/SDLViewControllerPresentable.h2
-rw-r--r--SmartDeviceLink/SmartDeviceLink.h3
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.h2
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.m4
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m2
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLStreamingMediaConfigurationSpec.m12
-rw-r--r--SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m53
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/PayloadSpecs/SDLRPCPayloadSpec.m2
-rw-r--r--SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m5
-rw-r--r--SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m36
40 files changed, 904 insertions, 150 deletions
diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec
index 069bb3f3c..b4fb6e61d 100644
--- a/SmartDeviceLink-iOS.podspec
+++ b/SmartDeviceLink-iOS.podspec
@@ -51,6 +51,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLButtonPress.h',
'SmartDeviceLink/SDLButtonPressMode.h',
'SmartDeviceLink/SDLCarModeStatus.h',
+'SmartDeviceLink/SDLCarWindowViewController.h',
'SmartDeviceLink/SDLChangeRegistration.h',
'SmartDeviceLink/SDLChangeRegistrationResponse.h',
'SmartDeviceLink/SDLCharacterSet.h',
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index 522a322d6..c48de453e 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -331,6 +331,8 @@
5D1665C91CF8CA3D00CC4CA1 /* SDLPermissionFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D1665C71CF8CA3D00CC4CA1 /* SDLPermissionFilter.m */; };
5D1665CB1CF8CA6700CC4CA1 /* NSNumber+NumberType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D1665CA1CF8CA6700CC4CA1 /* NSNumber+NumberType.h */; settings = {ATTRIBUTES = (Public, ); }; };
5D1665CD1CF8CA8A00CC4CA1 /* SDLPermissionConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D1665CC1CF8CA8A00CC4CA1 /* SDLPermissionConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 5D293AFE1FE078A9000CBD7E /* SDLCarWindowViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D293AFC1FE078A9000CBD7E /* SDLCarWindowViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 5D293AFF1FE078A9000CBD7E /* SDLCarWindowViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D293AFD1FE078A9000CBD7E /* SDLCarWindowViewController.m */; };
5D2F58081D0717D5001085CE /* SDLManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D2F58071D0717D5001085CE /* SDLManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
5D3E48751D6F3B330000BFEF /* SDLAsynchronousOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D3E48731D6F3B330000BFEF /* SDLAsynchronousOperation.h */; };
5D3E48761D6F3B330000BFEF /* SDLAsynchronousOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D3E48741D6F3B330000BFEF /* SDLAsynchronousOperation.m */; };
@@ -997,6 +999,10 @@
5DBF0D601F3B3DB4008AF2C9 /* SDLControlFrameVideoStartServiceAckSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DBF0D5F1F3B3DB4008AF2C9 /* SDLControlFrameVideoStartServiceAckSpec.m */; };
5DC09EDA1F2F7FEC00F4AB1D /* SDLControlFramePayloadNakSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DC09ED91F2F7FEC00F4AB1D /* SDLControlFramePayloadNakSpec.m */; };
5DC978261B7A38640012C2F1 /* SDLGlobalsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DC978251B7A38640012C2F1 /* SDLGlobalsSpec.m */; };
+ 5DCD7AE01FCCA8D200A0FC7F /* SDLCarWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DCD7ADC1FCCA8D100A0FC7F /* SDLCarWindow.h */; };
+ 5DCD7AE11FCCA8D200A0FC7F /* SDLCarWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DCD7ADD1FCCA8D200A0FC7F /* SDLCarWindow.m */; };
+ 5DCD7AF31FCCA8E400A0FC7F /* SDLScreenshotViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DCD7AE61FCCA8E400A0FC7F /* SDLScreenshotViewController.h */; };
+ 5DCD7AF71FCCA8E400A0FC7F /* SDLScreenshotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DCD7AEA1FCCA8E400A0FC7F /* SDLScreenshotViewController.m */; };
5DCF76F51ACDBAD300BB647B /* SDLSendLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DCF76F31ACDBAD300BB647B /* SDLSendLocation.h */; settings = {ATTRIBUTES = (Public, ); }; };
5DCF76F61ACDBAD300BB647B /* SDLSendLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DCF76F41ACDBAD300BB647B /* SDLSendLocation.m */; };
5DCF76F91ACDD7CD00BB647B /* SDLSendLocationResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DCF76F71ACDD7CD00BB647B /* SDLSendLocationResponse.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1540,6 +1546,8 @@
5D1665C71CF8CA3D00CC4CA1 /* SDLPermissionFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLPermissionFilter.m; sourceTree = "<group>"; };
5D1665CA1CF8CA6700CC4CA1 /* NSNumber+NumberType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNumber+NumberType.h"; sourceTree = "<group>"; };
5D1665CC1CF8CA8A00CC4CA1 /* SDLPermissionConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLPermissionConstants.h; sourceTree = "<group>"; };
+ 5D293AFC1FE078A9000CBD7E /* SDLCarWindowViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLCarWindowViewController.h; sourceTree = "<group>"; };
+ 5D293AFD1FE078A9000CBD7E /* SDLCarWindowViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLCarWindowViewController.m; sourceTree = "<group>"; };
5D2F58071D0717D5001085CE /* SDLManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLManagerDelegate.h; sourceTree = "<group>"; };
5D3E48731D6F3B330000BFEF /* SDLAsynchronousOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLAsynchronousOperation.h; sourceTree = "<group>"; };
5D3E48741D6F3B330000BFEF /* SDLAsynchronousOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLAsynchronousOperation.m; sourceTree = "<group>"; };
@@ -2223,6 +2231,10 @@
5DC09ED91F2F7FEC00F4AB1D /* SDLControlFramePayloadNakSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLControlFramePayloadNakSpec.m; path = ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m; sourceTree = "<group>"; };
5DC978251B7A38640012C2F1 /* SDLGlobalsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLGlobalsSpec.m; path = UtilitiesSpecs/SDLGlobalsSpec.m; sourceTree = "<group>"; };
5DCA93821EE0844D0015768E /* SmartDeviceLink.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = SmartDeviceLink.podspec; sourceTree = SOURCE_ROOT; };
+ 5DCD7ADC1FCCA8D100A0FC7F /* SDLCarWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLCarWindow.h; sourceTree = "<group>"; };
+ 5DCD7ADD1FCCA8D200A0FC7F /* SDLCarWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLCarWindow.m; sourceTree = "<group>"; };
+ 5DCD7AE61FCCA8E400A0FC7F /* SDLScreenshotViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLScreenshotViewController.h; sourceTree = "<group>"; };
+ 5DCD7AEA1FCCA8E400A0FC7F /* SDLScreenshotViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLScreenshotViewController.m; sourceTree = "<group>"; };
5DCF76F31ACDBAD300BB647B /* SDLSendLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSendLocation.h; sourceTree = "<group>"; };
5DCF76F41ACDBAD300BB647B /* SDLSendLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendLocation.m; sourceTree = "<group>"; };
5DCF76F71ACDD7CD00BB647B /* SDLSendLocationResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSendLocationResponse.h; sourceTree = "<group>"; };
@@ -3922,6 +3934,8 @@
5D616B481D552F7A00553F6B /* SDLLockScreen.storyboard */,
5D6F7A331BC5B9B60070BF37 /* SDLLockScreenViewController.h */,
5D6F7A341BC5B9B60070BF37 /* SDLLockScreenViewController.m */,
+ 5DCD7AE61FCCA8E400A0FC7F /* SDLScreenshotViewController.h */,
+ 5DCD7AEA1FCCA8E400A0FC7F /* SDLScreenshotViewController.m */,
);
name = "Lock Screen UI";
sourceTree = "<group>";
@@ -4405,6 +4419,17 @@
name = General;
sourceTree = "<group>";
};
+ 5DCD7AD91FCCA5BF00A0FC7F /* CarWindow */ = {
+ isa = PBXGroup;
+ children = (
+ 5DCD7ADC1FCCA8D100A0FC7F /* SDLCarWindow.h */,
+ 5DCD7ADD1FCCA8D200A0FC7F /* SDLCarWindow.m */,
+ 5D293AFC1FE078A9000CBD7E /* SDLCarWindowViewController.h */,
+ 5D293AFD1FE078A9000CBD7E /* SDLCarWindowViewController.m */,
+ );
+ name = CarWindow;
+ sourceTree = "<group>";
+ };
5DD67CAD1E65DD9C009CD394 /* Apple SysLog */ = {
isa = PBXGroup;
children = (
@@ -4490,6 +4515,7 @@
isa = PBXGroup;
children = (
5D23C9441FCF59F400002CA5 /* AudioManager */,
+ 5DCD7AD91FCCA5BF00A0FC7F /* CarWindow */,
5DA5918E1F96820F003264C3 /* Focus / Haptic */,
DAC5724C1D0FE3B60004288B /* Touches */,
DA8966F01E56970C00413EAB /* Utilities */,
@@ -4622,6 +4648,7 @@
5D61FC781A84238C00846EE7 /* SDLDeleteFileResponse.h in Headers */,
5DA240001F325621009C0313 /* SDLStreamingMediaConfiguration.h in Headers */,
5D61FC5F1A84238C00846EE7 /* SDLCharacterSet.h in Headers */,
+ 5DCD7AF31FCCA8E400A0FC7F /* SDLScreenshotViewController.h in Headers */,
5DD67CC71E68B568009CD394 /* SDLLogMacros.h in Headers */,
5D61FCFF1A84238C00846EE7 /* SDLOnAppInterfaceUnregistered.h in Headers */,
5D61FDC51A84238C00846EE7 /* SDLTCPTransport.h in Headers */,
@@ -4931,6 +4958,7 @@
5D61FDEF1A84238C00846EE7 /* SDLUpdateMode.h in Headers */,
EED5CA001F4D18DC00F04000 /* SDLRAWH264Packetizer.h in Headers */,
DA8966EB1E56939F00413EAB /* SDLStreamingMediaLifecycleManager.h in Headers */,
+ 5D293AFE1FE078A9000CBD7E /* SDLCarWindowViewController.h in Headers */,
5D61FDDB1A84238C00846EE7 /* SDLTriggerSource.h in Headers */,
5D61FD8F1A84238C00846EE7 /* SDLShow.h in Headers */,
5D61FDDD1A84238C00846EE7 /* SDLTTSChunk.h in Headers */,
@@ -4983,6 +5011,7 @@
5DD67CB01E65DDB7009CD394 /* SDLLogTargetAppleSystemLog.h in Headers */,
5D61FCBF1A84238C00846EE7 /* SDLHexUtility.h in Headers */,
5D00AC6B1F141339004000D9 /* SDLSystemCapability.h in Headers */,
+ 5DCD7AE01FCCA8D200A0FC7F /* SDLCarWindow.h in Headers */,
5D61FD6F1A84238C00846EE7 /* SDLRPCPayload.h in Headers */,
5D61FCF01A84238C00846EE7 /* SDLLockScreenStatusManager.h in Headers */,
5D61FD311A84238C00846EE7 /* SDLPolicyDataParser.h in Headers */,
@@ -5231,6 +5260,7 @@
5D7F87F41CE3C29E002DD7C4 /* SDLFileWrapper.m in Sources */,
5D61FD941A84238C00846EE7 /* SDLShowConstantTBTResponse.m in Sources */,
5D61FE0A1A84238C00846EE7 /* SDLVehicleDataType.m in Sources */,
+ 5D293AFF1FE078A9000CBD7E /* SDLCarWindowViewController.m in Sources */,
5D61FD1A1A84238C00846EE7 /* SDLOnSyncPData.m in Sources */,
8B7B319F1F2F7CF700BDC38D /* SDLVideoStreamingProtocol.m in Sources */,
5D61FC461A84238C00846EE7 /* SDLAudioPassThruCapabilities.m in Sources */,
@@ -5517,6 +5547,7 @@
5D7F87EC1CE3C1A1002DD7C4 /* SDLDeleteFileOperation.m in Sources */,
97E26DED1E807AD70074A3C7 /* SDLMutableDataQueue.m in Sources */,
5D61FD641A84238C00846EE7 /* SDLResetGlobalProperties.m in Sources */,
+ 5DCD7AE11FCCA8D200A0FC7F /* SDLCarWindow.m in Sources */,
1E5AD0911F20BE820029B8AF /* SDLSetInteriorVehicleData.m in Sources */,
5D60088B1BE3ED540094A505 /* SDLStateMachine.m in Sources */,
8877F5EF1F34A72200DC128A /* SDLSendHapticDataResponse.m in Sources */,
@@ -5544,6 +5575,7 @@
DA8966EC1E56939F00413EAB /* SDLStreamingMediaLifecycleManager.m in Sources */,
DAC5726A1D10D5FC0004288B /* dispatch_timer.m in Sources */,
5D61FC6C1A84238C00846EE7 /* SDLCreateInteractionChoiceSet.m in Sources */,
+ 5DCD7AF71FCCA8E400A0FC7F /* SDLScreenshotViewController.m in Sources */,
5D61FD081A84238C00846EE7 /* SDLOnCommand.m in Sources */,
5D53C46E1B7A99B9003526EA /* SDLStreamingMediaManager.m in Sources */,
5D61FD6A1A84238C00846EE7 /* SDLRPCMessage.m in Sources */,
diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec
index b28e48c74..0974d2055 100644
--- a/SmartDeviceLink.podspec
+++ b/SmartDeviceLink.podspec
@@ -51,6 +51,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLButtonPress.h',
'SmartDeviceLink/SDLButtonPressMode.h',
'SmartDeviceLink/SDLCarModeStatus.h',
+'SmartDeviceLink/SDLCarWindowViewController.h',
'SmartDeviceLink/SDLChangeRegistration.h',
'SmartDeviceLink/SDLChangeRegistrationResponse.h',
'SmartDeviceLink/SDLCharacterSet.h',
diff --git a/SmartDeviceLink/SDLCarWindow.h b/SmartDeviceLink/SDLCarWindow.h
new file mode 100755
index 000000000..076f24b23
--- /dev/null
+++ b/SmartDeviceLink/SDLCarWindow.h
@@ -0,0 +1,38 @@
+//
+// SDLCarWindow.h
+//
+// Created by Muller, Alexander (A.) on 10/6/16.
+// Copyright © 2016 Ford Motor Company. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@class SDLStreamingMediaConfiguration;
+@class SDLStreamingMediaLifecycleManager;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ SDLCarWindow is a class somewhat mimicking a `UIWindow` in that it has a `UIViewController` root, but it takes that ViewController, listens for a start to Video Streaming, and streams whatever is on that view controller to the head unit.
+ */
+@interface SDLCarWindow : NSObject
+
+/**
+ Initialize the CarWindow automatic streamer.
+
+ @param streamManager The stream manager to use for retrieving head unit dimension details and forwarding video frame data
+ @param configuration The streaming media configuration
+ @return An instance of this class
+ */
+- (instancetype)initWithStreamManager:(SDLStreamingMediaLifecycleManager *)streamManager configuration:(SDLStreamingMediaConfiguration *)configuration;
+
+/**
+ * View Controller that will be streamed.
+ */
+@property (strong, nonatomic, nullable) UIViewController *rootViewController;
+
+- (void)syncFrame;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLCarWindow.m b/SmartDeviceLink/SDLCarWindow.m
new file mode 100755
index 000000000..930ddf801
--- /dev/null
+++ b/SmartDeviceLink/SDLCarWindow.m
@@ -0,0 +1,237 @@
+//
+// SDLCarWindow.m
+// Projection
+//
+// Originally created by Muller, Alexander (A.) on 10/6/16.
+// Copyright © 2016 Ford Motor Company. All rights reserved.
+//
+// Updated by Joel Fischer, Livio Inc., on 11/27/17.
+
+#import <CommonCrypto/CommonDigest.h>
+#import <ImageIO/ImageIO.h>
+#import <MobileCoreServices/MobileCoreServices.h>
+
+#import "SDLCarWindow.h"
+#import "SDLGlobals.h"
+#import "SDLImageResolution.h"
+#import "SDLLogMacros.h"
+#import "SDLNotificationConstants.h"
+#import "SDLStateMachine.h"
+#import "SDLStreamingMediaConfiguration.h"
+#import "SDLStreamingMediaLifecycleManager.h"
+#import "SDLStreamingMediaManagerConstants.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLCarWindow ()
+
+@property (weak, nonatomic, nullable) SDLStreamingMediaLifecycleManager *streamManager;
+
+@property (assign, nonatomic) SDLCarWindowRenderingType renderingType;
+@property (assign, nonatomic) BOOL drawsAfterScreenUpdates;
+
+@property (assign, nonatomic, getter=isLockScreenPresenting) BOOL lockScreenPresenting;
+@property (assign, nonatomic, getter=isLockScreenDismissing) BOOL lockScreenBeingDismissed;
+
+@property (assign, nonatomic, getter=isVideoStreamStarted) BOOL videoStreamStarted;
+
+@end
+
+@implementation SDLCarWindow
+
+- (instancetype)initWithStreamManager:(SDLStreamingMediaLifecycleManager *)streamManager configuration:(nonnull SDLStreamingMediaConfiguration *)configuration {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _streamManager = streamManager;
+ _renderingType = configuration.carWindowRenderingType;
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_didReceiveVideoStreamStarted:) name:SDLVideoStreamDidStartNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_didReceiveVideoStreamStopped:) name:SDLVideoStreamDidStopNotification object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_willPresentLockScreenViewController:) name:SDLLockScreenManagerWillPresentLockScreenViewController object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_willDismissLockScreenViewController:) name:SDLLockScreenManagerWillDismissLockScreenViewController object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_didPresentLockScreenViewController:) name:SDLLockScreenManagerDidPresentLockScreenViewController object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_didDismissLockScreenViewController:) name:SDLLockScreenManagerDidDismissLockScreenViewController object:nil];
+
+ return self;
+}
+
+- (void)syncFrame {
+ if (!self.streamManager.isVideoConnected || self.streamManager.isVideoStreamingPaused) {
+ return;
+ }
+
+ if (self.isLockScreenPresenting || self.isLockScreenDismissing) {
+ SDLLogD(@"Paused CarWindow, lock screen moving");
+ return;
+ }
+
+ CGRect bounds = self.rootViewController.view.bounds;
+
+ UIGraphicsBeginImageContextWithOptions(bounds.size, YES, 1.0f);
+ switch (self.renderingType) {
+ case SDLCarWindowRenderingTypeLayer: {
+ [self.rootViewController.view.layer renderInContext:UIGraphicsGetCurrentContext()];
+ } break;
+ case SDLCarWindowRenderingTypeViewAfterScreenUpdates: {
+ [self.rootViewController.view drawViewHierarchyInRect:bounds afterScreenUpdates:YES];
+ } break;
+ case SDLCarWindowRenderingTypeViewBeforeScreenUpdates: {
+ [self.rootViewController.view drawViewHierarchyInRect:bounds afterScreenUpdates:NO];
+ } break;
+ }
+
+ UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ CGImageRef imageRef = screenshot.CGImage;
+ CVPixelBufferRef pixelBuffer = [self.class sdl_pixelBufferForImageRef:imageRef usingPool:self.streamManager.pixelBufferPool];
+ if (pixelBuffer != nil) {
+ [self.streamManager sendVideoData:pixelBuffer];
+ CVPixelBufferRelease(pixelBuffer);
+ }
+}
+
+#pragma mark - SDLNavigationLockScreenManager Notifications
+- (void)sdl_willPresentLockScreenViewController:(NSNotification *)notification {
+ self.lockScreenPresenting = YES;
+}
+
+- (void)sdl_didPresentLockScreenViewController:(NSNotification *)notification {
+ self.lockScreenPresenting = NO;
+}
+
+- (void)sdl_willDismissLockScreenViewController:(NSNotification *)notification {
+ self.lockScreenBeingDismissed = YES;
+}
+
+- (void)sdl_didDismissLockScreenViewController:(NSNotification *)notification {
+ self.lockScreenBeingDismissed = NO;
+}
+
+#pragma mark - SDLNavigationLifecycleManager Notifications
+- (void)sdl_didReceiveVideoStreamStarted:(NSNotification *)notification {
+ self.videoStreamStarted = true;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // If the video stream has started, we want to resize the streamingViewController to the size from the RegisterAppInterface
+ self.rootViewController.view.frame = CGRectMake(0, 0, self.streamManager.screenSize.width, self.streamManager.screenSize.height);
+ self.rootViewController.view.bounds = self.rootViewController.view.frame;
+
+ SDLLogD(@"Video stream started, setting CarWindow frame to: %@", NSStringFromCGRect(self.rootViewController.view.bounds));
+ });
+}
+
+- (void)sdl_didReceiveVideoStreamStopped:(NSNotification *)notification {
+ self.videoStreamStarted = false;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // And also reset the streamingViewController's frame, because we are about to show it.
+ self.rootViewController.view.frame = [UIScreen mainScreen].bounds;
+ SDLLogD(@"Video stream ended, setting view controller frame back: %@", NSStringFromCGRect(self.rootViewController.view.frame));
+ });
+}
+
+#pragma mark - Custom Accessors
+- (void)setRootViewController:(nullable UIViewController *)rootViewController {
+ if (rootViewController == nil || !self.isVideoStreamStarted) {
+ _rootViewController = rootViewController;
+ return;
+ }
+
+ NSAssert((rootViewController.supportedInterfaceOrientations == UIInterfaceOrientationMaskPortrait ||
+ rootViewController.supportedInterfaceOrientations == UIInterfaceOrientationMaskLandscapeLeft ||
+ rootViewController.supportedInterfaceOrientations == UIInterfaceOrientationMaskLandscapeRight), @"SDLCarWindow rootViewController must support only a single interface orientation");
+
+ if (self.streamManager.screenSize.width != 0) {
+ rootViewController.view.frame = CGRectMake(0, 0, self.streamManager.screenSize.width, self.streamManager.screenSize.height);
+ rootViewController.view.bounds = rootViewController.view.frame;
+ }
+
+ _rootViewController = rootViewController;
+}
+
+#pragma mark - Private Helpers
++ (nullable CVPixelBufferRef)sdl_pixelBufferForImageRef:(CGImageRef)imageRef usingPool:(CVPixelBufferPoolRef)pool {
+ size_t imageWidth = CGImageGetWidth(imageRef);
+ size_t imageHeight = CGImageGetHeight(imageRef);
+
+ CVPixelBufferRef pixelBuffer;
+ CVReturn result = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool, &pixelBuffer);
+ if (result != kCVReturnSuccess) {
+ return nil;
+ }
+
+ CVPixelBufferLockBaseAddress(pixelBuffer, 0);
+ void *data = CVPixelBufferGetBaseAddress(pixelBuffer);
+ CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = CGBitmapContextCreate(data, imageWidth, imageHeight, 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+ CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), imageRef);
+ CGColorSpaceRelease(rgbColorSpace);
+
+ CGContextRelease(context);
+
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
+
+ return pixelBuffer;
+}
+
+#pragma mark Backgrounded Screen / Text
+
++ (UIImage*)sdl_imageWithText:(NSString*)text size:(CGSize)size {
+ CGRect frame = CGRectMake(0, 0, size.width, size.height);
+ UIGraphicsBeginImageContextWithOptions(frame.size, NO, 1.0);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
+ CGContextFillRect(context, frame);
+ CGContextSaveGState(context);
+
+ NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.defaultParagraphStyle.mutableCopy;
+ textStyle.alignment = NSTextAlignmentCenter;
+
+ NSDictionary* textAttributes = @{
+ NSFontAttributeName: [self sdl_fontFittingSize:frame.size forText:text],
+ NSForegroundColorAttributeName: [UIColor whiteColor],
+ NSParagraphStyleAttributeName: textStyle
+ };
+ CGRect textFrame = [text boundingRectWithSize:size
+ options:NSStringDrawingUsesLineFragmentOrigin
+ attributes:textAttributes
+ context:nil];
+
+ CGRect textInset = CGRectMake(0,
+ (frame.size.height - CGRectGetHeight(textFrame)) / 2.0,
+ frame.size.width,
+ frame.size.height);
+
+ [text drawInRect:textInset
+ withAttributes:textAttributes];
+
+ CGContextRestoreGState(context);
+ UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
+
+ return image;
+}
+
++ (UIFont*)sdl_fontFittingSize:(CGSize)size forText:(NSString*)text {
+ CGFloat fontSize = 100;
+ while (fontSize > 0.0) {
+ CGSize textSize = [text boundingRectWithSize:CGSizeMake(size.width, CGFLOAT_MAX)
+ options:NSStringDrawingUsesLineFragmentOrigin
+ attributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:fontSize]}
+ context:nil].size;
+
+ if (textSize.height <= size.height) { break; }
+
+ fontSize -= 10.0;
+ }
+
+ return [UIFont boldSystemFontOfSize:fontSize];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLCarWindowViewController.h b/SmartDeviceLink/SDLCarWindowViewController.h
new file mode 100644
index 000000000..2dac757ca
--- /dev/null
+++ b/SmartDeviceLink/SDLCarWindowViewController.h
@@ -0,0 +1,18 @@
+//
+// SDLCarWindowViewController.h
+// SmartDeviceLink
+//
+// Created by Joel Fischer on 12/12/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ Note that if this is embedded in a UINavigationController and UITabBarController, it will not lock orientation. You must lock your container controller to a specific orientation.
+ */
+@interface SDLCarWindowViewController : UIViewController
+
+@property (nonatomic, assign) UIInterfaceOrientation supportedOrientation;
+
+@end
diff --git a/SmartDeviceLink/SDLCarWindowViewController.m b/SmartDeviceLink/SDLCarWindowViewController.m
new file mode 100644
index 000000000..5f6cbdbde
--- /dev/null
+++ b/SmartDeviceLink/SDLCarWindowViewController.m
@@ -0,0 +1,56 @@
+//
+// SDLCarWindowViewController.m
+// SmartDeviceLink
+//
+// Created by Joel Fischer on 12/12/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "SDLCarWindowViewController.h"
+
+@implementation SDLCarWindowViewController
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+ self = [super initWithCoder:aDecoder];
+ if (!self) { return nil; }
+
+ [self commonInit];
+
+ return self;
+}
+
+- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
+ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+ if (!self) { return nil; }
+
+ [self commonInit];
+
+ return self;
+}
+
+- (void)commonInit {
+ _supportedOrientation = 0;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+- (BOOL)shouldAutorotate {
+ return NO;
+}
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+ if (self.supportedOrientation == 0) {
+ return UIInterfaceOrientationMaskPortrait;
+ } else {
+ return (1 << self.supportedOrientation);
+ }
+}
+
+@end
diff --git a/SmartDeviceLink/SDLFocusableItemHitTester.h b/SmartDeviceLink/SDLFocusableItemHitTester.h
index fe5080500..7dd7662b4 100644
--- a/SmartDeviceLink/SDLFocusableItemHitTester.h
+++ b/SmartDeviceLink/SDLFocusableItemHitTester.h
@@ -1,5 +1,5 @@
//
-// SDLHapticHitTester.h
+// SDLFocusableItemHitTester.h
// SmartDeviceLink-iOS
//
// Copyright © 2017 smartdevicelink. All rights reserved.
diff --git a/SmartDeviceLink/SDLFocusableItemLocator.h b/SmartDeviceLink/SDLFocusableItemLocator.h
index 377b72571..3f065f106 100644
--- a/SmartDeviceLink/SDLFocusableItemLocator.h
+++ b/SmartDeviceLink/SDLFocusableItemLocator.h
@@ -16,6 +16,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL enableHapticDataRequests;
+/**
+ The projection view controller associated with the Haptic Manager
+ */
+@property (nonatomic, strong) UIViewController *viewController;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLFocusableItemLocator.m b/SmartDeviceLink/SDLFocusableItemLocator.m
index 391f43178..d44f8113c 100644
--- a/SmartDeviceLink/SDLFocusableItemLocator.m
+++ b/SmartDeviceLink/SDLFocusableItemLocator.m
@@ -20,11 +20,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLFocusableItemLocator()
/**
- The projection window associated with the Haptic Manager
- */
-@property (nonatomic, weak) UIWindow *projectionWindow;
-
-/**
Array of focusable view objects extracted from the projection window
*/
@property (nonatomic, strong) NSMutableArray<UIView *> *focusableViews;
@@ -39,26 +34,30 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLFocusableItemLocator
- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager{
+ return [self initWithViewController:window.rootViewController connectionManager:connectionManager];
+}
+
+- (instancetype)initWithViewController:(UIViewController *)viewController connectionManager:(id<SDLConnectionManagerType>)connectionManager {
self = [super init];
if(!self) {
return nil;
}
-
- _projectionWindow = window;
+
+ _viewController = viewController;
_connectionManager = connectionManager;
_enableHapticDataRequests = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_projectionViewUpdated:) name:SDLDidUpdateProjectionView object:nil];
-
+
return self;
}
- (void)updateInterfaceLayout {
if (@available(iOS 9.0, *)) {
self.focusableViews = [[NSMutableArray alloc] init];
- [self sdl_parseViewHierarchy:self.projectionWindow.subviews.lastObject];
+ [self sdl_parseViewHierarchy:self.viewController.view];
// If there is a preferred view bring that into top of the array
- NSUInteger preferredViewIndex = [self.focusableViews indexOfObject:self.projectionWindow.subviews.lastObject.preferredFocusedView];
+ NSUInteger preferredViewIndex = [self.focusableViews indexOfObject:self.viewController.view.subviews.lastObject.preferredFocusedView];
if (preferredViewIndex != NSNotFound && self.focusableViews.count > 1) {
[self.focusableViews exchangeObjectAtIndex:preferredViewIndex withObjectAtIndex:0];
}
@@ -112,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray<SDLHapticRect *> *hapticRects = [[NSMutableArray alloc] init];
for (UIView *view in self.focusableViews) {
- CGPoint originOnScreen = [self.projectionWindow convertPoint:view.frame.origin toView:nil];
+ CGPoint originOnScreen = [self.viewController.view convertPoint:view.frame.origin toView:nil];
CGRect convertedRect = {originOnScreen, view.bounds.size};
SDLRectangle* rect = [[SDLRectangle alloc] initWithCGRect:(convertedRect)];
// using the view index as the id field in SendHapticData request (should be guaranteed unique)
@@ -125,13 +124,13 @@ NS_ASSUME_NONNULL_BEGIN
[self.connectionManager sendManagerRequest:hapticRPC withResponseHandler:nil];
}
-#pragma mark SDLHapticHitTester functions
+#pragma mark SDLFocusableItemHitTester functions
- (nullable UIView *)viewForPoint:(CGPoint)point {
UIView *selectedView = nil;
for (UIView *view in self.focusableViews) {
//Convert the absolute location to local location and check if that falls within view boundary
- CGPoint localPoint = [view convertPoint:point fromView:self.projectionWindow];
+ CGPoint localPoint = [view convertPoint:point fromView:self.viewController.view];
if ([view pointInside:localPoint withEvent:nil]) {
if (selectedView != nil) {
selectedView = nil;
diff --git a/SmartDeviceLink/SDLFocusableItemLocatorType.h b/SmartDeviceLink/SDLFocusableItemLocatorType.h
index dc4d9488b..c75d61140 100644
--- a/SmartDeviceLink/SDLFocusableItemLocatorType.h
+++ b/SmartDeviceLink/SDLFocusableItemLocatorType.h
@@ -22,12 +22,25 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL enableHapticDataRequests;
/**
+ The projection view controller associated with the Haptic Manager
+ */
+@property (nonatomic, strong) UIViewController *viewController;
+
+/**
Initializes haptic interface. After initializing the application must call updateInterfaceLayout to process the UIWindow. Application must update later view changes in the window by sending SDLDidUpdateProjectionView notification.
@param window UIWindow to be stored in haptic interface
@param connectionManager Object of a class that implements ConnectionManagerType. This is used for RPC communication.
*/
-- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager;
+- (instancetype)initWithWindow:(UIWindow *)window connectionManager:(id<SDLConnectionManagerType>)connectionManager __deprecated_msg("Use initWithViewController:connectionManager: instead");
+
+/**
+ Initializes the haptic interface. After initializing the application must call updateInterfaceLayout to process the view controller. Application must update later view changes in the view controller (or a change in the view controller itself) by sending the SDLDidUpdateProjectionView notification.
+
+ @param viewController UIViewController to be checked for focusable views
+ @param connectionManager Object of a class that implements ConnectionManagerType. This is used for RPC communication.
+ */
+- (instancetype)initWithViewController:(UIViewController *)viewController connectionManager:(id<SDLConnectionManagerType>)connectionManager;
/**
updateInterfaceLayout crawls through the view hierarchy, updates and keep tracks of views to be reported through Haptic RPC. This function is automatically called when SDLDidUpdateProjectionView notification is sent by the application.
diff --git a/SmartDeviceLink/SDLH264VideoEncoder.m b/SmartDeviceLink/SDLH264VideoEncoder.m
index 6a2b6a1c1..c4d025464 100644
--- a/SmartDeviceLink/SDLH264VideoEncoder.m
+++ b/SmartDeviceLink/SDLH264VideoEncoder.m
@@ -35,11 +35,13 @@ static NSDictionary<NSString *, id>* _defaultVideoEncoderSettings;
if (self != [SDLH264VideoEncoder class]) {
return;
}
-
+
+ // https://support.google.com/youtube/answer/1722171?hl=en
_defaultVideoEncoderSettings = @{
(__bridge NSString *)kVTCompressionPropertyKey_ProfileLevel: (__bridge NSString *)kVTProfileLevel_H264_Baseline_AutoLevel,
(__bridge NSString *)kVTCompressionPropertyKey_RealTime: @YES,
- (__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate: @30,
+ (__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate: @15,
+ (__bridge NSString *)kVTCompressionPropertyKey_AverageBitRate: @600000,
};
}
@@ -103,7 +105,8 @@ static NSDictionary<NSString *, id>* _defaultVideoEncoderSettings;
status = VTSessionSetProperty(self.compressionSession, (__bridge CFStringRef)key, (__bridge CFTypeRef)value);
if (status != noErr) {
if (!*error) {
- *error = [NSError errorWithDomain:SDLErrorDomainVideoEncoder code:SDLVideoEncoderErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus": @(status) }];
+ NSString *description = [NSString stringWithFormat:@"Setting key failed \"%@\"", key];
+ *error = [NSError errorWithDomain:SDLErrorDomainVideoEncoder code:SDLVideoEncoderErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{NSLocalizedDescriptionKey: description, @"OSStatus": @(status)}];
}
return nil;
}
diff --git a/SmartDeviceLink/SDLLifecycleManager.m b/SmartDeviceLink/SDLLifecycleManager.m
index 6025e72ab..1643534fb 100644
--- a/SmartDeviceLink/SDLLifecycleManager.m
+++ b/SmartDeviceLink/SDLLifecycleManager.m
@@ -242,7 +242,11 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
if (error != nil || ![response.success boolValue]) {
SDLLogE(@"Failed to register the app. Error: %@, Response: %@", error, response);
weakSelf.readyHandler(NO, error);
- [weakSelf.lifecycleStateMachine transitionToState:SDLLifecycleStateStopped];
+
+ if (weakSelf.lifecycleState != SDLLifecycleStateReconnecting) {
+ [weakSelf.lifecycleStateMachine transitionToState:SDLLifecycleStateStopped];
+ }
+
return;
}
diff --git a/SmartDeviceLink/SDLLockScreenManager.m b/SmartDeviceLink/SDLLockScreenManager.m
index 7278ad2b1..de9d56f0f 100644
--- a/SmartDeviceLink/SDLLockScreenManager.m
+++ b/SmartDeviceLink/SDLLockScreenManager.m
@@ -16,6 +16,7 @@
#import "SDLNotificationConstants.h"
#import "SDLOnLockScreenStatus.h"
#import "SDLRPCNotificationNotification.h"
+#import "SDLScreenshotViewController.h"
#import "SDLViewControllerPresentable.h"
@@ -55,11 +56,10 @@ NS_ASSUME_NONNULL_BEGIN
// Create and initialize the lock screen controller depending on the configuration
if (!self.config.enableAutomaticLockScreen) {
- self.presenter.viewController = nil;
-
+ self.presenter.lockViewController = nil;
return;
} else if (self.config.customViewController != nil) {
- self.presenter.viewController = self.config.customViewController;
+ self.presenter.lockViewController = self.config.customViewController;
} else {
SDLLockScreenViewController *viewController = nil;
@@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
viewController.appIcon = self.config.appIcon;
viewController.backgroundColor = self.config.backgroundColor;
- self.presenter.viewController = viewController;
+ self.presenter.lockViewController = viewController;
}
self.canPresent = YES;
@@ -86,7 +86,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (nullable UIViewController *)lockScreenViewController {
- return self.presenter.viewController;
+ return self.presenter.lockViewController;
}
diff --git a/SmartDeviceLink/SDLLockScreenPresenter.h b/SmartDeviceLink/SDLLockScreenPresenter.h
index d8af89ddd..5e56f2479 100644
--- a/SmartDeviceLink/SDLLockScreenPresenter.h
+++ b/SmartDeviceLink/SDLLockScreenPresenter.h
@@ -6,7 +6,7 @@
// Copyright © 2016 smartdevicelink. All rights reserved.
//
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
#import "SDLViewControllerPresentable.h"
@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* The view controller to be presented.
*/
-@property (strong, nonatomic) UIViewController *viewController;
+@property (strong, nonatomic) UIViewController *lockViewController;
/**
* Whether or not `viewController` is currently presented.
@@ -29,4 +29,4 @@ NS_ASSUME_NONNULL_BEGIN
@end
-NS_ASSUME_NONNULL_END \ No newline at end of file
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLLockScreenPresenter.m b/SmartDeviceLink/SDLLockScreenPresenter.m
index 52b88b0a4..263b097b0 100644
--- a/SmartDeviceLink/SDLLockScreenPresenter.m
+++ b/SmartDeviceLink/SDLLockScreenPresenter.m
@@ -8,61 +8,109 @@
#import "SDLLockScreenPresenter.h"
+#import "SDLLogMacros.h"
+#import "SDLScreenshotViewController.h"
+#import "SDLStreamingMediaManagerConstants.h"
+
NS_ASSUME_NONNULL_BEGIN
@interface SDLLockScreenPresenter ()
+@property (strong, nonatomic) SDLScreenshotViewController *screenshotViewController;
+@property (strong, nonatomic) UIWindow *lockWindow;
+
@end
@implementation SDLLockScreenPresenter
-- (void)present {
- if (!self.viewController) {
- return;
- }
+- (instancetype)init {
+ self = [super init];
+ if (!self) { return nil; }
+
+ CGRect screenFrame = [[UIScreen mainScreen] bounds];
+ _lockWindow = [[UIWindow alloc] initWithFrame:screenFrame];
+ _screenshotViewController = [[SDLScreenshotViewController alloc] init];
+ _lockWindow.rootViewController = _screenshotViewController;
+ return self;
+}
+
+- (void)present {
dispatch_async(dispatch_get_main_queue(), ^{
- [[self.class sdl_getCurrentViewController] presentViewController:self.viewController animated:YES completion:nil];
+ NSArray* windows = [[UIApplication sharedApplication] windows];
+ UIWindow* appWindow = windows.firstObject;
+
+ if (self.lockWindow.isKeyWindow || appWindow == self.lockWindow) {
+ return;
+ }
+
+ // We let ourselves know that the lockscreen will present, because we have to pause streaming video for that 0.3 seconds or else it will be very janky.
+ [[NSNotificationCenter defaultCenter] postNotificationName:SDLLockScreenManagerWillPresentLockScreenViewController object:nil];
+
+ CGRect firstFrame = appWindow.frame;
+ firstFrame.origin.x = CGRectGetWidth(firstFrame);
+ appWindow.frame = firstFrame;
+
+ // We then move the lockWindow to the original appWindow location.
+ self.lockWindow.frame = appWindow.bounds;
+ [self.screenshotViewController loadScreenshotOfWindow:appWindow];
+ [self.lockWindow makeKeyAndVisible];
+
+ // And present the lock screen.
+ SDLLogD(@"Present lock screen window");
+ [self.lockWindow.rootViewController presentViewController:self.lockViewController animated:YES completion:^{
+ // Tell ourselves we are done.
+ [[NSNotificationCenter defaultCenter] postNotificationName:SDLLockScreenManagerDidPresentLockScreenViewController object:nil];
+ }];
});
}
- (void)dismiss {
- if (!self.viewController) {
- return;
- }
-
dispatch_async(dispatch_get_main_queue(), ^{
- [self.viewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
+ NSArray *windows = [[UIApplication sharedApplication] windows];
+ UIWindow *appWindow = windows.firstObject;
+
+ if (appWindow.isKeyWindow || appWindow == self.lockWindow) {
+ return;
+ }
+
+ // Let us know we are about to dismiss.
+ [[NSNotificationCenter defaultCenter] postNotificationName:SDLLockScreenManagerWillDismissLockScreenViewController object:nil];
+
+ // Dismiss the lockscreen
+ SDLLogD(@"Dismiss lock screen window");
+ [self.lockViewController dismissViewControllerAnimated:YES completion:^{
+ CGRect lockFrame = self.lockWindow.frame;
+ lockFrame.origin.x = CGRectGetWidth(lockFrame);
+ self.lockWindow.frame = lockFrame;
+
+ // Quickly move the map back, and make it the key window.
+ appWindow.frame = self.lockWindow.bounds;
+ [appWindow makeKeyAndVisible];
+
+ // Tell ourselves we are done.
+ [[NSNotificationCenter defaultCenter] postNotificationName:SDLLockScreenManagerDidDismissLockScreenViewController object:nil];
+ }];
});
}
- (BOOL)presented {
- if (!self.viewController) {
- return NO;
- }
-
- __block BOOL presented = NO;
- if (![NSThread isMainThread]) {
+ __block BOOL isPresented = NO;
+ if ([NSThread isMainThread]) {
+ isPresented = [self sdl_presented];
+ } else {
dispatch_sync(dispatch_get_main_queue(), ^{
- presented = (self.viewController.isViewLoaded && (self.viewController.view.window || self.viewController.isBeingPresented));
+ isPresented = [self sdl_presented];
});
- } else {
- presented = (self.viewController.isViewLoaded && (self.viewController.view.window || self.viewController.isBeingPresented));
}
-
- return presented;
+
+ return isPresented;
}
-+ (UIViewController *)sdl_getCurrentViewController {
- // http://stackoverflow.com/questions/6131205/iphone-how-to-find-topmost-view-controller
- UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
- while (topController.presentedViewController != nil) {
- topController = topController.presentedViewController;
- }
-
- return topController;
+- (BOOL)sdl_presented {
+ return (self.lockViewController.isViewLoaded && (self.lockViewController.view.window || self.lockViewController.isBeingPresented) && self.lockWindow.isKeyWindow);
}
@end
diff --git a/SmartDeviceLink/SDLLockScreenViewController.m b/SmartDeviceLink/SDLLockScreenViewController.m
index 27cc98797..291913aaa 100644
--- a/SmartDeviceLink/SDLLockScreenViewController.m
+++ b/SmartDeviceLink/SDLLockScreenViewController.m
@@ -39,6 +39,10 @@ NS_ASSUME_NONNULL_BEGIN
return NO;
}
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+ return UIInterfaceOrientationMaskPortrait;
+}
+
- (UIStatusBarStyle)preferredStatusBarStyle {
BOOL useWhiteIcon = [self.class sdl_shouldUseWhiteForegroundForBackgroundColor:self.backgroundColor];
@@ -63,7 +67,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)setBackgroundColor:(UIColor *_Nullable)backgroundColor {
_backgroundColor = backgroundColor;
- self.view.backgroundColor = _backgroundColor;
[self sdl_layoutViews];
}
@@ -85,6 +88,8 @@ NS_ASSUME_NONNULL_BEGIN
self.lockedLabel.textColor = iconColor;
+ self.view.backgroundColor = self.backgroundColor;
+
if (self.vehicleIcon != nil && self.appIcon != nil) {
[self sdl_setVehicleAndAppIconsLayout];
} else if (self.vehicleIcon != nil) {
diff --git a/SmartDeviceLink/SDLLogFileModuleMap.m b/SmartDeviceLink/SDLLogFileModuleMap.m
index d3cc0c29e..77024bb5f 100644
--- a/SmartDeviceLink/SDLLogFileModuleMap.m
+++ b/SmartDeviceLink/SDLLogFileModuleMap.m
@@ -60,7 +60,7 @@
}
+ (SDLLogFileModule *)sdl_streamingMediaManagerModule {
- return [SDLLogFileModule moduleWithName:@"Streaming" files:[NSSet setWithArray:@[@"SDLH264VideoEncoder", @"SDLRAWH264Packetizer", @"SDLRTPH264Packetizer", @"SDLStreamingMediaManager", @"SDLStreamingMediaLifecycleManager", @"SDLTouchManager"]]];
+ return [SDLLogFileModule moduleWithName:@"Streaming" files:[NSSet setWithArray:@[@"SDLH264VideoEncoder", @"SDLRAWH264Packetizer", @"SDLRTPH264Packetizer", @"SDLStreamingMediaManager", @"SDLStreamingMediaLifecycleManager", @"SDLTouchManager", @"SDLCarWindow"]]];
}
diff --git a/SmartDeviceLink/SDLScreenshotViewController.h b/SmartDeviceLink/SDLScreenshotViewController.h
new file mode 100755
index 000000000..4bb543647
--- /dev/null
+++ b/SmartDeviceLink/SDLScreenshotViewController.h
@@ -0,0 +1,22 @@
+//
+// SDLScreenShotViewController.h
+//
+// Created by Muller, Alexander (A.) on 2/6/17.
+// Copyright © 2017 Ford Motor Company. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ This class interacts with `SDLLockScreenPresenter`. It loads a screenshot of the app window and presents it on itself in an image view. This view controller is then presented on the lock window, which then presents the lock view controller over it.
+ */
+@interface SDLScreenshotViewController : UIViewController
+
+/**
+ Load a screenshot of the specified window into the image view on this class
+
+ @param window The window to take a screenshot of
+ */
+- (void)loadScreenshotOfWindow:(UIWindow *)window;
+
+@end
diff --git a/SmartDeviceLink/SDLScreenshotViewController.m b/SmartDeviceLink/SDLScreenshotViewController.m
new file mode 100755
index 000000000..2d9e73666
--- /dev/null
+++ b/SmartDeviceLink/SDLScreenshotViewController.m
@@ -0,0 +1,48 @@
+//
+// SDLScreenShotViewController.m
+// ios
+//
+// Created by Muller, Alexander (A.) on 2/6/17.
+// Copyright © 2017 Ford Motor Company. All rights reserved.
+//
+
+#import "SDLScreenshotViewController.h"
+
+@interface SDLScreenshotViewController ()
+
+@property (nonatomic, strong) UIImageView *imageView;
+
+@end
+
+@implementation SDLScreenshotViewController
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) { return nil; }
+
+ self.view.backgroundColor = [UIColor clearColor];
+
+ self.imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
+ self.imageView.backgroundColor = [UIColor clearColor];
+ self.imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ [self.view addSubview:self.imageView];
+
+ return self;
+}
+
+- (void)layoutSubviews {
+ self.imageView.frame = self.view.bounds;
+}
+
+- (void)loadScreenshotOfWindow:(UIWindow *)window {
+ UIGraphicsBeginImageContextWithOptions(window.bounds.size, YES, 0.0f);
+ [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:NO];
+
+ UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ self.imageView.image = image;
+}
+
+
+@end
diff --git a/SmartDeviceLink/SDLStreamingMediaConfiguration.h b/SmartDeviceLink/SDLStreamingMediaConfiguration.h
index be8a58554..efc3c0897 100644
--- a/SmartDeviceLink/SDLStreamingMediaConfiguration.h
+++ b/SmartDeviceLink/SDLStreamingMediaConfiguration.h
@@ -16,6 +16,12 @@
NS_ASSUME_NONNULL_BEGIN
+typedef NS_ENUM(NSUInteger, SDLCarWindowRenderingType) {
+ SDLCarWindowRenderingTypeLayer,
+ SDLCarWindowRenderingTypeViewAfterScreenUpdates,
+ SDLCarWindowRenderingTypeViewBeforeScreenUpdates
+};
+
@interface SDLStreamingMediaConfiguration : NSObject <NSCopying>
/**
@@ -29,7 +35,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (assign, nonatomic) SDLStreamingEncryptionFlag maximumDesiredEncryption;
/**
- * Properties to use for applications that utilitze the video encoder for streaming. See VTCompressionProperties.h for more details. For example, you can set kVTCompressionPropertyKey_ExpectedFrameRate to set your expected framerate.
+ * Properties to use for applications that utilize the video encoder for streaming. See VTCompressionProperties.h for more details. For example, you can set kVTCompressionPropertyKey_ExpectedFrameRate to set your framerate. Setting the framerate this way will also set the framerate if you use CarWindow automatic streaming.
+ *
+ * Other properties you may want to try adjusting include kVTCompressionPropertyKey_AverageBitRate and kVTCompressionPropertyKey_DataRateLimits.
*/
@property (copy, nonatomic, nullable) NSDictionary<NSString *, id> *customVideoEncoderSettings;
@@ -47,7 +55,34 @@ NS_ASSUME_NONNULL_BEGIN
@warning This is a weak property and it's therefore your job to hold a strong reference to this window.
*/
-@property (weak, nonatomic, nullable) UIWindow *window;
+@property (weak, nonatomic, nullable) UIWindow *window __deprecated_msg("Use rootViewController instead");
+
+/**
+ Set the initial view controller your video streaming content is within.
+
+ Activates the haptic view parser and CarWindow systems when set. This library will also use that information to attempt to return the touched view to you in `SDLTouchManagerDelegate`.
+
+ @note If you wish to alter this `rootViewController` while streaming via CarWindow, you must set a new `rootViewController` on `SDLStreamingMediaManager` and this will update both the haptic view parser and CarWindow.
+
+ @warning Apps using views outside of the `UIView` heirarchy (such as OpenGL) are currently unsupported. If you app uses partial views in the heirarchy, only those views will be discovered. Your OpenGL views will not be discoverable to a haptic interface head unit and you will have to manually make these views discoverable via the `SDLSendHapticData` RPC request.
+
+ @warning If the `rootViewController` is app UI and is set from the `UIViewController` class, it should only be set after viewDidAppear:animated is called. Setting the `rootViewController` in `viewDidLoad` or `viewWillAppear:animated` can cause weird behavior when setting the new frame.
+
+ @warning If setting the `rootViewController` when the app returns to the foreground, the app should register for the `UIApplicationDidBecomeActive` notification and not the `UIApplicationWillEnterForeground` notification. Setting the frame after a notification from the latter can also cause weird behavior when setting the new frame.
+
+ @warning While `viewDidLoad` will fire, appearance methods will not.
+ */
+@property (strong, nonatomic, nullable) UIViewController *rootViewController;
+
+/**
+ Declares if CarWindow will use layer rendering or view rendering. Defaults to layer rendering.
+ */
+@property (assign, nonatomic) SDLCarWindowRenderingType carWindowRenderingType;
+
+/**
+ When YES, the StreamingMediaManager will run a CADisplayLink with the framerate set to the video encoder settings kVTCompressionPropertyKey_ExpectedFrameRate. This then forces TouchManager (and CarWindow, if used) to sync their callbacks to the framerate. If using CarWindow, this *must* be YES. If NO, `enableSyncedPanning` on SDLTouchManager will be set to NO. Defaults to YES.
+ */
+@property (assign, nonatomic) BOOL enableForcedFramerateSync;
/**
Create an insecure video streaming configuration. No security managers will be provided and the encryption flag will be set to None. If you'd like custom video encoder settings, you can set the property manually.
@@ -65,7 +100,18 @@ NS_ASSUME_NONNULL_BEGIN
@param window The UIWindow you are running the content that is being streamed on, to use for haptics if needed and possible (only works for UIViews)
@return The configuration
*/
-- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource window:(nullable UIWindow *)window;
+- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource window:(nullable UIWindow *)window __deprecated_msg("Use initWithSecurityManagers:encryptionFlag:videoSettings:dataSource:rootViewController: instead");
+
+/**
+ Manually set all the properties to the streaming media configuration
+
+ @param securityManagers The security managers to use or nil for none.
+ @param encryptionFlag The maximum encrpytion supported. If the connected head unit supports less than set here, it will still connect, but if it supports more than set here, it will not connect.
+ @param videoSettings Custom video encoder settings to be used in video streaming.
+ @param rootViewController The UIViewController wih the content that is being streamed on, to use for haptics if needed and possible (only works for UIViews)
+ @return The configuration
+ */
+- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource rootViewController:(nullable UIViewController *)rootViewController;
/**
Create a secure configuration for each of the security managers provided.
@@ -90,6 +136,23 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (instancetype)insecureConfiguration NS_SWIFT_UNAVAILABLE("Use the standard initializer instead");
+/**
+ Create a CarWindow insecure configuration with a view controller
+
+ @param initialViewController The initial view controller that will be streamed
+ @return The configuration
+ */
++ (instancetype)autostreamingInsecureConfigurationWithInitialViewController:(UIViewController *)initialViewController;
+
+/**
+ Create a CarWindow secure configuration with a view controller and security managers
+
+ @param securityManagers The security managers available for secure streaming use
+ @param initialViewController The initial view controller that will be streamed, this can be a basic `UIViewController` if you need to set your actual streaming view controller at a later time on `SDLManager.streamingManager.rootViewController`.
+ @return The configuration
+ */
++ (instancetype)autostreamingSecureConfigurationWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *)securityManagers initialViewController:(UIViewController *)initialViewController;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLStreamingMediaConfiguration.m b/SmartDeviceLink/SDLStreamingMediaConfiguration.m
index d3293bd5a..45c5728d7 100644
--- a/SmartDeviceLink/SDLStreamingMediaConfiguration.m
+++ b/SmartDeviceLink/SDLStreamingMediaConfiguration.m
@@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLStreamingMediaConfiguration
- (instancetype)init {
- return [self initWithSecurityManagers:nil encryptionFlag:SDLStreamingEncryptionFlagNone videoSettings:nil dataSource:nil window:nil];
+ return [self initWithSecurityManagers:nil encryptionFlag:SDLStreamingEncryptionFlagNone videoSettings:nil dataSource:nil rootViewController:nil];
}
+ (instancetype)insecureConfiguration {
@@ -24,6 +24,10 @@ NS_ASSUME_NONNULL_BEGIN
}
- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *,id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource window:(nullable UIWindow *)window {
+ return [self initWithSecurityManagers:securityManagers encryptionFlag:encryptionFlag videoSettings:videoSettings dataSource:dataSource rootViewController:window.rootViewController];
+}
+
+- (instancetype)initWithSecurityManagers:(nullable NSArray<Class<SDLSecurityType>> *)securityManagers encryptionFlag:(SDLStreamingEncryptionFlag)encryptionFlag videoSettings:(nullable NSDictionary<NSString *,id> *)videoSettings dataSource:(nullable id<SDLStreamingMediaManagerDataSource>)dataSource rootViewController:(nullable UIViewController *)rootViewController {
self = [super init];
if (!self) {
return nil;
@@ -33,7 +37,9 @@ NS_ASSUME_NONNULL_BEGIN
_maximumDesiredEncryption = encryptionFlag;
_customVideoEncoderSettings = videoSettings;
_dataSource = dataSource;
- _window = window;
+ _rootViewController = rootViewController;
+ _carWindowRenderingType = SDLCarWindowRenderingTypeLayer;
+ _enableForcedFramerateSync = YES;
return self;
}
@@ -42,17 +48,37 @@ NS_ASSUME_NONNULL_BEGIN
NSAssert(securityManagers.count > 0, @"A secure streaming media configuration requires security managers to be passed.");
SDLStreamingEncryptionFlag encryptionFlag = SDLStreamingEncryptionFlagAuthenticateAndEncrypt;
- return [self initWithSecurityManagers:securityManagers encryptionFlag:encryptionFlag videoSettings:nil dataSource:nil window:nil];
+ return [self initWithSecurityManagers:securityManagers encryptionFlag:encryptionFlag videoSettings:nil dataSource:nil rootViewController:nil];
}
+ (instancetype)secureConfigurationWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *)securityManagers {
return [[self alloc] initWithSecurityManagers:securityManagers];
}
++ (instancetype)autostreamingInsecureConfigurationWithInitialViewController:(UIViewController *)initialViewController {
+ return [[self alloc] initWithSecurityManagers:nil encryptionFlag:SDLStreamingEncryptionFlagNone videoSettings:nil dataSource:nil rootViewController:initialViewController];
+}
+
++ (instancetype)autostreamingSecureConfigurationWithSecurityManagers:(NSArray<Class<SDLSecurityType>> *)securityManagers initialViewController:(UIViewController *)initialViewController {
+ return [[self alloc] initWithSecurityManagers:securityManagers encryptionFlag:SDLStreamingEncryptionFlagAuthenticateAndEncrypt videoSettings:nil dataSource:nil rootViewController:initialViewController];
+}
+
+#pragma mark - Getters / Setters
+- (void)setWindow:(nullable UIWindow *)window {
+ _window = window;
+ if (window != nil) {
+ _rootViewController = window.rootViewController;
+ }
+}
+
#pragma mark NSCopying
- (id)copyWithZone:(nullable NSZone *)zone {
- return [[self.class allocWithZone:zone] initWithSecurityManagers:_securityManagers encryptionFlag:_maximumDesiredEncryption videoSettings:_customVideoEncoderSettings dataSource:_dataSource window:_window];
+ SDLStreamingMediaConfiguration *newConfig = [[self.class allocWithZone:zone] initWithSecurityManagers:_securityManagers encryptionFlag:_maximumDesiredEncryption videoSettings:_customVideoEncoderSettings dataSource:_dataSource rootViewController:_rootViewController];
+
+ newConfig.carWindowRenderingType = self.carWindowRenderingType;
+
+ return newConfig;
}
@end
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
index 9c09285c2..008cb2a01 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
@@ -17,6 +17,7 @@
@class SDLAbstractProtocol;
@class SDLAudioStreamManager;
+@class SDLCarWindow;
@class SDLImageResolution;
@class SDLStateMachine;
@class SDLStreamingMediaConfiguration;
@@ -67,6 +68,8 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown;
@property (nonatomic, strong, readonly) SDLTouchManager *touchManager;
@property (nonatomic, strong, readonly) SDLAudioStreamManager *audioManager;
+@property (nonatomic, strong) UIViewController *rootViewController;
+@property (strong, nonatomic, readonly, nullable) SDLCarWindow *carWindow;
/**
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.
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
index e77d4a7c9..080157de8 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
@@ -10,6 +10,7 @@
#import "SDLAbstractProtocol.h"
#import "SDLAudioStreamManager.h"
+#import "SDLCarWindow.h"
#import "SDLControlFramePayloadAudioStartServiceAck.h"
#import "SDLControlFramePayloadConstants.h"
#import "SDLControlFramePayloadNak.h"
@@ -89,6 +90,9 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
@property (assign, nonatomic) CV_NULLABLE CVPixelBufferRef backgroundingPixelBuffer;
+@property (strong, nonatomic, nullable) CADisplayLink *displayLink;
+@property (assign, nonatomic) BOOL useDisplayLink;
+
@property (assign, nonatomic) CMTime lastPresentationTimestamp;
@end
@@ -106,20 +110,28 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
}
SDLLogV(@"Creating StreamingLifecycleManager");
+
_connectionManager = connectionManager;
+ _videoEncoderSettings = configuration.customVideoEncoderSettings ?: SDLH264VideoEncoder.defaultVideoEncoderSettings;
- if (@available(iOS 9.0, *)) {
- if (configuration.window != nil) {
- _focusableItemManager = [[SDLFocusableItemLocator alloc] initWithWindow:configuration.window connectionManager:_connectionManager];
+ if (configuration.rootViewController != nil) {
+ NSAssert(configuration.enableForcedFramerateSync, @"When using CarWindow (rootViewController != nil), forceFrameRateSync must be YES");
+ if (@available(iOS 9.0, *)) {
+ SDLLogD(@"Initializing focusable item locator");
+ _focusableItemManager = [[SDLFocusableItemLocator alloc] initWithViewController:configuration.rootViewController connectionManager:_connectionManager];
}
+
+ SDLLogD(@"Initializing CarWindow");
+ _carWindow = [[SDLCarWindow alloc] initWithStreamManager:self configuration:configuration];
+ _carWindow.rootViewController = configuration.rootViewController;
}
_touchManager = [[SDLTouchManager alloc] initWithHitTester:(id)_focusableItemManager];
_audioManager = [[SDLAudioStreamManager alloc] initWithManager:self];
- _videoEncoderSettings = configuration.customVideoEncoderSettings ?: SDLH264VideoEncoder.defaultVideoEncoderSettings;
_requestedEncryptionType = configuration.maximumDesiredEncryption;
_dataSource = configuration.dataSource;
+ _useDisplayLink = configuration.enableForcedFramerateSync;
_screenSize = SDLDefaultScreenSize;
_backgroundingPixelBuffer = NULL;
_preferredFormatIndex = 0;
@@ -312,6 +324,9 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
_videoEncoder = nil;
}
+ self.displayLink.paused = YES;
+ [self.displayLink invalidate];
+
[[NSNotificationCenter defaultCenter] postNotificationName:SDLVideoStreamDidStopNotification object:nil];
if (self.shouldRestartVideoStream) {
@@ -393,6 +408,23 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
}
[[NSNotificationCenter defaultCenter] postNotificationName:SDLVideoStreamDidStartNotification object:nil];
+
+ if (self.useDisplayLink) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // And start up the displayLink
+ NSInteger targetFramerate = ((NSNumber *)self.videoEncoderSettings[(__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate]).integerValue;
+ SDLLogD(@"Initializing CADisplayLink with framerate: %ld", (long)targetFramerate);
+ self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(sdl_displayLinkFired:)];
+ if (SDL_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10")) {
+ self.displayLink.preferredFramesPerSecond = targetFramerate;
+ } else {
+ self.displayLink.frameInterval = (60 / targetFramerate);
+ }
+ [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+ });
+ } else {
+ self.touchManager.enableSyncedPanning = NO;
+ }
}
- (void)didEnterStateVideoStreamShuttingDown {
@@ -643,8 +675,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
return;
}
- if ([self.videoStreamStateMachine isCurrentState:SDLVideoStreamStateStopped]
- && self.isHmiStateVideoStreamCapable) {
+ if ([self.videoStreamStateMachine isCurrentState:SDLVideoStreamStateStopped] && self.isHmiStateVideoStreamCapable) {
[self.videoStreamStateMachine transitionToState:SDLVideoStreamStateStarting];
} else {
SDLLogE(@"Unable to send video start service request\n"
@@ -701,6 +732,14 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
}
}
+- (void)sdl_displayLinkFired:(CADisplayLink *)displayLink {
+ NSAssert([NSThread isMainThread], @"Display link should always fire on the main thread");
+ SDLLogV(@"DisplayLink frame fired, duration: %f, last frame timestamp: %f, target timestamp: %f", displayLink.duration, displayLink.timestamp, displayLink.targetTimestamp);
+
+ [self.touchManager syncFrame];
+ [self.carWindow syncFrame];
+}
+
- (void)sdl_sendBackgroundFrames {
SDLLogV(@"Attempting to send background frames");
if (!self.backgroundingPixelBuffer) {
@@ -758,7 +797,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
// If this fails we have no known formats to use
if (self.preferredFormatIndex >= self.preferredFormats.count
|| self.preferredResolutionIndex >= self.preferredResolutions.count) {
- SDLLogE(@"No preferred format or no preferred resolution found that works: format index %lu, resolution index %lu", self.preferredFormatIndex, self.preferredResolutionIndex);
+ SDLLogE(@"No preferred format or no preferred resolution found that works: format index %lu, resolution index %lu", (unsigned long)self.preferredFormatIndex, (unsigned long)self.preferredResolutionIndex);
[self sdl_transitionToStoppedState:SDLServiceTypeVideo];
return;
}
@@ -784,7 +823,17 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
}
-#pragma mark Getters
+#pragma mark Setters / Getters
+
+- (void)setRootViewController:(UIViewController *)rootViewController {
+ if (self.focusableItemManager != nil) {
+ self.focusableItemManager.viewController = rootViewController;
+ }
+
+ if (self.carWindow != nil) {
+ self.carWindow.rootViewController = rootViewController;
+ }
+}
- (BOOL)isAppStateVideoStreamCapable {
return [self.appStateMachine isCurrentState:SDLAppStateActive];
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h
index c4c24c184..76f4ab8a2 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaManager.h
@@ -35,6 +35,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, readonly) SDLAudioStreamManager *audioManager;
/**
+ This property is used for SDLCarWindow, the ability to stream any view controller. To start, you must set an initial view controller on `SDLStreamingMediaConfiguration` `rootViewController`. After streaming begins, you can replace that view controller with a new root by placing the new view controller into this property.
+ */
+@property (nonatomic, strong) UIViewController *rootViewController;
+
+/**
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<SDLFocusableItemLocatorType> focusableItemManager;
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m
index 7ba030484..4a0b08b28 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaManager.m
@@ -72,6 +72,10 @@ NS_ASSUME_NONNULL_BEGIN
return self.lifecycleManager.audioManager;
}
+- (UIViewController *)rootViewController {
+ return self.lifecycleManager.rootViewController;
+}
+
- (nullable id<SDLFocusableItemLocatorType>)focusableItemManager {
return self.lifecycleManager.focusableItemManager;
}
@@ -121,6 +125,10 @@ NS_ASSUME_NONNULL_BEGIN
}
#pragma mark - Setters
+- (void)setRootViewController:(UIViewController *)rootViewController {
+ self.lifecycleManager.rootViewController = rootViewController;
+}
+
- (void)setRequestedEncryptionType:(SDLStreamingEncryptionFlag)requestedEncryptionType {
self.lifecycleManager.requestedEncryptionType = requestedEncryptionType;
}
diff --git a/SmartDeviceLink/SDLStreamingMediaManagerConstants.h b/SmartDeviceLink/SDLStreamingMediaManagerConstants.h
index 2fc007d6f..0e6cbe88c 100644
--- a/SmartDeviceLink/SDLStreamingMediaManagerConstants.h
+++ b/SmartDeviceLink/SDLStreamingMediaManagerConstants.h
@@ -24,4 +24,9 @@ extern NSString *const SDLVideoStreamDidStopNotification;
extern NSString *const SDLAudioStreamDidStartNotification;
extern NSString *const SDLAudioStreamDidStopNotification;
+extern NSString *const SDLLockScreenManagerWillPresentLockScreenViewController;
+extern NSString *const SDLLockScreenManagerDidPresentLockScreenViewController;
+extern NSString *const SDLLockScreenManagerWillDismissLockScreenViewController;
+extern NSString *const SDLLockScreenManagerDidDismissLockScreenViewController;
+
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLStreamingMediaManagerConstants.m b/SmartDeviceLink/SDLStreamingMediaManagerConstants.m
index 1c65284d3..f9be99fef 100644
--- a/SmartDeviceLink/SDLStreamingMediaManagerConstants.m
+++ b/SmartDeviceLink/SDLStreamingMediaManagerConstants.m
@@ -16,3 +16,8 @@ NSString *const SDLVideoStreamDidStopNotification = @"com.sdl.videoStreamDidStop
NSString *const SDLAudioStreamDidStartNotification = @"com.sdl.audioStreamDidStart";
NSString *const SDLAudioStreamDidStopNotification = @"com.sdl.audioStreamDidStop";
+
+NSString *const SDLLockScreenManagerWillPresentLockScreenViewController = @"com.sdl.lockscreen.willPresent";
+NSString *const SDLLockScreenManagerDidPresentLockScreenViewController = @"com.sdl.lockscreen.didPresent";
+NSString *const SDLLockScreenManagerWillDismissLockScreenViewController = @"com.sdl.lockscreen.willDismiss";
+NSString *const SDLLockScreenManagerDidDismissLockScreenViewController = @"com.sdl.lockscreen.didDismiss";
diff --git a/SmartDeviceLink/SDLTouchManager.h b/SmartDeviceLink/SDLTouchManager.h
index 8cf417a2c..fb206665d 100644
--- a/SmartDeviceLink/SDLTouchManager.h
+++ b/SmartDeviceLink/SDLTouchManager.h
@@ -10,7 +10,7 @@
#import "SDLTouchType.h"
-@protocol SDLHapticHitTester;
+@protocol SDLFocusableItemHitTester;
@protocol SDLTouchManagerDelegate;
@class SDLTouch;
@@ -55,7 +55,12 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
* @remark
* Default is 0.05 seconds.
*/
-@property (nonatomic, assign) CGFloat movementTimeThreshold;
+@property (nonatomic, assign) CGFloat movementTimeThreshold __deprecated_msg("This is now unused, the movement time threshold is now synced to the framerate automatically");
+
+/**
+ If set to NO, the display link syncing will be ignored and `movementTimeThreshold` will be used. Defaults to YES.
+ */
+@property (assign, nonatomic) BOOL enableSyncedPanning;
/**
* @abstract
@@ -82,7 +87,12 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
@param hitTester The hit tester to be used to correlate a point with a view
@return The initialized touch manager
*/
-- (instancetype)initWithHitTester:(nullable id<SDLHapticHitTester>)hitTester;
+- (instancetype)initWithHitTester:(nullable id<SDLFocusableItemHitTester>)hitTester;
+
+/**
+ Called by SDLStreamingMediaManager in sync with the streaming framerate. This helps to moderate panning gestures by allowing the UI to be modified in time with the framerate.
+ */
+- (void)syncFrame;
@end
diff --git a/SmartDeviceLink/SDLTouchManager.m b/SmartDeviceLink/SDLTouchManager.m
index 4c9417961..40b3b1c54 100644
--- a/SmartDeviceLink/SDLTouchManager.m
+++ b/SmartDeviceLink/SDLTouchManager.m
@@ -82,6 +82,16 @@ static NSUInteger const MaximumNumberOfTouches = 2;
*/
@property (nonatomic, weak, nullable) id<SDLFocusableItemHitTester> hitTester;
+/**
+ The last panning touch we received
+ */
+@property (nonatomic) CGPoint lastStoredTouchLocation;
+
+/**
+ The last panning touch that we notified the developer about
+ */
+@property (nonatomic) CGPoint lastNotifiedTouchLocation;
+
@end
@implementation SDLTouchManager
@@ -97,6 +107,7 @@ static NSUInteger const MaximumNumberOfTouches = 2;
_tapTimeThreshold = 0.4f;
_tapDistanceThreshold = 50.0f;
_touchEnabled = YES;
+ _enableSyncedPanning = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_onTouchEvent:) name:SDLDidReceiveTouchEventNotification object:nil];
@@ -108,6 +119,45 @@ static NSUInteger const MaximumNumberOfTouches = 2;
[self sdl_cancelSingleTapTimer];
}
+- (void)syncFrame {
+ if (!self.isTouchEnabled || (!self.touchEventHandler && !self.touchEventDelegate)) {
+ return;
+ }
+
+ if (self.performingTouchType == SDLPerformingTouchTypePanningTouch) {
+ CGPoint storedTouchLocation = self.lastStoredTouchLocation;
+ CGPoint notifiedTouchLocation = self.lastNotifiedTouchLocation;
+
+ if (CGPointEqualToPoint(storedTouchLocation, CGPointZero) ||
+ CGPointEqualToPoint(notifiedTouchLocation, CGPointZero) ||
+ CGPointEqualToPoint(storedTouchLocation, notifiedTouchLocation)) {
+ return;
+ }
+
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePanningFromPoint:toPoint:)]) {
+ [self.touchEventDelegate touchManager:self
+ didReceivePanningFromPoint:notifiedTouchLocation
+ toPoint:storedTouchLocation];
+
+ self.lastNotifiedTouchLocation = storedTouchLocation;
+ }
+ } else if (self.performingTouchType == SDLPerformingTouchTypeMultiTouch) {
+ if (self.previousPinchDistance == self.currentPinchGesture.distance) {
+ return;
+ }
+
+ if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePinchAtCenterPoint:withScale:)]) {
+ CGFloat scale = self.currentPinchGesture.distance / self.previousPinchDistance;
+ [self.touchEventDelegate touchManager:self
+ didReceivePinchAtCenterPoint:self.currentPinchGesture.center
+ withScale:scale];
+ }
+
+ self.previousPinchDistance = self.currentPinchGesture.distance;
+
+ }
+}
+
#pragma mark - SDLDidReceiveTouchEventNotification
/**
@@ -178,9 +228,13 @@ static NSUInteger const MaximumNumberOfTouches = 2;
* @param touch Gesture information
*/
- (void)sdl_handleTouchMoved:(SDLTouch *)touch {
- if ((touch.timeStamp - self.previousTouch.timeStamp) <= (self.movementTimeThreshold * NSEC_PER_USEC)) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ if (!self.enableSyncedPanning &&
+ ((touch.timeStamp - self.previousTouch.timeStamp) <= (self.movementTimeThreshold * NSEC_PER_USEC))) {
return; // no-op
}
+#pragma clang diagnostic pop
switch (self.performingTouchType) {
case SDLPerformingTouchTypeMultiTouch: {
@@ -193,16 +247,14 @@ static NSUInteger const MaximumNumberOfTouches = 2;
} break;
}
- if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePinchAtCenterPoint:withScale:)]) {
- CGFloat scale = self.currentPinchGesture.distance / self.previousPinchDistance;
- [self.touchEventDelegate touchManager:self
- didReceivePinchAtCenterPoint:self.currentPinchGesture.center
- withScale:scale];
+ if (!self.enableSyncedPanning) {
+ [self syncFrame];
}
-
- self.previousPinchDistance = self.currentPinchGesture.distance;
} break;
case SDLPerformingTouchTypeSingleTouch: {
+ self.lastNotifiedTouchLocation = touch.location;
+ self.lastStoredTouchLocation = touch.location;
+
_performingTouchType = SDLPerformingTouchTypePanningTouch;
if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:panningDidStartInView:atPoint:)]) {
UIView *hitView = (self.hitTester != nil) ? [self.hitTester viewForPoint:touch.location] : nil;
@@ -210,11 +262,10 @@ static NSUInteger const MaximumNumberOfTouches = 2;
}
} break;
case SDLPerformingTouchTypePanningTouch: {
- if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceivePanningFromPoint:toPoint:)]) {
- [self.touchEventDelegate touchManager:self
- didReceivePanningFromPoint:self.previousTouch.location
- toPoint:touch.location];
+ if (!self.enableSyncedPanning) {
+ [self syncFrame];
}
+ self.lastStoredTouchLocation = touch.location;
} break;
case SDLPerformingTouchTypeNone: break;
}
@@ -316,6 +367,8 @@ static NSUInteger const MaximumNumberOfTouches = 2;
_performingTouchType = SDLPerformingTouchTypeNone;
}
+#pragma mark - Helpers
+
/**
* Saves the pinch touch gesture to the correct finger
*
diff --git a/SmartDeviceLink/SDLViewControllerPresentable.h b/SmartDeviceLink/SDLViewControllerPresentable.h
index 76ee668ef..72cfd31f6 100644
--- a/SmartDeviceLink/SDLViewControllerPresentable.h
+++ b/SmartDeviceLink/SDLViewControllerPresentable.h
@@ -13,7 +13,7 @@
*/
@protocol SDLViewControllerPresentable <NSObject>
-@property (strong, nonatomic) UIViewController *viewController;
+@property (strong, nonatomic) UIViewController *lockViewController;
@property (assign, nonatomic, readonly) BOOL presented;
- (void)present;
diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h
index 845ce4808..f992275c1 100644
--- a/SmartDeviceLink/SmartDeviceLink.h
+++ b/SmartDeviceLink/SmartDeviceLink.h
@@ -13,7 +13,6 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLProxy.h"
#import "SDLProxyFactory.h"
#import "SDLProxyListener.h"
-#import "SDLSecurityType.h"
/***** Transport *****/
#import "SDLAbstractTransport.h"
@@ -322,10 +321,12 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
// Streaming
#import "SDLAudioStreamManager.h"
#import "SDLAudioStreamManagerDelegate.h"
+#import "SDLCarWindowViewController.h"
#import "SDLStreamingAudioManagerType.h"
#import "SDLStreamingMediaManager.h"
#import "SDLTouchManager.h"
#import "SDLTouchManagerDelegate.h"
+#import "SDLSecurityType.h"
// Files
#import "SDLArtwork.h"
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.h b/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.h
index 1f71cffa8..4b1d7249a 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.h
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.h
@@ -12,7 +12,7 @@
@interface SDLFakeViewControllerPresenter : NSObject <SDLViewControllerPresentable>
-@property (strong, nonatomic) UIViewController *viewController;
+@property (strong, nonatomic) UIViewController *lockViewController;
@property (assign, nonatomic, readonly) BOOL presented;
@end
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.m b/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.m
index 0630fd9f7..3e6230897 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLFakeViewControllerPresenter.m
@@ -19,13 +19,13 @@
@implementation SDLFakeViewControllerPresenter
- (void)present {
- if (!self.viewController) { return; }
+ if (!self.lockViewController) { return; }
_presented = YES;
}
- (void)dismiss {
- if (!self.viewController) { return; }
+ if (!self.lockViewController) { return; }
_presented = NO;
}
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
index 17e42a750..4f4d0d14c 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
@@ -209,7 +209,7 @@ describe(@"a lifecycle manager", ^{
});
it(@"should be in the started state", ^{
- expect(testManager.lifecycleState).to(match(SDLLifecycleStateStarted));
+ expect(testManager.lifecycleState).to(match(SDLLifecycleStateReconnecting));
});
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingMediaConfigurationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingMediaConfigurationSpec.m
index 447dac87b..56b66ea5d 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingMediaConfigurationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingMediaConfigurationSpec.m
@@ -17,7 +17,7 @@ describe(@"a streaming media configuration", ^{
__block SDLStreamingEncryptionFlag testEncryptionFlag = SDLStreamingEncryptionFlagNone;
__block SDLFakeStreamingManagerDataSource *testDataSource = nil;
__block NSDictionary<NSString *, id> *testVideoEncoderSettings = nil;
- __block UIWindow *testWindow = nil;
+ __block UIViewController *testViewController = nil;
beforeEach(^{
testFakeSecurityManager = [[SDLFakeSecurityManager alloc] init];
@@ -25,10 +25,10 @@ describe(@"a streaming media configuration", ^{
testVideoEncoderSettings = @{
(__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate : @1
};
- testWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
+ testViewController = [[UIViewController alloc] init];
testEncryptionFlag = SDLStreamingEncryptionFlagAuthenticateAndEncrypt;
- testConfig = [[SDLStreamingMediaConfiguration alloc] initWithSecurityManagers:@[testFakeSecurityManager.class] encryptionFlag:testEncryptionFlag videoSettings:testVideoEncoderSettings dataSource:testDataSource window:testWindow];
+ testConfig = [[SDLStreamingMediaConfiguration alloc] initWithSecurityManagers:@[testFakeSecurityManager.class] encryptionFlag:testEncryptionFlag videoSettings:testVideoEncoderSettings dataSource:testDataSource rootViewController:testViewController];
});
it(@"should have properly set properties", ^{
@@ -36,7 +36,7 @@ describe(@"a streaming media configuration", ^{
expect(@(testConfig.maximumDesiredEncryption)).to(equal(@(SDLStreamingEncryptionFlagAuthenticateAndEncrypt)));
expect(testConfig.customVideoEncoderSettings).to(equal(testVideoEncoderSettings));
expect(testConfig.dataSource).to(equal(testDataSource));
- expect(testConfig.window).to(equal(testWindow));
+ expect(testConfig.rootViewController).to(equal(testViewController));
});
});
@@ -50,7 +50,7 @@ describe(@"a streaming media configuration", ^{
expect(@(testConfig.maximumDesiredEncryption)).to(equal(@(SDLStreamingEncryptionFlagNone)));
expect(testConfig.customVideoEncoderSettings).to(beNil());
expect(testConfig.dataSource).to(beNil());
- expect(testConfig.window).to(beNil());
+ expect(testConfig.rootViewController).to(beNil());
});
});
@@ -68,7 +68,7 @@ describe(@"a streaming media configuration", ^{
expect(@(testConfig.maximumDesiredEncryption)).to(equal(@(SDLStreamingEncryptionFlagAuthenticateAndEncrypt)));
expect(testConfig.customVideoEncoderSettings).to(beNil());
expect(testConfig.dataSource).to(beNil());
- expect(testConfig.window).to(beNil());
+ expect(testConfig.rootViewController).to(beNil());
});
});
});
diff --git a/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m b/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
index 9eb2f019d..8413e6abf 100644
--- a/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
+++ b/SmartDeviceLinkTests/ProxySpecs/SDLHapticManagerSpec.m
@@ -19,8 +19,7 @@
#import "SDLTouchEvent.h"
#import "SDLTouch.h"
-BOOL compareRectangle(SDLRectangle *sdlRectangle, CGRect cgRect)
-{
+BOOL compareRectangle(SDLRectangle *sdlRectangle, CGRect cgRect) {
expect(sdlRectangle.x).to(equal(cgRect.origin.x));
expect(sdlRectangle.y).to(equal(cgRect.origin.y));
expect(sdlRectangle.width).to(equal(cgRect.size.width));
@@ -47,8 +46,8 @@ describe(@"the haptic manager", ^{
uiWindow = [[UIWindow alloc] init];
uiViewController = [[UIViewController alloc] init];
-
- [uiWindow addSubview:uiViewController.view];
+
+ uiWindow.rootViewController = uiViewController;
OCMExpect([[sdlLifecycleManager stub] sendManagerRequest:[OCMArg checkWithBlock:^BOOL(id value){
BOOL isFirstArg = [value isKindOfClass:[SDLSendHapticData class]];
@@ -62,10 +61,10 @@ describe(@"the haptic manager", ^{
context(@"when disabled", ^{
beforeEach(^{
viewRect1 = CGRectMake(101, 101, 50, 50);
- UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
- [uiWindow insertSubview:textField1 aboveSubview:uiWindow];
+ UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
+ [uiViewController.view addSubview:textField1];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = NO;
[hapticManager updateInterfaceLayout];
});
@@ -79,7 +78,7 @@ describe(@"the haptic manager", ^{
context(@"when initialized with no focusable view", ^{
beforeEach(^{
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
[hapticManager updateInterfaceLayout];
});
@@ -93,9 +92,9 @@ describe(@"the haptic manager", ^{
beforeEach(^{
viewRect1 = CGRectMake(101, 101, 50, 50);
UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
- [uiWindow insertSubview:textField1 aboveSubview:uiWindow];
+ [uiViewController.view addSubview:textField1];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -119,10 +118,10 @@ describe(@"the haptic manager", ^{
context(@"when initialized with single button view", ^{
beforeEach(^{
viewRect1 = CGRectMake(101, 101, 50, 50);
- UIButton *button = [[UIButton alloc] initWithFrame:viewRect1];
- [uiWindow addSubview:button];
+ UIButton *button = [[UIButton alloc] initWithFrame:viewRect1];
+ [uiViewController.view addSubview:button];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -145,16 +144,16 @@ describe(@"the haptic manager", ^{
context(@"when initialized with no views and then updated with two additional views", ^{
beforeEach(^{
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
viewRect1 = CGRectMake(101, 101, 50, 50);
- UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
+ UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
[uiViewController.view addSubview:textField1];
viewRect2 = CGRectMake(201, 201, 50, 50);
- UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
+ UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[uiViewController.view addSubview:textField2];
[hapticManager updateInterfaceLayout];
@@ -174,8 +173,8 @@ describe(@"the haptic manager", ^{
SDLHapticRect *sdlhapticRect2 = hapticRectData[1];
SDLRectangle *sdlRect2 = sdlhapticRect2.rect;
- compareRectangle(sdlRect1, viewRect1);
- compareRectangle(sdlRect2, viewRect2);
+ compareRectangle(sdlRect1, viewRect2);
+ compareRectangle(sdlRect2, viewRect1);
}
});
});
@@ -193,7 +192,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[textField addSubview:textField2];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -231,7 +230,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[button addSubview:textField2];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -266,7 +265,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:viewRect2];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
@@ -297,7 +296,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:viewRect1];
[uiViewController.view addSubview:textField1];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
@@ -322,8 +321,8 @@ describe(@"the haptic manager", ^{
SDLHapticRect *sdlhapticRect2 = hapticRectData[1];
SDLRectangle *sdlRect2 = sdlhapticRect2.rect;
- compareRectangle(sdlRect1, viewRect1);
- compareRectangle(sdlRect2, viewRect2);
+ compareRectangle(sdlRect1, viewRect2);
+ compareRectangle(sdlRect2, viewRect1);
}
});
});
@@ -336,7 +335,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:CGRectMake(201, 201, 50, 50)];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -358,7 +357,7 @@ describe(@"the haptic manager", ^{
UITextField *textField2 = [[UITextField alloc] initWithFrame:CGRectMake(126, 126, 50, 50)];
[uiViewController.view addSubview:textField2];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
@@ -374,7 +373,7 @@ describe(@"the haptic manager", ^{
UITextField *textField1 = [[UITextField alloc] initWithFrame:CGRectMake(101, 101, 50, 50)];
[uiWindow insertSubview:textField1 aboveSubview:uiWindow];
- hapticManager = [[SDLFocusableItemLocator alloc] initWithWindow:uiWindow connectionManager:sdlLifecycleManager];
+ hapticManager = [[SDLFocusableItemLocator alloc] initWithViewController:uiViewController connectionManager:sdlLifecycleManager];
hapticManager.enableHapticDataRequests = YES;
[hapticManager updateInterfaceLayout];
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/PayloadSpecs/SDLRPCPayloadSpec.m b/SmartDeviceLinkTests/RPCSpecs/PayloadSpecs/SDLRPCPayloadSpec.m
index f0632eb87..cde24a77a 100644
--- a/SmartDeviceLinkTests/RPCSpecs/PayloadSpecs/SDLRPCPayloadSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/PayloadSpecs/SDLRPCPayloadSpec.m
@@ -19,7 +19,7 @@ __block NSDictionary* dict = @{SDLNameResponse:
@{SDLNameParameters:@{},
SDLNameOperationName:SDLNameDeleteCommand}};
-NSData* (^testData)() = ^NSData* {
+NSData* (^testData)(void) = ^NSData* {
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:0];
NSData* binaryData = [NSData dataWithBytes:"PrimitiveString" length:strlen("PrimitiveString")];
diff --git a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
index 75c0518c4..e1487076a 100644
--- a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m
@@ -7,6 +7,7 @@
#import <Nimble/Nimble.h>
#import <OCMock/OCMock.h>
+#import "SDLCarWindowViewController.h"
#import "SDLConnectionManagerType.h"
#import "SDLControlFramePayloadAudioStartServiceAck.h"
#import "SDLControlFramePayloadConstants.h"
@@ -46,7 +47,7 @@ QuickSpecBegin(SDLStreamingMediaLifecycleManagerSpec)
describe(@"the streaming media manager", ^{
__block SDLStreamingMediaLifecycleManager *streamingLifecycleManager = nil;
__block SDLStreamingMediaConfiguration *testConfiguration = [SDLStreamingMediaConfiguration insecureConfiguration];
- __block UIWindow *testWindow = [[UIWindow alloc] init];
+ __block SDLCarWindowViewController *testViewController = [[SDLCarWindowViewController alloc] init];
__block SDLFakeStreamingManagerDataSource *testDataSource = [[SDLFakeStreamingManagerDataSource alloc] init];
__block NSString *someBackgroundTitleString = nil;
__block TestConnectionManager *testConnectionManager = nil;
@@ -65,7 +66,7 @@ describe(@"the streaming media manager", ^{
(__bridge NSString *)kVTCompressionPropertyKey_ExpectedFrameRate : @1
};
testConfiguration.dataSource = testDataSource;
- testConfiguration.window = testWindow;
+ testConfiguration.rootViewController = testViewController;
someBackgroundTitleString = @"Open Test App";
testConnectionManager = [[TestConnectionManager alloc] init];
streamingLifecycleManager = [[SDLStreamingMediaLifecycleManager alloc] initWithConnectionManager:testConnectionManager configuration:testConfiguration];
diff --git a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
index 43a2f6fab..86204073c 100644
--- a/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
+++ b/SmartDeviceLinkTests/UtilitiesSpecs/Touches/SDLTouchManagerSpec.m
@@ -44,7 +44,6 @@ describe(@"SDLTouchManager Tests", ^{
expect(touchManager.touchEventDelegate).to(beNil());
expect(@(touchManager.tapDistanceThreshold)).to(equal(@50));
expect(@(touchManager.tapTimeThreshold)).to(beCloseTo(@0.4).within(0.0001));
- expect(@(touchManager.movementTimeThreshold)).to(beCloseTo(@0.05).within(0.0001));
expect(@(touchManager.isTouchEnabled)).to(beTruthy());
});
});
@@ -441,8 +440,7 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panStartTouchCoord = [[SDLTouchCoord alloc] init];
panStartTouchCoord.x = @(panStartPoint.x);
panStartTouchCoord.y = @(panStartPoint.y);
- double movementTimeThresholdOffset = (touchManager.movementTimeThreshold + .01) * 1000;
- NSUInteger panStartTimeStamp = ([[NSDate date] timeIntervalSince1970] * 1000) + movementTimeThresholdOffset;
+ NSUInteger panStartTimeStamp = ([[NSDate date] timeIntervalSince1970] * 1000);
SDLTouchEvent* panStartTouchEvent = [[SDLTouchEvent alloc] init];
panStartTouchEvent.coord = [NSArray arrayWithObject:panStartTouchCoord];
panStartTouchEvent.timeStamp = [NSArray arrayWithObject:@(panStartTimeStamp)];
@@ -455,7 +453,7 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panMoveTouchCoord = [[SDLTouchCoord alloc] init];
panMoveTouchCoord.x = @(panMovePoint.x);
panMoveTouchCoord.y = @(panMovePoint.y);
- NSUInteger panMoveTimeStamp = panStartTimeStamp + movementTimeThresholdOffset;
+ NSUInteger panMoveTimeStamp = panStartTimeStamp;
SDLTouchEvent* panMoveTouchEvent = [[SDLTouchEvent alloc] init];
panMoveTouchEvent.coord = [NSArray arrayWithObject:panMoveTouchCoord];
panMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panMoveTimeStamp)];
@@ -468,10 +466,9 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panSecondMoveTouchCoord = [[SDLTouchCoord alloc] init];
panSecondMoveTouchCoord.x = @(panSecondMovePoint.x);
panSecondMoveTouchCoord.y = @(panSecondMovePoint.y);
- NSUInteger panSecondMoveTimeStamp = panMoveTimeStamp + movementTimeThresholdOffset;
SDLTouchEvent* panSecondMoveTouchEvent = [[SDLTouchEvent alloc] init];
panSecondMoveTouchEvent.coord = [NSArray arrayWithObject:panSecondMoveTouchCoord];
- panSecondMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panSecondMoveTimeStamp)];
+ panSecondMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panMoveTimeStamp)];
panSecondMoveOnTouchEvent = [[SDLOnTouchEvent alloc] init];
panSecondMoveOnTouchEvent.event = [NSArray arrayWithObject:panSecondMoveTouchEvent];
panSecondMoveOnTouchEvent.type = SDLTouchTypeMove;
@@ -481,10 +478,9 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panEndTouchCoord = [[SDLTouchCoord alloc] init];
panEndTouchCoord.x = @(panEndPoint.x);
panEndTouchCoord.y = @(panEndPoint.y);
- NSUInteger panEndTimeStamp = panSecondMoveTimeStamp + movementTimeThresholdOffset;
SDLTouchEvent* panEndTouchEvent = [[SDLTouchEvent alloc] init];
panEndTouchEvent.coord = [NSArray arrayWithObject:panEndTouchCoord];
- panEndTouchEvent.timeStamp = [NSArray arrayWithObject:@(panEndTimeStamp)];
+ panEndTouchEvent.timeStamp = [NSArray arrayWithObject:@(panMoveTimeStamp)];
panEndOnTouchEvent = [[SDLOnTouchEvent alloc] init];
panEndOnTouchEvent.event = [NSArray arrayWithObject:panEndTouchEvent];
panEndOnTouchEvent.type = SDLTouchTypeEnd;
@@ -494,10 +490,9 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panCancelAfterMoveTouchCoord = [[SDLTouchCoord alloc] init];
panCancelAfterMoveTouchCoord.x = @(panCancelPointAfterMove.x);
panCancelAfterMoveTouchCoord.y = @(panCancelPointAfterMove.y);
- NSUInteger panCancelAfterMoveTimeStamp = panMoveTimeStamp + movementTimeThresholdOffset;
SDLTouchEvent* panCancelAfterMoveTouchEvent = [[SDLTouchEvent alloc] init];
panCancelAfterMoveTouchEvent.coord = [NSArray arrayWithObject:panCancelAfterMoveTouchCoord];
- panCancelAfterMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panCancelAfterMoveTimeStamp)];
+ panCancelAfterMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panMoveTimeStamp)];
panCancelAfterMoveOnTouchEvent = [[SDLOnTouchEvent alloc] init];
panCancelAfterMoveOnTouchEvent.event = [NSArray arrayWithObject:panCancelAfterMoveTouchEvent];
panCancelAfterMoveOnTouchEvent.type = SDLTouchTypeCancel;
@@ -507,10 +502,9 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* panCancelAfterSecondMoveTouchCoord = [[SDLTouchCoord alloc] init];
panCancelAfterSecondMoveTouchCoord.x = @(panCancelPointAfterSecondMove.x);
panCancelAfterSecondMoveTouchCoord.y = @(panCancelPointAfterSecondMove.y);
- NSUInteger panCancelAfterSecondMoveTimeStamp = panEndTimeStamp;
SDLTouchEvent* panCancelAfterSecondMoveTouchEvent = [[SDLTouchEvent alloc] init];
panCancelAfterSecondMoveTouchEvent.coord = [NSArray arrayWithObject:panCancelAfterSecondMoveTouchCoord];
- panCancelAfterSecondMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panCancelAfterSecondMoveTimeStamp)];
+ panCancelAfterSecondMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(panMoveTimeStamp)];
panCancelAfterSecondMoveOnTouchEvent = [[SDLOnTouchEvent alloc] init];
panCancelAfterSecondMoveOnTouchEvent.event = [NSArray arrayWithObject:panCancelAfterSecondMoveTouchEvent];
panCancelAfterSecondMoveOnTouchEvent.type = SDLTouchTypeCancel;
@@ -553,7 +547,9 @@ describe(@"SDLTouchManager Tests", ^{
performTouchEvent(touchManager, panStartOnTouchEvent);
performTouchEvent(touchManager, panMoveOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, panSecondMoveOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, panEndOnTouchEvent);
expectedDidCallBeginPan = YES;
@@ -632,7 +628,9 @@ describe(@"SDLTouchManager Tests", ^{
performTouchEvent(touchManager, panStartOnTouchEvent);
performTouchEvent(touchManager, panMoveOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, panSecondMoveOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, panCancelAfterMoveOnTouchEvent);
expectedDidCallBeginPan = YES;
@@ -707,11 +705,10 @@ describe(@"SDLTouchManager Tests", ^{
SDLTouchCoord* secondFingerMoveTouchCoord = [[SDLTouchCoord alloc] init];
secondFingerMoveTouchCoord.x = @(secondFingerTouchCoord.x.floatValue - 50);
secondFingerMoveTouchCoord.y = @(secondFingerTouchCoord.y.floatValue - 40);
- NSUInteger secondFingerMoveTimeStamp = secondFingerTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
SDLTouchEvent* secondFingerMoveTouchEvent = [[SDLTouchEvent alloc] init];
secondFingerMoveTouchEvent.touchEventId = @1;
secondFingerMoveTouchEvent.coord = [NSArray arrayWithObject:secondFingerMoveTouchCoord];
- secondFingerMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerMoveTimeStamp)];
+ secondFingerMoveTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerTimeStamp)];
pinchMoveSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
pinchMoveSecondFingerOnTouchEvent.event = [NSArray arrayWithObject:secondFingerMoveTouchEvent];
pinchMoveSecondFingerOnTouchEvent.type = SDLTouchTypeMove;
@@ -723,11 +720,10 @@ describe(@"SDLTouchManager Tests", ^{
// Second finger end
SDLTouchCoord* secondFingerEndTouchCoord = secondFingerMoveTouchCoord;
- NSUInteger secondFingerEndTimeStamp = secondFingerMoveTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
SDLTouchEvent* secondFingerEndTouchEvent = [[SDLTouchEvent alloc] init];
secondFingerEndTouchEvent.touchEventId = @1;
secondFingerEndTouchEvent.coord = [NSArray arrayWithObject:secondFingerEndTouchCoord];
- secondFingerEndTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerEndTimeStamp)];
+ secondFingerEndTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerTimeStamp)];
pinchEndSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
pinchEndSecondFingerOnTouchEvent.event = [NSArray arrayWithObject:secondFingerEndTouchEvent];
pinchEndSecondFingerOnTouchEvent.type = SDLTouchTypeEnd;
@@ -735,11 +731,10 @@ describe(@"SDLTouchManager Tests", ^{
// First finger cancel
SDLTouchCoord* firstFingerCanceledTouchCoord = secondFingerMoveTouchCoord;
- NSUInteger firstFingerCanceledTimeStamp = secondFingerMoveTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
SDLTouchEvent* firstFingerCanceledTouchEvent = [[SDLTouchEvent alloc] init];
firstFingerCanceledTouchEvent.touchEventId = @0;
firstFingerCanceledTouchEvent.coord = [NSArray arrayWithObject:firstFingerCanceledTouchCoord];
- firstFingerCanceledTouchEvent.timeStamp = [NSArray arrayWithObject:@(firstFingerCanceledTimeStamp)];
+ firstFingerCanceledTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerTimeStamp)];
pinchCancelFirstFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
pinchCancelFirstFingerOnTouchEvent.event = [NSArray arrayWithObject:firstFingerCanceledTouchEvent];
pinchCancelFirstFingerOnTouchEvent.type = SDLTouchTypeCancel;
@@ -747,11 +742,10 @@ describe(@"SDLTouchManager Tests", ^{
// Second finger cancel
SDLTouchCoord* secondFingerCanceledTouchCoord = secondFingerMoveTouchCoord;
- NSUInteger secondFingerCanceledTimeStamp = firstFingerTimeStamp + ((touchManager.movementTimeThreshold + 0.1) * 1000);
SDLTouchEvent* secondFingerCanceledTouchEvent = [[SDLTouchEvent alloc] init];
secondFingerCanceledTouchEvent.touchEventId = @1;
secondFingerCanceledTouchEvent.coord = [NSArray arrayWithObject:secondFingerCanceledTouchCoord];
- secondFingerCanceledTouchEvent.timeStamp = [NSArray arrayWithObject:@(secondFingerCanceledTimeStamp)];
+ secondFingerCanceledTouchEvent.timeStamp = [NSArray arrayWithObject:@(firstFingerTimeStamp)];
pinchCancelSecondFingerOnTouchEvent = [[SDLOnTouchEvent alloc] init];
pinchCancelSecondFingerOnTouchEvent.event = [NSArray arrayWithObject:secondFingerCanceledTouchEvent];
pinchCancelSecondFingerOnTouchEvent.type = SDLTouchTypeCancel;
@@ -799,6 +793,7 @@ describe(@"SDLTouchManager Tests", ^{
performTouchEvent(touchManager, pinchStartFirstFingerOnTouchEvent);
performTouchEvent(touchManager, pinchStartSecondFingerOnTouchEvent);
performTouchEvent(touchManager, pinchMoveSecondFingerOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, pinchEndSecondFingerOnTouchEvent);
expectedDidCallBeginPinch = YES;
@@ -879,6 +874,7 @@ describe(@"SDLTouchManager Tests", ^{
performTouchEvent(touchManager, pinchStartFirstFingerOnTouchEvent);
performTouchEvent(touchManager, pinchStartSecondFingerOnTouchEvent);
performTouchEvent(touchManager, pinchMoveSecondFingerOnTouchEvent);
+ [touchManager syncFrame];
performTouchEvent(touchManager, pinchCancelSecondFingerOnTouchEvent);
expectedDidCallBeginPinch = YES;