summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2018-08-16 13:06:19 -0400
committerGitHub <noreply@github.com>2018-08-16 13:06:19 -0400
commit01fbc3602a19c18f3e999584639eac3ca933cc77 (patch)
treefd868a5591b5bf48d57cf68cf6bf03ff9f9f29a9
parent43efffc3e883d1beee890b9dc70cf948f448a767 (diff)
parenta3f56fbe66cd6954040ee05806d5df0d418b742c (diff)
downloadsdl_ios-01fbc3602a19c18f3e999584639eac3ca933cc77.tar.gz
Merge pull request #991 from smartdevicelink/feature/issue_599_expand_mobile_putfile
SDL 0037 Expand Mobile Putfile RPC
-rw-r--r--SmartDeviceLink-iOS.podspec1
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj22
-rw-r--r--SmartDeviceLink.podspec1
-rw-r--r--SmartDeviceLink/SDLConfiguration.h108
-rw-r--r--SmartDeviceLink/SDLConfiguration.m47
-rw-r--r--SmartDeviceLink/SDLFile.m16
-rw-r--r--SmartDeviceLink/SDLFileManager.h13
-rw-r--r--SmartDeviceLink/SDLFileManager.m135
-rw-r--r--SmartDeviceLink/SDLFileManagerConfiguration.h54
-rw-r--r--SmartDeviceLink/SDLFileManagerConfiguration.m47
-rw-r--r--SmartDeviceLink/SDLLifecycleManager.m5
-rw-r--r--SmartDeviceLink/SDLManager.m3
-rw-r--r--SmartDeviceLink/SDLNames.h1
-rw-r--r--SmartDeviceLink/SDLNames.m1
-rw-r--r--SmartDeviceLink/SDLPutFile.h108
-rw-r--r--SmartDeviceLink/SDLPutFile.m62
-rw-r--r--SmartDeviceLink/SDLPutFileResponse.h2
-rw-r--r--SmartDeviceLink/SDLResult.h5
-rw-r--r--SmartDeviceLink/SDLResult.m1
-rw-r--r--SmartDeviceLink/SDLTextAndGraphicManager.m49
-rw-r--r--SmartDeviceLink/SDLUploadFileOperation.m25
-rw-r--r--SmartDeviceLink/SmartDeviceLink.h1
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m10
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLConfigurationSpec.m82
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m127
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m18
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m3
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m4
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m3
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m2
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m82
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLUploadFileOperationSpec.m7
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLResultSpec.m1
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddCommandSpec.m6
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m5
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLGetVehicleDataSpec.m3
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLPutFileSpec.m132
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLShowSpec.m2
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSubscribeVehicleDataSpec.m3
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLUnsubscribeVehicleDataSpec.m3
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLPutFileResponseSpec.m9
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlCapabilitiesSpec.m5
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlDataSpec.m3
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m5
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageSpec.m6
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlCapabilitiesSpec.m5
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlDataSpec.m12
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRemoteControlCapabilitiesSpec.m3
-rw-r--r--SmartDeviceLinkTests/SDLFileManagerConfigurationSpec.m50
-rw-r--r--SmartDeviceLink_Example/Classes/ProxyManager.m3
-rw-r--r--SmartDeviceLink_Example/ProxyManager.swift2
51 files changed, 1106 insertions, 197 deletions
diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec
index c7af62700..ddaa964d7 100644
--- a/SmartDeviceLink-iOS.podspec
+++ b/SmartDeviceLink-iOS.podspec
@@ -107,6 +107,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLErrorConstants.h',
'SmartDeviceLink/SDLFile.h',
'SmartDeviceLink/SDLFileManager.h',
+'SmartDeviceLink/SDLFileManagerConfiguration.h',
'SmartDeviceLink/SDLFileManagerConstants.h',
'SmartDeviceLink/SDLFileType.h',
'SmartDeviceLink/SDLFuelCutoffStatus.h',
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index 7320fe8dd..e75e5a10c 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -1192,6 +1192,8 @@
5DF40B28208FDA9700DD6FDA /* SDLVoiceCommandManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DF40B27208FDA9700DD6FDA /* SDLVoiceCommandManagerSpec.m */; };
5DFFB9151BD7C89700DB3F04 /* SDLConnectionManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */; };
8800871E20A6356D008E1EA0 /* ButtonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8800871B20A6338C008E1EA0 /* ButtonManager.m */; };
+ 880245A420F79C3400ED195B /* SDLFileManagerConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 880245A220F79C3400ED195B /* SDLFileManagerConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 880245A520F79C3400ED195B /* SDLFileManagerConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 880245A320F79C3400ED195B /* SDLFileManagerConfiguration.m */; };
8803A0AF208E2A3A009FDC02 /* AudioManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8803A0AC208E2907009FDC02 /* AudioManager.m */; };
8803A0B2208E7CA4009FDC02 /* VehicleDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8803A0B1208E7CA4009FDC02 /* VehicleDataManager.m */; };
880E35B42088F75A00181259 /* SDLSystemCapabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 880E35B22088F75A00181259 /* SDLSystemCapabilityManager.m */; };
@@ -1224,6 +1226,7 @@
88802FF620853CD500E9EBC6 /* SmartDeviceLinkSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 88802FEF20853AE600E9EBC6 /* SmartDeviceLinkSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8880B2EF21021E37004721DB /* TextValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8880B2ED21021964004721DB /* TextValidator.swift */; };
8880B2F421022896004721DB /* TextValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 8880B2F121022887004721DB /* TextValidator.m */; };
+ 8886EB982111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8886EB972111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m */; };
888D178F207E7F42008E9F8F /* ButtonManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888D178D207E7F0E008E9F8F /* ButtonManager.swift */; };
888D1790207E815C008E9F8F /* AppConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 8863B597207D2388002D6459 /* AppConstants.m */; };
88A0AA56207CFE5D0075132C /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0AA55207CFE5C0075132C /* AppUserDefaults.swift */; };
@@ -2678,6 +2681,8 @@
5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLConnectionManagerType.h; sourceTree = "<group>"; };
8800871A20A6338C008E1EA0 /* ButtonManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonManager.h; sourceTree = "<group>"; };
8800871B20A6338C008E1EA0 /* ButtonManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ButtonManager.m; sourceTree = "<group>"; };
+ 880245A220F79C3400ED195B /* SDLFileManagerConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLFileManagerConfiguration.h; sourceTree = "<group>"; };
+ 880245A320F79C3400ED195B /* SDLFileManagerConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLFileManagerConfiguration.m; sourceTree = "<group>"; };
8803A0AB208E2907009FDC02 /* AudioManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioManager.h; sourceTree = "<group>"; };
8803A0AC208E2907009FDC02 /* AudioManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioManager.m; sourceTree = "<group>"; };
8803A0B0208E7CA4009FDC02 /* VehicleDataManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VehicleDataManager.h; sourceTree = "<group>"; };
@@ -2711,6 +2716,7 @@
8880B2ED21021964004721DB /* TextValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextValidator.swift; sourceTree = "<group>"; };
8880B2F021022887004721DB /* TextValidator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextValidator.h; sourceTree = "<group>"; };
8880B2F121022887004721DB /* TextValidator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TextValidator.m; sourceTree = "<group>"; };
+ 8886EB972111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLFileManagerConfigurationSpec.m; sourceTree = "<group>"; };
888D178D207E7F0E008E9F8F /* ButtonManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonManager.swift; sourceTree = "<group>"; };
88A0AA55207CFE5C0075132C /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = "<group>"; };
88A0AA57207CFE650075132C /* ProxyManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyManager.swift; sourceTree = "<group>"; };
@@ -4746,6 +4752,7 @@
5D82042A1BCEA91E00D0A41B /* Files */ = {
isa = PBXGroup;
children = (
+ 880245A120F79BDA00ED195B /* Configuration */,
5D8204201BCEA89A00D0A41B /* SDLFileManager.h */,
5D8204211BCEA89A00D0A41B /* SDLFileManager.m */,
5D7F87F51CE51CD8002DD7C4 /* File Types */,
@@ -5029,10 +5036,11 @@
isa = PBXGroup;
children = (
5DBEFA551F434F8A009EE295 /* Utilities */,
+ 5DB1BCE01D243DDE002FFC37 /* SDLConfigurationSpec.m */,
+ 8886EB972111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m */,
5DB1BCDC1D243DC3002FFC37 /* SDLLifecycleConfigurationSpec.m */,
5DB1BCDE1D243DD3002FFC37 /* SDLLockScreenConfigurationSpec.m */,
5DBEFA531F434B9E009EE295 /* SDLStreamingMediaConfigurationSpec.m */,
- 5DB1BCE01D243DDE002FFC37 /* SDLConfigurationSpec.m */,
);
name = Configurations;
sourceTree = "<group>";
@@ -5336,6 +5344,15 @@
name = Menu;
sourceTree = "<group>";
};
+ 880245A120F79BDA00ED195B /* Configuration */ = {
+ isa = PBXGroup;
+ children = (
+ 880245A220F79C3400ED195B /* SDLFileManagerConfiguration.h */,
+ 880245A320F79C3400ED195B /* SDLFileManagerConfiguration.m */,
+ );
+ name = Configuration;
+ sourceTree = "<group>";
+ };
880E35B12088F73400181259 /* System Capabilities */ = {
isa = PBXGroup;
children = (
@@ -5753,6 +5770,7 @@
5D61FDDA1A84238C00846EE7 /* SDLTransportDelegate.h in Headers */,
5D61FC411A84238C00846EE7 /* SDLAppHMIType.h in Headers */,
5D61FCEE1A84238C00846EE7 /* SDLListFilesResponse.h in Headers */,
+ 880245A420F79C3400ED195B /* SDLFileManagerConfiguration.h in Headers */,
5D61FC491A84238C00846EE7 /* SDLAudioType.h in Headers */,
5D61FC761A84238C00846EE7 /* SDLDeleteFile.h in Headers */,
5D61FD211A84238C00846EE7 /* SDLOnVehicleData.h in Headers */,
@@ -6348,6 +6366,7 @@
5D61FC421A84238C00846EE7 /* SDLAppHMIType.m in Sources */,
5D61FD421A84238C00846EE7 /* SDLPRNDL.m in Sources */,
E9C32B921AB20BA200F283AF /* SDLIAPSession.m in Sources */,
+ 880245A520F79C3400ED195B /* SDLFileManagerConfiguration.m in Sources */,
5D61FD0C1A84238C00846EE7 /* SDLOnEncodedSyncPData.m in Sources */,
5D61FD0A1A84238C00846EE7 /* SDLOnDriverDistraction.m in Sources */,
5D61FCED1A84238C00846EE7 /* SDLListFiles.m in Sources */,
@@ -6955,6 +6974,7 @@
162E83541A9BDE8B00906325 /* SDLEncodedSyncPDataResponseSpec.m in Sources */,
1EAA47582035AFD9000FE74B /* SDLHMISettingsControlDataSpec.m in Sources */,
162E83161A9BDE8B00906325 /* SDLOnHashChangeSpec.m in Sources */,
+ 8886EB982111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m in Sources */,
162E82FE1A9BDE8B00906325 /* SDLTBTStateSpec.m in Sources */,
5D5DBF0B1D48E5E600D4F914 /* SDLLockScreenViewControllerSnapshotTests.m in Sources */,
5DB1BCD41D243A8E002FFC37 /* SDLListFilesOperationSpec.m in Sources */,
diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec
index eeac8a8ac..c37e56f27 100644
--- a/SmartDeviceLink.podspec
+++ b/SmartDeviceLink.podspec
@@ -107,6 +107,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLErrorConstants.h',
'SmartDeviceLink/SDLFile.h',
'SmartDeviceLink/SDLFileManager.h',
+'SmartDeviceLink/SDLFileManagerConfiguration.h',
'SmartDeviceLink/SDLFileManagerConstants.h',
'SmartDeviceLink/SDLFileType.h',
'SmartDeviceLink/SDLFuelCutoffStatus.h',
diff --git a/SmartDeviceLink/SDLConfiguration.h b/SmartDeviceLink/SDLConfiguration.h
index 9f92cd6c1..2cd6420fd 100644
--- a/SmartDeviceLink/SDLConfiguration.h
+++ b/SmartDeviceLink/SDLConfiguration.h
@@ -8,6 +8,7 @@
#import <Foundation/Foundation.h>
+@class SDLFileManagerConfiguration;
@class SDLLifecycleConfiguration;
@class SDLLockScreenConfiguration;
@class SDLLogConfiguration;
@@ -28,56 +29,107 @@ NS_ASSUME_NONNULL_BEGIN
@property (copy, nonatomic, readonly) SDLLockScreenConfiguration *lockScreenConfig;
/**
- The log configuration.
+ * The log configuration.
*/
@property (copy, nonatomic, readonly) SDLLogConfiguration *loggingConfig;
/**
- The configuration
+ * The streaming media configuration.
*/
@property (copy, nonatomic, readonly) SDLStreamingMediaConfiguration *streamingMediaConfig;
/**
- Create a new configuration to be passed into SDLManager with a custom lifecycle, lock screen, and logging configuration.
+ * The file manager configuration.
+ */
+@property (copy, nonatomic, readonly) SDLFileManagerConfiguration *fileManagerConfig;
- @param lifecycleConfig The lifecycle configuration to be used.
- @param lockScreenConfig The lockscreen configuration to be used, or `enabledConfiguration` if nil.
- @param logConfig The logging configuration to be used, or `defaultConfiguration` if nil.
- @return The configuration
+/**
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen and logging configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @return The configuration
*/
-- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig;
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig __deprecated_msg("Use initWithLifecycle:lockScreen:logging:fileManager: instead");
/**
- Create a new configuration to be passed into SDLManager with a custom lifecycle, lock screen, and logging configuration.
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging and file manager configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param fileManagerConfig The file manager configuration to be used or `defaultConfiguration` if nil.
+ * @return The configuration
+ */
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig;
- @param lifecycleConfig The lifecycle configuration to be used.
- @param lockScreenConfig The lockscreen configuration to be used, or `enabledConfiguration` if nil.
- @param logConfig The logging configuration to be used, or `defaultConfiguration` if nil.
- @return The configuration
+/**
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen and logging configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @return The configuration
*/
-+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig NS_SWIFT_UNAVAILABLE("Use an initializer instead");
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig __deprecated_msg("Use configurationWithLifecycle:lockScreen:logging:fileManager: instead") NS_SWIFT_UNAVAILABLE("Use an initializer instead");
/**
- Create a new configuration to be passed into SDLManager with a custom lifecycle, lock screen, logging, and streaming media configuration.
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging and file manager configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param fileManagerConfig The file manager configuration to be used or `defaultConfiguration` if nil.
+ * @return The configuration
+ */
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig NS_SWIFT_UNAVAILABLE("Use an initializer instead");
- @param lifecycleConfig The lifecycle configuration to be used.
- @param lockScreenConfig The lockscreen configuration to be used, or `enabledConfiguration` if nil.
- @param logConfig The logging configuration to be used, or `defaultConfiguration` if nil.
- @param streamingMediaConfig The streaming media configuration to be used, or nil because it is not needed.
- @return The configuration
+/**
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging and streaming media configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param streamingMediaConfig The streaming media configuration to be used or nil if not used.
+ * @return The configuration
*/
-- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig;
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig __deprecated_msg("Use initWithLifecycle:lockScreen:logging:streamingMedia:fileManager: instead");
/**
- Create a new configuration to be passed into SDLManager with a custom lifecycle, lock screen, logging, and streaming media configuration.
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging, streaming media and file manager configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param streamingMediaConfig The streaming media configuration to be used or nil if not used.
+ * @param fileManagerConfig The file manager configuration to be used or `defaultConfiguration` if nil.
+ * @return The configuration
+ */
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig;
- @param lifecycleConfig The lifecycle configuration to be used.
- @param lockScreenConfig The lockscreen configuration to be used, or `enabledConfiguration` if nil.
- @param logConfig The logging configuration to be used, or `defaultConfiguration` if nil.
- @param streamingMediaConfig The streaming media configuration to be used, or nil because it is not needed.
- @return The configuration
+/**
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging and streaming media configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param streamingMediaConfig The streaming media configuration to be used or nil if not used.
+ * @return The configuration
+ */
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig __deprecated_msg("Use configurationWithLifecycle:lockScreen:logging:streamingMedia:fileManager: instead") NS_SWIFT_UNAVAILABLE("Use an initializer instead");
+
+/**
+ * Creates a new configuration to be passed to the SDLManager with custom lifecycle, lock screen, logging, streaming media and file manager configurations.
+ *
+ * @param lifecycleConfig The lifecycle configuration to be used.
+ * @param lockScreenConfig The lockscreen configuration to be used. If nil, the `enabledConfiguration` will be used.
+ * @param logConfig The logging configuration to be used. If nil, the `defaultConfiguration` will be used.
+ * @param streamingMediaConfig The streaming media configuration to be used or nil if not used.
+ * @param fileManagerConfig The file manager configuration to be used or `defaultConfiguration` if nil.
+ * @return The configuration
*/
-+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig NS_SWIFT_UNAVAILABLE("Use an initializer instead");
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig NS_SWIFT_UNAVAILABLE("Use an initializer instead");
@end
diff --git a/SmartDeviceLink/SDLConfiguration.m b/SmartDeviceLink/SDLConfiguration.m
index 98fddadc1..a96b27d68 100644
--- a/SmartDeviceLink/SDLConfiguration.m
+++ b/SmartDeviceLink/SDLConfiguration.m
@@ -8,6 +8,7 @@
#import "SDLConfiguration.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLLifecycleConfiguration.h"
#import "SDLLockScreenConfiguration.h"
#import "SDLLogConfiguration.h"
@@ -18,22 +19,18 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLConfiguration
- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfiguration {
- return [self initWithLifecycle:lifecycleConfiguration lockScreen:nil logging:nil];
-}
-
-+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfiguration {
- return [[self alloc] initWithLifecycle:lifecycleConfiguration lockScreen:nil logging:nil];
+ return [self initWithLifecycle:lifecycleConfiguration lockScreen:nil];
}
- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig {
- return [self initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:nil];
+ return [self initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:nil fileManager:nil];
}
-+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig {
- return [[self alloc] initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig];
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig {
+ return [self initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig fileManager:nil];
}
-- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig {
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig {
self = [super init];
if (!self) {
return nil;
@@ -42,15 +39,32 @@ NS_ASSUME_NONNULL_BEGIN
_lifecycleConfig = lifecycleConfig;
_lockScreenConfig = lockScreenConfig ?: [SDLLockScreenConfiguration enabledConfiguration];
_loggingConfig = logConfig ?: [SDLLogConfiguration defaultConfiguration];
+ _fileManagerConfig = fileManagerConfig ?: [SDLFileManagerConfiguration defaultConfiguration];
return self;
}
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfiguration {
+ return [self configurationWithLifecycle:lifecycleConfiguration lockScreen:nil];
+}
+
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig {
+ return [self configurationWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:nil fileManager:nil];
+}
+
+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig {
- return [[self alloc] initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig];
+ return [self configurationWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig fileManager:nil];
+}
+
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig {
+ return [[self alloc] initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig fileManager:fileManagerConfig];
}
- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig {
+ return [self initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig streamingMedia:streamingMediaConfig fileManager:nil];
+}
+
+- (instancetype)initWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig {
self = [super init];
if (!self) {
return nil;
@@ -59,8 +73,8 @@ NS_ASSUME_NONNULL_BEGIN
_lifecycleConfig = lifecycleConfig;
_lockScreenConfig = lockScreenConfig ?: [SDLLockScreenConfiguration enabledConfiguration];
_loggingConfig = logConfig ?: [SDLLogConfiguration defaultConfiguration];
- _streamingMediaConfig = streamingMediaConfig;
+ _streamingMediaConfig = streamingMediaConfig;
if (_streamingMediaConfig != nil) {
// If we have a streaming config, the apptype MUST be navigation or projection
NSAssert(([_lifecycleConfig.appType isEqualToEnum:SDLAppHMITypeNavigation] || [_lifecycleConfig.appType isEqualToEnum:SDLAppHMITypeProjection] || [_lifecycleConfig.additionalAppTypes containsObject:SDLAppHMITypeNavigation] || [_lifecycleConfig.additionalAppTypes containsObject:SDLAppHMITypeProjection]), @"You should only set a streaming media configuration if your app is a NAVIGATION or PROJECTION HMI type");
@@ -70,18 +84,23 @@ NS_ASSUME_NONNULL_BEGIN
NSAssert(!([_lifecycleConfig.appType isEqualToEnum:SDLAppHMITypeNavigation] || [_lifecycleConfig.appType isEqualToEnum:SDLAppHMITypeProjection] || [_lifecycleConfig.additionalAppTypes containsObject:SDLAppHMITypeNavigation] || [_lifecycleConfig.additionalAppTypes containsObject:SDLAppHMITypeProjection]), @"If your app is a NAVIGATION or PROJECTION HMI type, you must set a streaming media configuration on SDLConfiguration");
}
+ _fileManagerConfig = fileManagerConfig ?: [SDLFileManagerConfiguration defaultConfiguration];
+
return self;
}
+ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig {
- return [[self alloc] initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig streamingMedia:streamingMediaConfig];
+ return [self configurationWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig streamingMedia:streamingMediaConfig fileManager:nil];
+}
+
++ (instancetype)configurationWithLifecycle:(SDLLifecycleConfiguration *)lifecycleConfig lockScreen:(nullable SDLLockScreenConfiguration *)lockScreenConfig logging:(nullable SDLLogConfiguration *)logConfig streamingMedia:(nullable SDLStreamingMediaConfiguration *)streamingMediaConfig fileManager:(nullable SDLFileManagerConfiguration *)fileManagerConfig {
+ return [[self alloc] initWithLifecycle:lifecycleConfig lockScreen:lockScreenConfig logging:logConfig streamingMedia:streamingMediaConfig fileManager:fileManagerConfig];
}
#pragma mark - NSCopying
- (id)copyWithZone:(nullable NSZone *)zone {
- SDLConfiguration *new = [[SDLConfiguration allocWithZone:zone] initWithLifecycle: _lifecycleConfig lockScreen: _lockScreenConfig logging:_loggingConfig streamingMedia:_streamingMediaConfig];
-
+ SDLConfiguration *new = [[SDLConfiguration allocWithZone:zone] initWithLifecycle:_lifecycleConfig lockScreen:_lockScreenConfig logging:_loggingConfig streamingMedia:_streamingMediaConfig fileManager:_fileManagerConfig];
return new;
}
diff --git a/SmartDeviceLink/SDLFile.m b/SmartDeviceLink/SDLFile.m
index 522171f24..5e925711e 100644
--- a/SmartDeviceLink/SDLFile.m
+++ b/SmartDeviceLink/SDLFile.m
@@ -100,17 +100,17 @@ NS_ASSUME_NONNULL_BEGIN
/**
Initalizes a socket from which to read data.
+ @discussion A new `NSInputStream` is created when requested instead of returning the already open `NSInputStream`. This is done because once a opened, a stream *cannot* be closed and reopened. If the same file is accessed multiple times (i.e. a non-persistant file is uploaded before and after a disconnect from Core during the same session) the file cannot be accessed after the first access because the stream is closed once the upload is completed. Apple `NSInputStream` doc: https://developer.apple.com/documentation/foundation/nsstream/1411963-open
+
@return A socket
*/
- (NSInputStream *)inputStream {
- if (!_inputStream) {
- if (_fileURL) {
- // Data in file
- _inputStream = [[NSInputStream alloc] initWithURL:_fileURL];
- } else if (_data.length != 0) {
- // Data in memory
- _inputStream = [[NSInputStream alloc] initWithData:_data];
- }
+ if (_fileURL) {
+ // Data in file
+ _inputStream = [[NSInputStream alloc] initWithURL:_fileURL];
+ } else if (_data.length != 0) {
+ // Data in memory
+ _inputStream = [[NSInputStream alloc] initWithData:_data];
}
return _inputStream;
}
diff --git a/SmartDeviceLink/SDLFileManager.h b/SmartDeviceLink/SDLFileManager.h
index 49755aec6..e71948a37 100644
--- a/SmartDeviceLink/SDLFileManager.h
+++ b/SmartDeviceLink/SDLFileManager.h
@@ -12,6 +12,7 @@
#import "SDLFileManagerConstants.h"
@class SDLFile;
+@class SDLFileManagerConfiguration;
@protocol SDLConnectionManagerType;
@@ -66,7 +67,17 @@ typedef void (^SDLFileManagerStartupCompletionHandler)(BOOL success, NSError *__
*
* @return An instance of SDLFileManager
*/
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)manager NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)manager __deprecated_msg("Use initWithConnectionManager:configuration: instead");
+
+/**
+ * Creates a new file manager with a specified connection manager and configuration
+ *
+ * @param manager A connection manager to use to forward on RPCs
+ * @param configuration A configuration for this file manager session
+ *
+ * @return An instance of SDLFileManager
+ */
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)manager configuration:(SDLFileManagerConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
/**
* The manager stars up and attempts to fetch its initial list and transfer initial files.
diff --git a/SmartDeviceLink/SDLFileManager.m b/SmartDeviceLink/SDLFileManager.m
index c6ac7fc4b..717660f47 100644
--- a/SmartDeviceLink/SDLFileManager.m
+++ b/SmartDeviceLink/SDLFileManager.m
@@ -13,13 +13,13 @@
#import "SDLDeleteFileOperation.h"
#import "SDLError.h"
#import "SDLFile.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLFileWrapper.h"
#import "SDLGlobals.h"
#import "SDLListFilesOperation.h"
#import "SDLManager.h"
#import "SDLNotificationConstants.h"
#import "SDLPutFile.h"
-#import "SDLPutFileResponse.h"
#import "SDLStateMachine.h"
#import "SDLUploadFileOperation.h"
@@ -50,6 +50,10 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
@property (strong, nonatomic) SDLStateMachine *stateMachine;
@property (copy, nonatomic, nullable) SDLFileManagerStartupCompletionHandler startupCompletionHandler;
+@property (strong, nonatomic) NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *failedFileUploadsCount;
+@property (assign, nonatomic) UInt8 maxFileUploadAttempts;
+@property (assign, nonatomic) UInt8 maxArtworkUploadAttempts;
+
@end
#pragma mark Constants
@@ -59,6 +63,10 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
#pragma mark - Lifecycle
- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)manager {
+ return [self initWithConnectionManager:manager configuration:[SDLFileManagerConfiguration defaultConfiguration]];
+}
+
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)manager configuration:(SDLFileManagerConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
@@ -76,10 +84,13 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
_stateMachine = [[SDLStateMachine alloc] initWithTarget:self initialState:SDLFileManagerStateShutdown states:[self.class sdl_stateTransitionDictionary]];
+ _failedFileUploadsCount = [NSMutableDictionary dictionary];
+ _maxFileUploadAttempts = configuration.fileRetryCount + 1;
+ _maxArtworkUploadAttempts = configuration.artworkRetryCount + 1;
+
return self;
}
-
#pragma mark - Setup / Shutdown
- (void)startWithCompletionHandler:(nullable SDLFileManagerStartupCompletionHandler)handler {
@@ -94,6 +105,9 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
- (void)stop {
[self.stateMachine transitionToState:SDLFileManagerStateShutdown];
+
+ // Clear the failed uploads tracking so failed files can be uploaded again when a new connection has been established with Core
+ _failedFileUploadsCount = [NSMutableDictionary dictionary];
}
@@ -329,35 +343,6 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
});
}
-/**
- * Computes the total amount of bytes to be uploaded to the remote. This total is computed by summing up the file size of all files to be uploaded to the remote
- *
- * @param files All the files being uploaded to the remote
- * @return The total byte count
- */
-- (float)sdl_totalBytesToUpload:(NSArray<SDLFile *> *)files {
- float totalBytes = 0.0;
- for(SDLFile *file in files) {
- totalBytes += file.fileSize;
- }
-
- return totalBytes;
-}
-
-/**
- * Computes the percentage of files uploaded to the remote. This percentage is a decimal number between 0.0 - 1.0. It is calculated by dividing the total number of bytes in files successfully or unsuccessfully uploaded by the total number of bytes in all files to be uploaded.
- *
- * @param totalBytes The total number of bytes in all files to be uploaded
- * @param uploadedBytes The total number of bytes in files successfully or unsuccessfully uploaded
- * @return The upload percentage
- */
-- (float)sdl_uploadPercentage:(float)totalBytes uploadedBytes:(float)uploadedBytes {
- if (totalBytes == 0 || uploadedBytes == 0) {
- return 0.0;
- }
- return uploadedBytes / totalBytes;
-}
-
- (void)uploadFile:(SDLFile *)file completionHandler:(nullable SDLFileManagerUploadCompletionHandler)handler {
if (file == nil || file.data.length == 0) {
if (handler != nil) {
@@ -407,7 +392,18 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
if (success) {
[weakSelf.mutableRemoteFileNames addObject:fileName];
[weakSelf.uploadedEphemeralFileNames addObject:fileName];
+ } else {
+ self.failedFileUploadsCount = [self.class sdl_incrementFailedUploadCountForFileName:file.name failedFileUploadsCount:self.failedFileUploadsCount];
+
+ UInt8 maxUploadCount = [file isKindOfClass:[SDLArtwork class]] ? self.maxArtworkUploadAttempts : self.maxFileUploadAttempts;
+ if ([self sdl_canFileBeUploadedAgain:file maxUploadCount:maxUploadCount failedFileUploadsCount:self.failedFileUploadsCount]) {
+ SDLLogD(@"Attempting to resend file with name %@ after a failed upload attempt", file.name);
+ return [self sdl_uploadFile:file completionHandler:handler];
+ } else {
+ SDLLogE(@"File named %@ failed to upload. Max number of upload attempts reached", file.name);
+ }
}
+
if (uploadCompletion != nil) {
uploadCompletion(success, bytesAvailable, error);
}
@@ -424,7 +420,7 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
- (void)uploadArtwork:(SDLArtwork *)artwork completionHandler:(nullable SDLFileManagerUploadArtworkCompletionHandler)completion {
[self uploadFile:artwork completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) {
if (completion == nil) { return; }
- if ([self isErrorACannotOverwriteError:error]) {
+ if ([self sdl_isErrorCannotOverwriteError:error]) {
// Artwork with same name already uploaded to remote
return completion(true, artwork.name, bytesAvailable, nil);
}
@@ -443,7 +439,7 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
[self uploadFiles:artworks progressHandler:^BOOL(SDLFileName * _Nonnull fileName, float uploadPercentage, NSError * _Nullable error) {
if (progressHandler == nil) { return YES; }
- if ([self isErrorACannotOverwriteError:error]) {
+ if ([self sdl_isErrorCannotOverwriteError:error]) {
return progressHandler(fileName, uploadPercentage, nil);
}
return progressHandler(fileName, uploadPercentage, error);
@@ -458,7 +454,7 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
if (error != nil) {
for (NSString *erroredArtworkName in error.userInfo) {
- if (![self isErrorACannotOverwriteError:[error.userInfo objectForKey:erroredArtworkName]]) {
+ if (![self sdl_isErrorCannotOverwriteError:[error.userInfo objectForKey:erroredArtworkName]]) {
[successfulArtworkUploadNames removeObject:erroredArtworkName];
} else {
// An overwrite error means that an artwork with the same name is already uploaded to the remote
@@ -471,13 +467,80 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
}];
}
-- (BOOL)isErrorACannotOverwriteError:(NSError * _Nullable)error {
- if (error != nil && error.code == SDLFileManagerErrorCannotOverwrite) {
+#pragma mark Helpers
+
+/**
+ * Checks an error returned by Core to see if it is a "can not overwrite" error.
+ *
+ * @param error The error returned by SDL Core
+ * @return True if the error is an overwrite error; false if not
+ */
+- (BOOL)sdl_isErrorCannotOverwriteError:(NSError * _Nullable)error {
+ if (error != nil && error.domain == SDLErrorDomainFileManager && error.code == SDLFileManagerErrorCannotOverwrite) {
return YES;
}
return NO;
}
+/**
+ * Computes the total amount of bytes to be uploaded to the remote. This total is computed by summing up the file size of all files to be uploaded to the remote
+ *
+ * @param files All the files being uploaded to the remote
+ * @return The total byte count
+ */
+- (float)sdl_totalBytesToUpload:(NSArray<SDLFile *> *)files {
+ float totalBytes = 0.0;
+ for(SDLFile *file in files) {
+ totalBytes += file.fileSize;
+ }
+
+ return totalBytes;
+}
+
+/**
+ * Computes the percentage of files uploaded to the remote. This percentage is a decimal number between 0.0 - 1.0. It is calculated by dividing the total number of bytes in files successfully or unsuccessfully uploaded by the total number of bytes in all files to be uploaded.
+ *
+ * @param totalBytes The total number of bytes in all files to be uploaded
+ * @param uploadedBytes The total number of bytes in files successfully or unsuccessfully uploaded
+ * @return The upload percentage
+ */
+- (float)sdl_uploadPercentage:(float)totalBytes uploadedBytes:(float)uploadedBytes {
+ if (totalBytes == 0 || uploadedBytes == 0) {
+ return 0.0;
+ }
+ return uploadedBytes / totalBytes;
+}
+
+#pragma mark Reuploads
+
+/**
+ * Checks if an artwork needs to be uploaded to Core. The arwork should not be sent to Core if the artwork is already on Core or if the artwork is not on Core after the maximum number of repeated upload attempts has been reached.
+ *
+ * @param file The file to be uploaded to Core
+ * @param maxUploadCount The max number of times the file is allowed to be uploaded to Core
+ * @return True if the file still needs to be (re)sent to Core; false if not.
+ */
+- (BOOL)sdl_canFileBeUploadedAgain:(nullable SDLFile *)file maxUploadCount:(UInt8)maxUploadCount failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount {
+ if (!file || [self hasUploadedFile:file]) {
+ return NO;
+ }
+ NSNumber *failedUploadCount = failedFileUploadsCount[file.name];
+ return (failedUploadCount == nil) ? YES : (failedUploadCount.integerValue < maxUploadCount);
+}
+
+/**
+ * Increments the number of upload attempts for a file name by 1.
+ *
+ * @param fileName The name used to upload the file to Core
+ */
++ (NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)sdl_incrementFailedUploadCountForFileName:(SDLFileName *)fileName failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount {
+ NSNumber *currentFailedUploadCount = failedFileUploadsCount[fileName];
+ NSNumber *newFailedUploadCount = (currentFailedUploadCount != nil) ? @(currentFailedUploadCount.integerValue + 1) : @1;
+ failedFileUploadsCount[fileName] = newFailedUploadCount;
+ SDLLogW(@"File with name %@ failed to upload %@ times", fileName, newFailedUploadCount);
+ return failedFileUploadsCount;
+}
+
#pragma mark - Temporary Files
+ (NSURL *)temporaryFileDirectory {
diff --git a/SmartDeviceLink/SDLFileManagerConfiguration.h b/SmartDeviceLink/SDLFileManagerConfiguration.h
new file mode 100644
index 000000000..869e1db3e
--- /dev/null
+++ b/SmartDeviceLink/SDLFileManagerConfiguration.h
@@ -0,0 +1,54 @@
+//
+// SDLFileManagerConfiguration.h
+// SmartDeviceLink
+//
+// Created by Nicole on 7/12/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "NSNumber+NumberType.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLFileManagerConfiguration : NSObject <NSCopying>
+
+/**
+ * Defines the number of times the file manager will attempt to reupload `SDLArtwork` files in the event of a failed upload to Core.
+ *
+ * Defaults to 1. To disable reuploads, set to 0.
+ */
+@property (assign, nonatomic) UInt8 artworkRetryCount;
+
+/**
+ * Defines the number of times the file manager will attempt to reupload general `SDLFile`s in the event of a failed upload to Core.
+ *
+ * Defaults to 1. To disable reuploads, set to 0.
+ */
+@property (assign, nonatomic) UInt8 fileRetryCount;
+
+/**
+ * Creates a default file manager configuration.
+ *
+ * @return A default configuration that may be customized.
+ */
++ (instancetype)defaultConfiguration;
+
+/**
+ * Creates a file manager configuration.
+ *
+ * @return The configuration
+ */
+- (instancetype)init;
+
+/**
+ * Creates a file manager configuration with customized upload retry counts.
+ *
+ * @return The configuration
+ */
+- (instancetype)initWithArtworkRetryCount:(UInt8)artworkRetryCount fileRetryCount:(UInt8)fileRetryCount;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLFileManagerConfiguration.m b/SmartDeviceLink/SDLFileManagerConfiguration.m
new file mode 100644
index 000000000..4b125feb1
--- /dev/null
+++ b/SmartDeviceLink/SDLFileManagerConfiguration.m
@@ -0,0 +1,47 @@
+//
+// SDLFileManagerConfiguration.m
+// SmartDeviceLink
+//
+// Created by Nicole on 7/12/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import "SDLFileManagerConfiguration.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+static NSUInteger const DefaultRetryCount = 1;
+
+@implementation SDLFileManagerConfiguration
+
++ (instancetype)defaultConfiguration {
+ return [[self.class alloc] initWithArtworkRetryCount:DefaultRetryCount fileRetryCount:DefaultRetryCount];
+}
+
+- (instancetype)init {
+ return [self.class defaultConfiguration];
+}
+
+- (instancetype)initWithArtworkRetryCount:(UInt8)artworkRetryCount fileRetryCount:(UInt8)fileRetryCount {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _artworkRetryCount = artworkRetryCount;
+ _fileRetryCount = fileRetryCount;
+
+ return self;
+}
+
+
+#pragma mark - NSCopying
+
+- (id)copyWithZone:(nullable NSZone *)zone {
+ SDLFileManagerConfiguration *new = [[SDLFileManagerConfiguration allocWithZone:zone] initWithArtworkRetryCount:_artworkRetryCount fileRetryCount:_fileRetryCount];
+ return new;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLLifecycleManager.m b/SmartDeviceLink/SDLLifecycleManager.m
index dc85e918e..d41f01cf8 100644
--- a/SmartDeviceLink/SDLLifecycleManager.m
+++ b/SmartDeviceLink/SDLLifecycleManager.m
@@ -21,6 +21,7 @@
#import "SDLError.h"
#import "SDLFile.h"
#import "SDLFileManager.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLLifecycleConfiguration.h"
#import "SDLLifecycleConfigurationUpdate.h"
#import "SDLLockScreenConfiguration.h"
@@ -88,7 +89,7 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
#pragma mark Lifecycle
- (instancetype)init {
- return [self initWithConfiguration:[SDLConfiguration configurationWithLifecycle:[SDLLifecycleConfiguration defaultConfigurationWithAppName:@"SDL APP" appId:@"001"] lockScreen:[SDLLockScreenConfiguration disabledConfiguration] logging:[SDLLogConfiguration defaultConfiguration]] delegate:nil];
+ return [self initWithConfiguration:[SDLConfiguration configurationWithLifecycle:[SDLLifecycleConfiguration defaultConfigurationWithAppName:@"SDL APP" appId:@"001"] lockScreen:[SDLLockScreenConfiguration disabledConfiguration] logging:[SDLLogConfiguration defaultConfiguration] fileManager:[SDLFileManagerConfiguration defaultConfiguration]] delegate:nil];
}
- (instancetype)initWithConfiguration:(SDLConfiguration *)configuration delegate:(nullable id<SDLManagerDelegate>)delegate {
@@ -119,7 +120,7 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready";
_lifecycleQueue = dispatch_queue_create("com.sdl.lifecycle", DISPATCH_QUEUE_SERIAL);
// Managers
- _fileManager = [[SDLFileManager alloc] initWithConnectionManager:self];
+ _fileManager = [[SDLFileManager alloc] initWithConnectionManager:self configuration:_configuration.fileManagerConfig];
_permissionManager = [[SDLPermissionManager alloc] init];
_lockScreenManager = [[SDLLockScreenManager alloc] initWithConfiguration:_configuration.lockScreenConfig notificationDispatcher:_notificationDispatcher presenter:[[SDLLockScreenPresenter alloc] init]];
_screenManager = [[SDLScreenManager alloc] initWithConnectionManager:self fileManager:_fileManager];
diff --git a/SmartDeviceLink/SDLManager.m b/SmartDeviceLink/SDLManager.m
index e30ae87ea..61d135c9a 100644
--- a/SmartDeviceLink/SDLManager.m
+++ b/SmartDeviceLink/SDLManager.m
@@ -7,6 +7,7 @@
#import "NSMapTable+Subscripting.h"
#import "SDLConfiguration.h"
#import "SDLConnectionManagerType.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLLifecycleConfiguration.h"
#import "SDLLifecycleManager.h"
#import "SDLLockScreenConfiguration.h"
@@ -39,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark Lifecycle
- (instancetype)init {
- return [self initWithConfiguration:[SDLConfiguration configurationWithLifecycle:[SDLLifecycleConfiguration defaultConfigurationWithAppName:@"SDL APP" appId:@"001"] lockScreen:[SDLLockScreenConfiguration enabledConfiguration] logging:[SDLLogConfiguration defaultConfiguration]] delegate:nil];
+ return [self initWithConfiguration:[SDLConfiguration configurationWithLifecycle:[SDLLifecycleConfiguration defaultConfigurationWithAppName:@"SDL APP" appId:@"001"] lockScreen:[SDLLockScreenConfiguration enabledConfiguration] logging:[SDLLogConfiguration defaultConfiguration] fileManager:[SDLFileManagerConfiguration defaultConfiguration]] delegate:nil];
}
- (instancetype)initWithConfiguration:(SDLConfiguration *)configuration delegate:(nullable id<SDLManagerDelegate>)delegate {
diff --git a/SmartDeviceLink/SDLNames.h b/SmartDeviceLink/SDLNames.h
index 74aac6008..c1c1466ae 100644
--- a/SmartDeviceLink/SDLNames.h
+++ b/SmartDeviceLink/SDLNames.h
@@ -99,6 +99,7 @@ extern SDLName const SDLNameCompassDirection;
extern SDLName const SDLNameCorrelationId;
extern SDLName const SDLNameCountryCode;
extern SDLName const SDLNameCountryName;
+extern SDLName const SDLNameCRC;
extern SDLName const SDLNameCreateInteractionChoiceSet;
extern SDLName const SDLNameClockText;
extern SDLName const SDLNameCurrentTemperature;
diff --git a/SmartDeviceLink/SDLNames.m b/SmartDeviceLink/SDLNames.m
index fa7e6bf8f..43ff54d33 100644
--- a/SmartDeviceLink/SDLNames.m
+++ b/SmartDeviceLink/SDLNames.m
@@ -97,6 +97,7 @@ SDLName const SDLNameCompassDirection = @"compassDirection";
SDLName const SDLNameCorrelationId = @"correlationID";
SDLName const SDLNameCountryCode = @"countryCode";
SDLName const SDLNameCountryName = @"countryName";
+SDLName const SDLNameCRC = @"crc";
SDLName const SDLNameCreateInteractionChoiceSet = @"CreateInteractionChoiceSet";
SDLName const SDLNameClockText = @"CT";
SDLName const SDLNameCurrentTemperature = @"currentTemperature";
diff --git a/SmartDeviceLink/SDLPutFile.h b/SmartDeviceLink/SDLPutFile.h
index 247228fbd..ac621a0b4 100644
--- a/SmartDeviceLink/SDLPutFile.h
+++ b/SmartDeviceLink/SDLPutFile.h
@@ -6,72 +6,132 @@
#import "SDLFileType.h"
/**
- * Used to push a binary data onto the SDL module from a mobile device, such as
- * icons and album art
+ * Used to push a binary data onto the SDL module from a mobile device, such as icons and album art.
*
- * Since SmartDeviceLink 2.0
- * @see SDLDeleteFile
- * @see SDLListFiles
+ * Since SmartDeviceLink 2.0
+ * @see SDLDeleteFile, SDLListFiles
*/
NS_ASSUME_NONNULL_BEGIN
@interface SDLPutFile : SDLRPCRequest
+/**
+ * Init
+ *
+ * @return A SDLPutFile object
+ */
+- (instancetype)init;
+
+/**
+ * Convenience init for creating a putfile with a name and file format.
+ *
+ * @param fileName The file's name
+ * @param fileType The file's format
+ * @return A SDLPutFile object
+ */
- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType;
+/**
+ * Convenience init for creating a putfile with a name, file format, and persistance.
+ *
+ * @param fileName The file's name
+ * @param fileType The file's format
+ * @param persistentFile Whether or not the image should persist between ignition cycles
+ * @return A SDLPutFile object
+ */
- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile;
-- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length;
+/**
+ * Convenience init for creating a putfile that is part of a multiple frame payload.
+ *
+ * @param fileName The file's name
+ * @param fileType The file's format
+ * @param persistentFile Whether or not the image should persist between ignition cycles
+ * @param systemFile Whether or not the file is meant to be passed through Core to elsewhere on the system
+ * @param offset Offset in bytes for resuming partial data chunks
+ * @param length Length in bytes for resuming partial data chunks
+ * @return A SDLPutFile object
+ */
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length __deprecated_msg("Use initWithFileName:fileType:persistentFile:systemFile:offset:length:crc: instead");
/**
- * A file reference name
+ * Convenience init for creating a putfile that is part of a multiple frame payload.
*
- * Required, maxlength 255 characters
+ * @param fileName The file's name
+ * @param fileType The file's format
+ * @param persistentFile Whether or not the image should persist between ignition cycles
+ * @param systemFile Whether or not the file is meant to be passed through Core to elsewhere on the system
+ * @param offset Offset in bytes for resuming partial data chunks
+ * @param length Length in bytes for resuming partial data chunks
+ * @param crc Checksum of the bulk data. Used by Core to check data integrity
+ * @return A SDLPutFile object
+ */
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length crc:(UInt64)crc;
+
+/**
+ * Convenience init for creating a putfile that is part of a multiple frame payload. A CRC checksum is calculated for the bulk data.
+ *
+ * @param fileName The file's name
+ * @param fileType The file's format
+ * @param persistentFile Whether or not the image should persist between ignition cycles
+ * @param systemFile Whether or not the file is meant to be passed through Core to elsewhere on the system
+ * @param offset Offset in bytes for resuming partial data chunks
+ * @param length Length in bytes for resuming partial data chunks
+ * @param bulkData Data being sent in the putfile
+ * @return A SDLPutFile object
+ */
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length bulkData:(NSData *)bulkData;
+
+/**
+ * File reference name
+ *
+ * Required, max length 255 characters
*/
@property (strong, nonatomic) NSString *syncFileName;
/**
- * A FileType value representing a selected file type
+ * A FileType value representing a selected file type
*
- * Required
+ * Required
*/
@property (strong, nonatomic) SDLFileType fileType;
/**
- * A value to indicates if the file is meant to persist between
- * sessions / ignition cycles. If set to TRUE, then the system will aim to
- * persist this file through session / cycles. While files with this
- * designation will have priority over others, they are subject to deletion
- * by the system at any time. In the event of automatic deletion by the
- * system, the app will receive a rejection and have to resend the file. If
- * omitted, the value will be set to false
+ * A value to indicates if the file is meant to persist between sessions / ignition cycles. If set to TRUE, then the system will aim to persist this file through session / cycles. While files with this designation will have priority over others, they are subject to deletion by the system at any time. In the event of automatic deletion by the system, the app will receive a rejection and have to resend the file. If omitted, the value will be set to false.
*
- * Boolean, Optional, default = NO
+ * Boolean, Optional, default = NO
*/
@property (nullable, strong, nonatomic) NSNumber<SDLBool> *persistentFile;
/**
- * Indicates if the file is meant to be passed through core to elsewhere on the system. If set to TRUE, then the system will instead pass the data thru as it arrives to a predetermined area outside of core.
+ * Indicates if the file is meant to be passed through core to elsewhere on the system. If set to TRUE, then the system will instead pass the data thru as it arrives to a predetermined area outside of core.
*
- * Boolean, Optional, default = NO
+ * Boolean, Optional, default = NO
*/
@property (nullable, strong, nonatomic) NSNumber<SDLBool> *systemFile;
/**
- * Offset in bytes for resuming partial data chunks.
+ * Offset in bytes for resuming partial data chunks.
*
- * Integer, Optional, 0 - 100,000,000,000
+ * Integer, Optional, 0 - 100,000,000,000
*/
@property (nullable, strong, nonatomic) NSNumber<SDLUInt> *offset;
/**
- * Length in bytes for resuming partial data chunks. If offset is set to 0, then length is the total length of the file to be downloaded
+ * Length in bytes for resuming partial data chunks. If offset is set to 0, then length is the total length of the file to be downloaded
*
- * Integer, Optional, 0 - 100,000,000,000
+ * Integer, Optional, 0 - 100,000,000,000
*/
@property (nullable, strong, nonatomic) NSNumber<SDLUInt> *length;
+/**
+ * Additional CRC32 checksum to protect data integrity up to 512 Mbits.
+ *
+ * Integer, Optional, 0 - 4,294,967,295
+ */
+@property (nullable, strong, nonatomic) NSNumber<SDLUInt> *crc;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLPutFile.m b/SmartDeviceLink/SDLPutFile.m
index 5b289d4ce..f058b5ec2 100644
--- a/SmartDeviceLink/SDLPutFile.m
+++ b/SmartDeviceLink/SDLPutFile.m
@@ -6,6 +6,8 @@
#import "NSMutableDictionary+Store.h"
#import "SDLNames.h"
+#import <zlib.h>
+
NS_ASSUME_NONNULL_BEGIN
@implementation SDLPutFile
@@ -16,6 +18,29 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+
+ self.syncFileName = fileName;
+ self.fileType = fileType;
+
+ return self;
+}
+
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile {
+ self = [self initWithFileName:fileName fileType:fileType];
+ if (!self) {
+ return nil;
+ }
+
+ self.persistentFile = @(persistentFile);
+
+ return self;
+}
+
- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length {
self = [self initWithFileName:fileName fileType:fileType persistentFile:persistentFile];
if (!self) {
@@ -29,29 +54,34 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile {
- self = [self initWithFileName:fileName fileType:fileType];
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length crc:(UInt64)crc {
+ self = [self initWithFileName:fileName fileType:fileType persistentFile:persistentFile];
if (!self) {
return nil;
}
- self.persistentFile = @(persistentFile);
+ self.systemFile = @(systemFile);
+ self.offset = @(offset);
+ self.length = @(length);
+ self.crc = crc == 0 ? nil : @(crc);
return self;
}
-- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType {
- self = [self init];
+- (instancetype)initWithFileName:(NSString *)fileName fileType:(SDLFileType)fileType persistentFile:(BOOL)persistentFile systemFile:(BOOL)systemFile offset:(UInt32)offset length:(UInt32)length bulkData:(NSData *)bulkData {
+
+ self = [self initWithFileName:fileName fileType:fileType persistentFile:persistentFile systemFile:systemFile offset:offset length:length crc:[self.class sdl_getCRC32ChecksumForBulkData:bulkData]];
if (!self) {
return nil;
}
- self.syncFileName = fileName;
- self.fileType = fileType;
+ self.bulkData = bulkData;
return self;
}
+#pragma mark - Getters and Setters
+
- (void)setSyncFileName:(NSString *)syncFileName {
[parameters sdl_setObject:syncFileName forName:SDLNameSyncFileName];
}
@@ -100,6 +130,24 @@ NS_ASSUME_NONNULL_BEGIN
return [parameters sdl_objectForName:SDLNameLength];
}
+- (void)setCrc:(nullable NSNumber<SDLUInt> *)crc {
+ [parameters sdl_setObject:crc forName:SDLNameCRC];
+}
+
+- (nullable NSNumber<SDLUInt> *)crc {
+ return [parameters sdl_objectForName:SDLNameCRC];
+}
+
+#pragma mark - Helpers
+
++ (unsigned long)sdl_getCRC32ChecksumForBulkData:(NSData *)data {
+ if (data.length == 0) {
+ return 0;
+ }
+
+ return crc32(0, data.bytes, (uInt)data.length);
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLPutFileResponse.h b/SmartDeviceLink/SDLPutFileResponse.h
index fbc9744b5..322ab47d4 100644
--- a/SmartDeviceLink/SDLPutFileResponse.h
+++ b/SmartDeviceLink/SDLPutFileResponse.h
@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLPutFileResponse : SDLRPCResponse
/**
- Provides the total local space available in SDL Core for the registered app. If the transfer has systemFile enabled, then the value will be set to 0 automatically.
+ * Provides the total local space available in SDL Core for the registered app. If the transfer has systemFile enabled, then the value will be set to 0 automatically.
*/
@property (strong, nonatomic) NSNumber<SDLInt> *spaceAvailable;
diff --git a/SmartDeviceLink/SDLResult.h b/SmartDeviceLink/SDLResult.h
index 99678b852..fe9820475 100644
--- a/SmartDeviceLink/SDLResult.h
+++ b/SmartDeviceLink/SDLResult.h
@@ -160,6 +160,11 @@ extern SDLResult const SDLResultTimedOut;
extern SDLResult const SDLResultCancelRoute;
/**
+ * The data sent failed to pass CRC check in receiver end.
+ */
+extern SDLResult const SDLResultCorruptedData;
+
+/**
The RPC (e.g. ReadDID) executed successfully but the data exceeded the platform maximum threshold and thus, only part of the data is available.
*/
extern SDLResult const SDLResultTruncatedData;
diff --git a/SmartDeviceLink/SDLResult.m b/SmartDeviceLink/SDLResult.m
index 77c8c5529..5e169c3a2 100644
--- a/SmartDeviceLink/SDLResult.m
+++ b/SmartDeviceLink/SDLResult.m
@@ -30,6 +30,7 @@ SDLResult const SDLResultDisallowed = @"DISALLOWED";
SDLResult const SDLResultUserDisallowed = @"USER_DISALLOWED";
SDLResult const SDLResultTimedOut = @"TIMED_OUT";
SDLResult const SDLResultCancelRoute = @"CANCEL_ROUTE";
+SDLResult const SDLResultCorruptedData = @"CORRUPTED_DATA";
SDLResult const SDLResultTruncatedData = @"TRUNCATED_DATA";
SDLResult const SDLResultRetry = @"RETRY";
SDLResult const SDLResultWarnings = @"WARNINGS";
diff --git a/SmartDeviceLink/SDLTextAndGraphicManager.m b/SmartDeviceLink/SDLTextAndGraphicManager.m
index 34bc8d97d..644200215 100644
--- a/SmartDeviceLink/SDLTextAndGraphicManager.m
+++ b/SmartDeviceLink/SDLTextAndGraphicManager.m
@@ -156,43 +156,55 @@ NS_ASSUME_NONNULL_BEGIN
fullShow = [self sdl_assembleShowImages:fullShow];
self.inProgressHandler = handler;
+
__weak typeof(self)weakSelf = self;
if (!([self sdl_shouldUpdatePrimaryImage] || [self sdl_shouldUpdateSecondaryImage])) {
- SDLLogV(@"No images to send, only sending text");
- // If there are no images to update, just send the text update
+ SDLLogV(@"No images to send, sending text");
+ // If there are no images to update, just send the text
self.inProgressUpdate = [self sdl_extractTextFromShow:fullShow];
- } else if ([self sdl_uploadedArtworkOrDoesntExist:self.primaryGraphic] && [self sdl_uploadedArtworkOrDoesntExist:self.secondaryGraphic]) {
+ } else if ([self sdl_isArtworkUploadedOrNonExistent:self.primaryGraphic] && [self sdl_isArtworkUploadedOrNonExistent:self.secondaryGraphic]) {
SDLLogV(@"Images already uploaded, sending full update");
// The files to be updated are already uploaded, send the full show immediately
self.inProgressUpdate = fullShow;
} else {
SDLLogV(@"Images need to be uploaded, sending text and uploading images");
+
// We need to upload or queue the upload of the images
// Send the text immediately
self.inProgressUpdate = [self sdl_extractTextFromShow:fullShow];
+
// Start uploading the images
__block SDLShow *thisUpdate = fullShow;
[self sdl_uploadImagesWithCompletionHandler:^(NSError * _Nonnull error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error != nil) {
- SDLLogE(@"Error uploading text and graphic image: %@", error);
+ SDLShow *showWithGraphics = [self sdl_createImageOnlyShowWithPrimaryArtwork:self.primaryGraphic secondaryArtwork:self.secondaryGraphic];
+ if (showWithGraphics != nil) {
+ SDLLogW(@"Some images failed to upload. Sending update with the successfully uploaded images");
+ self.inProgressUpdate = showWithGraphics;
+ } else {
+ SDLLogE(@"All images failed to upload. No graphics to show, skipping update.");
+ self.inProgressUpdate = nil;
+ }
+ return;
}
// Check if queued image update still matches our images (there could have been a new Show in the meantime) and send a new update if it does. Since the images will already be on the head unit, the whole show will be sent
// TODO: Send delete if it doesn't?
if ([strongSelf sdl_showImages:thisUpdate isEqualToShowImages:strongSelf.queuedImageUpdate]) {
SDLLogV(@"Queued image update matches the images we need, sending update");
- [strongSelf sdl_updateWithCompletionHandler:strongSelf.inProgressHandler];
+ return [strongSelf sdl_updateWithCompletionHandler:strongSelf.inProgressHandler];
} else {
SDLLogV(@"Queued image update does not match the images we need, skipping update");
}
}];
-
// When the images are done uploading, send another show with the images
self.queuedImageUpdate = fullShow;
}
+ if (self.inProgressUpdate == nil) { return; }
+
[self.connectionManager sendConnectionRequest:self.inProgressUpdate withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
SDLLogD(@"Text and Graphic update completed");
@@ -227,6 +239,10 @@ NS_ASSUME_NONNULL_BEGIN
}
[self.fileManager uploadArtworks:artworksToUpload completionHandler:^(NSArray<NSString *> * _Nonnull artworkNames, NSError * _Nullable error) {
+ if (error != nil) {
+ SDLLogW(@"Text and graphic manager artwork failed to upload with error: %@", error.localizedDescription);
+ }
+
handler(error);
}];
}
@@ -439,6 +455,19 @@ NS_ASSUME_NONNULL_BEGIN
return newShow;
}
+- (nullable SDLShow *)sdl_createImageOnlyShowWithPrimaryArtwork:(nullable SDLArtwork *)primaryArtwork secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork {
+ SDLShow *newShow = [[SDLShow alloc] init];
+ newShow.graphic = [self sdl_isArtworkUploadedOrNonExistent:primaryArtwork] ? [[SDLImage alloc] initWithName:primaryArtwork.name ofType:SDLImageTypeDynamic isTemplate:primaryArtwork.isTemplate] : nil;
+ newShow.secondaryGraphic = [self sdl_isArtworkUploadedOrNonExistent:secondaryArtwork] ? [[SDLImage alloc] initWithName:secondaryArtwork.name ofType:SDLImageTypeDynamic isTemplate:secondaryArtwork.isTemplate] : nil;
+
+ if (newShow.graphic == nil && newShow.secondaryGraphic == nil) {
+ SDLLogV(@"No graphics to upload");
+ return nil;
+ }
+
+ return newShow;
+}
+
- (void)sdl_updateCurrentScreenDataFromShow:(SDLShow *)show {
// If the items are nil, they were not updated, so we can't just set it directly
self.currentScreenData.mainField1 = show.mainField1 ?: self.currentScreenData.mainField1;
@@ -454,7 +483,13 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Helpers
-- (BOOL)sdl_uploadedArtworkOrDoesntExist:(SDLArtwork *)artwork {
+/**
+ * Checks if an artwork needs to be uploaded to Core.
+ *
+ * @param artwork The artwork to be uploaded to Core
+ * @return True if the artwork does not need to be uploaded to Core; false if artwork stills needs to be sent to Core.
+ */
+- (BOOL)sdl_isArtworkUploadedOrNonExistent:(SDLArtwork *)artwork {
return (!artwork || [self.fileManager hasUploadedFile:artwork]);
}
diff --git a/SmartDeviceLink/SDLUploadFileOperation.m b/SmartDeviceLink/SDLUploadFileOperation.m
index a7366c7c3..3eea620ba 100644
--- a/SmartDeviceLink/SDLUploadFileOperation.m
+++ b/SmartDeviceLink/SDLUploadFileOperation.m
@@ -94,9 +94,8 @@ NS_ASSUME_NONNULL_BEGIN
__weak typeof(self) weakself = self;
dispatch_group_notify(putFileGroup, dispatch_get_main_queue(), ^{
typeof(weakself) strongself = weakself;
-
[weakself sdl_closeInputStream];
-
+
if (streamError != nil || strongself.isCancelled) {
completion(NO, bytesAvailable, streamError);
} else {
@@ -110,15 +109,21 @@ NS_ASSUME_NONNULL_BEGIN
for (int i = 0; i < (((file.fileSize - 1) / mtuSize) + 1); i++) {
dispatch_group_enter(putFileGroup);
- // The putfile's length parameter is based on the current offset
- SDLPutFile *putFile = [[SDLPutFile alloc] initWithFileName:file.name fileType:file.fileType persistentFile:file.isPersistent];
- putFile.offset = @(currentOffset);
- putFile.length = @([self.class sdl_getPutFileLengthForOffset:currentOffset fileSize:(NSUInteger)file.fileSize mtuSize:mtuSize]);
-
// Get a chunk of data from the input stream
- NSUInteger dataSize = [self.class sdl_getDataSizeForOffset:currentOffset fileSize:file.fileSize mtuSize:mtuSize];
- putFile.bulkData = [self.class sdl_getDataChunkWithSize:dataSize inputStream:self.inputStream];
- currentOffset += dataSize;
+ UInt32 putFileLength = (UInt32)[self.class sdl_getPutFileLengthForOffset:currentOffset fileSize:(NSUInteger)file.fileSize mtuSize:mtuSize];
+ NSUInteger putFileBulkDataSize = [self.class sdl_getDataSizeForOffset:currentOffset fileSize:file.fileSize mtuSize:mtuSize];
+ NSData *putFileBulkData = [self.class sdl_getDataChunkWithSize:putFileBulkDataSize inputStream:self.inputStream];
+
+ SDLPutFile *putFile = [[SDLPutFile alloc]
+ initWithFileName:file.name
+ fileType:file.fileType
+ persistentFile:file.isPersistent
+ systemFile:NO
+ offset:(UInt32)currentOffset
+ length:putFileLength
+ bulkData:putFileBulkData];
+
+ currentOffset += putFileBulkDataSize;
__weak typeof(self) weakself = self;
[self.connectionManager sendConnectionManagerRequest:putFile withResponseHandler:^(__kindof SDLRPCRequest *_Nullable request, __kindof SDLRPCResponse *_Nullable response, NSError *_Nullable error) {
diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h
index 996da6be6..1ab1ae83f 100644
--- a/SmartDeviceLink/SmartDeviceLink.h
+++ b/SmartDeviceLink/SmartDeviceLink.h
@@ -329,6 +329,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
// Developer API
// Configurations
#import "SDLConfiguration.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLLifecycleConfiguration.h"
#import "SDLLifecycleConfigurationUpdate.h"
#import "SDLLockScreenConfiguration.h"
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m
index 0a5da7974..2809c3871 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLCheckChoiceVROptionalOperationSpec.m
@@ -65,7 +65,7 @@ describe(@"check choice VR optional operation", ^{
});
it(@"should have called the completion handler with proper data", ^{
- expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
expect(resultVROptional).to(beTrue());
expect(resultError).to(beNil());
});
@@ -110,9 +110,9 @@ describe(@"check choice VR optional operation", ^{
});
it(@"should have called the completion handler with proper data", ^{
- expect(hasCalledOperationCompletionHandler).to(beTrue());
- expect(resultVROptional).to(beFalse());
- expect(resultError).to(beNil());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
+ expect(resultVROptional).toEventually(beFalse());
+ expect(resultError).toEventually(beNil());
});
it(@"should be set to finished", ^{
@@ -131,7 +131,7 @@ describe(@"check choice VR optional operation", ^{
});
it(@"should return a failure", ^{
- expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
expect(resultVROptional).to(beFalse());
expect(resultError).toNot(beNil());
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLConfigurationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLConfigurationSpec.m
index 6afb1f3cf..106f26ebc 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLConfigurationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLConfigurationSpec.m
@@ -2,6 +2,7 @@
#import <Nimble/Nimble.h>
#import "SDLConfiguration.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLLifecycleConfiguration.h"
#import "SDLLogConfiguration.h"
#import "SDLLockScreenConfiguration.h"
@@ -17,6 +18,7 @@ describe(@"a configuration", ^{
__block SDLLockScreenConfiguration *someLockscreenConfig = nil;
__block SDLLogConfiguration *someLogConfig = nil;
__block SDLStreamingMediaConfiguration *someStreamingConfig = nil;
+ __block SDLFileManagerConfiguration *someFileManagerConfig = nil;
__block NSString *someAppName = nil;
__block NSString *someAppId = nil;
@@ -33,42 +35,106 @@ describe(@"a configuration", ^{
someLockscreenConfig = [SDLLockScreenConfiguration enabledConfigurationWithAppIcon:someImage backgroundColor:someBackgroundColor];
someLogConfig = [SDLLogConfiguration defaultConfiguration];
someStreamingConfig = [SDLStreamingMediaConfiguration insecureConfiguration];
+ someFileManagerConfig = [SDLFileManagerConfiguration defaultConfiguration];
});
-
- it(@"should create correctly with initWithLifecycle:lockScreen:logging:", ^{
+
+ it(@"initWithLifecycle:lockScreen:logging:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testConfig = [[SDLConfiguration alloc] initWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig];
expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
expect(testConfig.loggingConfig).to(equal(someLogConfig));
expect(testConfig.streamingMediaConfig).to(beNil());
+ expect(testConfig.fileManagerConfig).toNot(beNil());
+ #pragma clang diagnostic pop
});
- it(@"should create correctly with configurationWithLifecycle:lockScreen:logging:", ^{
- testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig];
+ it(@"initWithLifecycle:lockScreen:logging:fileManager:", ^{
+ testConfig = [[SDLConfiguration alloc] initWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig fileManager:someFileManagerConfig];
expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
expect(testConfig.loggingConfig).to(equal(someLogConfig));
expect(testConfig.streamingMediaConfig).to(beNil());
+ expect(testConfig.fileManagerConfig).to(equal(someFileManagerConfig));
});
- it(@"should create correctly with initWithLifecycle:lockScreen:logging:streamingMedia:", ^{
- testConfig = [[SDLConfiguration alloc] initWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:nil];
+ it(@"configurationWithLifecycle:lockScreen:logging:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig];
expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
expect(testConfig.loggingConfig).to(equal(someLogConfig));
expect(testConfig.streamingMediaConfig).to(beNil());
+ expect(testConfig.fileManagerConfig).toNot(beNil());
+ #pragma clang diagnostic pop
});
- it(@"should create correctly with configurationWithLifecycle:lockScreen:logging:streamingMedia:", ^{
- testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:nil];
+ it(@"configurationWithLifecycle:lockScreen:logging:fileManager", ^{
+ testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig fileManager:someFileManagerConfig];
expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
expect(testConfig.loggingConfig).to(equal(someLogConfig));
expect(testConfig.streamingMediaConfig).to(beNil());
+ expect(testConfig.fileManagerConfig).to(equal(someFileManagerConfig));
+ });
+
+ describe(@"streaming media config", ^{
+ beforeEach(^{
+ someLifecycleConfig = [SDLLifecycleConfiguration defaultConfigurationWithAppName:someAppName appId:someAppId];
+ someLifecycleConfig.appType = SDLAppHMITypeNavigation;
+ });
+
+ it(@"initWithLifecycle:lockScreen:logging:streamingMedia:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ testConfig = [[SDLConfiguration alloc] initWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:someStreamingConfig];
+
+ expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
+ expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
+ expect(testConfig.loggingConfig).to(equal(someLogConfig));
+ expect(testConfig.streamingMediaConfig).to(equal(someStreamingConfig));
+ expect(testConfig.fileManagerConfig).toNot(beNil());
+ #pragma clang diagnostic pop
+ });
+
+ it(@"initWithLifecycle:lockScreen:logging:streamingMedia:fileManager:", ^{
+ testConfig = [[SDLConfiguration alloc] initWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:someStreamingConfig fileManager:someFileManagerConfig];
+
+ expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
+ expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
+ expect(testConfig.loggingConfig).to(equal(someLogConfig));
+ expect(testConfig.streamingMediaConfig).to(equal(someStreamingConfig));
+ expect(testConfig.fileManagerConfig).to(equal(someFileManagerConfig));
+ });
+
+ it(@"configurationWithLifecycle:lockScreen:logging:streamingMedia:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:someStreamingConfig];
+
+ expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
+ expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
+ expect(testConfig.loggingConfig).to(equal(someLogConfig));
+ expect(testConfig.streamingMediaConfig).to(equal(someStreamingConfig));
+ expect(testConfig.fileManagerConfig).toNot(beNil());
+ #pragma clang diagnostic pop
+ });
+
+ it(@"configurationWithLifecycle:lockScreen:logging:streamingMedia:fileManager:", ^{
+ testConfig = [SDLConfiguration configurationWithLifecycle:someLifecycleConfig lockScreen:someLockscreenConfig logging:someLogConfig streamingMedia:someStreamingConfig fileManager:someFileManagerConfig];
+
+ expect(testConfig.lifecycleConfig).to(equal(someLifecycleConfig));
+ expect(testConfig.lockScreenConfig).to(equal(someLockscreenConfig));
+ expect(testConfig.loggingConfig).to(equal(someLogConfig));
+ expect(testConfig.streamingMediaConfig).to(equal(someStreamingConfig));
+ expect(testConfig.fileManagerConfig).to(equal(someFileManagerConfig));
+ });
});
});
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m
index 942aa6b7a..8a5ea9318 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m
@@ -5,6 +5,7 @@
#import "SDLError.h"
#import "SDLFile.h"
#import "SDLFileManager.h"
+#import "SDLFileManagerConfiguration.h"
#import "SDLFileType.h"
#import "SDLListFiles.h"
#import "SDLListFilesOperation.h"
@@ -26,6 +27,13 @@ SDLFileManagerState *const SDLFileManagerStateReady = @"Ready";
@interface SDLFileManager ()
@property (strong, nonatomic) NSOperationQueue *transactionQueue;
@property (strong, nonatomic) NSMutableSet<SDLFileName *> *uploadedEphemeralFileNames;
+@property (strong, nonatomic) NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *failedFileUploadsCount;
+@property (assign, nonatomic) UInt8 maxFileUploadAttempts;
+@property (assign, nonatomic) UInt8 maxArtworkUploadAttempts;
+
+- (BOOL)sdl_canFileBeUploadedAgain:(nullable SDLFile *)file maxUploadCount:(int)maxRetryCount failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount;
++ (NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)sdl_incrementFailedUploadCountForFileName:(SDLFileName *)fileName failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount;
+
@end
QuickSpecBegin(SDLFileManagerSpec)
@@ -33,11 +41,13 @@ QuickSpecBegin(SDLFileManagerSpec)
describe(@"SDLFileManager", ^{
__block TestConnectionManager *testConnectionManager = nil;
__block SDLFileManager *testFileManager = nil;
+ __block SDLFileManagerConfiguration *testFileManagerConfiguration = nil;
__block NSUInteger initialSpaceAvailable = 250;
beforeEach(^{
testConnectionManager = [[TestConnectionManager alloc] init];
- testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager];
+ testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:0 fileRetryCount:0];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
testFileManager.suspended = YES;
});
@@ -57,6 +67,11 @@ describe(@"SDLFileManager", ^{
it(@"should have no pending operations", ^{
expect(testFileManager.pendingTransactions).to(beEmpty());
});
+
+ it(@"should set the maximum number of upload attempts to 1", ^{
+ expect(testFileManager.maxFileUploadAttempts).to(equal(1));
+ expect(testFileManager.maxArtworkUploadAttempts).to(equal(1));
+ });
});
describe(@"after receiving a start message", ^{
@@ -296,6 +311,10 @@ describe(@"SDLFileManager", ^{
expect(@(completionSuccess)).to(equal(testResponseSuccess));
expect(completionError).toEventuallyNot(beNil());
});
+
+ it(@"should increment the failure count for the artwork", ^{
+ expect(testFileManager.failedFileUploadsCount[testFileName]).toEventually(equal(1));
+ });
});
context(@"when the connection errors without a response", ^{
@@ -575,7 +594,8 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{
beforeEach(^{
testConnectionManager = [[TestMultipleFilesConnectionManager alloc] init];
- testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager];
+ SDLFileManagerConfiguration *testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:0 fileRetryCount:0];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
initialSpaceAvailable = 66666;
});
@@ -1525,4 +1545,107 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{
});
});
+describe(@"SDLFileManager reupload failed files", ^{
+ context(@"setting max upload attempts with the file manager configuration", ^{
+ __block SDLFileManager *testFileManager = nil;
+ __block TestConnectionManager *testConnectionManager = nil;
+ __block SDLFileManagerConfiguration *testFileManagerConfiguration = nil;
+
+ it(@"should set the max upload attempts to 2 if the configuration properties are not set", ^{
+ testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] init];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
+
+ expect(testFileManager.maxFileUploadAttempts).to(equal(2));
+ expect(testFileManager.maxArtworkUploadAttempts).to(equal(2));
+ });
+
+ it(@"should set the max upload attempts to 1 if retry attempts are disabled", ^{
+ testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:0 fileRetryCount:0];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
+
+ expect(testFileManager.maxFileUploadAttempts).to(equal(1));
+ expect(testFileManager.maxArtworkUploadAttempts).to(equal(1));
+ });
+
+ it(@"should set the max upload attempts to the corresponding file manager configuration retry attempt count + 1", ^{
+ UInt8 artworkRetryCount = 5;
+ UInt8 fileRetryCount = 3;
+ testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:artworkRetryCount fileRetryCount:fileRetryCount];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
+
+ expect(testFileManager.maxArtworkUploadAttempts).to(equal((artworkRetryCount + 1)));
+ expect(testFileManager.maxFileUploadAttempts).to(equal(fileRetryCount + 1));
+ });
+ });
+
+ context(@"updating the failed upload count", ^{
+ __block NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *testFailedFileUploadsCount = nil;
+ __block NSString *testFileName = @"Test File A";
+
+ beforeEach(^{
+ testFailedFileUploadsCount = [NSMutableDictionary dictionary];
+
+ expect(testFailedFileUploadsCount).to(beEmpty());
+ });
+
+ it(@"should correctly add a file name", ^{
+ testFailedFileUploadsCount = [SDLFileManager sdl_incrementFailedUploadCountForFileName:testFileName failedFileUploadsCount:testFailedFileUploadsCount];
+
+ expect(testFailedFileUploadsCount[testFileName]).to(equal(1));
+ });
+
+ it(@"should correctly increment the count for a file name", ^{
+ testFailedFileUploadsCount[testFileName] = @1;
+ testFailedFileUploadsCount = [SDLFileManager sdl_incrementFailedUploadCountForFileName:testFileName failedFileUploadsCount:testFailedFileUploadsCount];
+
+ expect(testFailedFileUploadsCount[testFileName]).to(equal(2));
+ });
+ });
+
+ context(@"checking if a failed upload can be uploaded again", ^{
+ __block TestConnectionManager *testConnectionManager = nil;
+ __block SDLFileManager *testFileManager = nil;
+ __block SDLFileManagerConfiguration *testFileManagerConfiguration = nil;
+ __block NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *testFailedFileUploadsCount = nil;
+ __block SDLFile *testFile = nil;
+ __block NSString *testFileName = @"Test File B";
+
+ beforeEach(^{
+ testConnectionManager = [[TestConnectionManager alloc] init];
+ testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:0 fileRetryCount:0];
+ testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration];
+ testFailedFileUploadsCount = [NSMutableDictionary dictionary];
+ testFile = [[SDLFile alloc] initWithData:[@"someData" dataUsingEncoding:NSUTF8StringEncoding] name:testFileName fileExtension:@"bin" persistent:false];
+ });
+
+ describe(@"the file cannot be uploaded again", ^{
+ it(@"should not upload a file that is nil", ^{
+ testFile = nil;
+ BOOL canUploadAgain = [testFileManager sdl_canFileBeUploadedAgain:testFile maxUploadCount:5 failedFileUploadsCount:testFailedFileUploadsCount];
+ expect(canUploadAgain).to(equal(NO));
+ });
+
+ it(@"should not upload a file that has already been uploaded the max number of times", ^{
+ testFailedFileUploadsCount[testFileName] = @4;
+ BOOL canUploadAgain = [testFileManager sdl_canFileBeUploadedAgain:testFile maxUploadCount:4 failedFileUploadsCount:testFailedFileUploadsCount];
+ expect(canUploadAgain).to(equal(NO));
+ });
+ });
+
+ describe(@"the file can be uploaded again", ^{
+ it(@"should upload a file that has not yet failed to upload", ^{
+ testFailedFileUploadsCount = [NSMutableDictionary dictionary];
+ BOOL canUploadAgain = [testFileManager sdl_canFileBeUploadedAgain:testFile maxUploadCount:2 failedFileUploadsCount:testFailedFileUploadsCount];
+ expect(canUploadAgain).to(equal(YES));
+ });
+
+ it(@"should upload a file that has not been reuploaded the max number of times", ^{
+ testFailedFileUploadsCount[testFileName] = @2;
+ BOOL canUploadAgain = [testFileManager sdl_canFileBeUploadedAgain:testFile maxUploadCount:4 failedFileUploadsCount:testFailedFileUploadsCount];
+ expect(canUploadAgain).to(equal(YES));
+ });
+ });
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
index acdcb833c..c7b4271af 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
@@ -286,7 +286,7 @@ describe(@"a lifecycle manager", ^{
testManager.registerResponse = response;
[testManager.lifecycleStateMachine setToState:SDLLifecycleStateSettingUpHMI fromOldState:nil callEnterTransition:YES];
-
+
expect(@(readyHandlerSuccess)).to(equal(@NO));
expect(readyHandlerError).to(beNil());
});
@@ -370,10 +370,10 @@ describe(@"a lifecycle manager", ^{
// Transition to StateSettingUpManagers to prevent assert error from the lifecycle machine
[testManager.lifecycleStateMachine setToState:SDLLifecycleStateSettingUpManagers fromOldState:SDLLifecycleStateUpdatingConfiguration callEnterTransition:NO];
- expect(testManager.configuration.lifecycleConfig.language).to(equal(SDLLanguageEnGb));
- expect(testManager.configuration.lifecycleConfig.appName).to(equal(@"EnGb"));
- expect(testManager.configuration.lifecycleConfig.shortAppName).to(equal(@"E"));
- expect(testManager.configuration.lifecycleConfig.ttsName).to(equal([SDLTTSChunk textChunksFromString:@"EnGb ttsName"]));
+ expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnGb));
+ expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"EnGb"));
+ expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"E"));
+ expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(equal([SDLTTSChunk textChunksFromString:@"EnGb ttsName"]));
OCMVerify([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any]]);
});
@@ -392,10 +392,10 @@ describe(@"a lifecycle manager", ^{
// Transition to StateSettingUpManagers to prevent assert error from the lifecycle machine
[testManager.lifecycleStateMachine setToState:SDLLifecycleStateSettingUpManagers fromOldState:SDLLifecycleStateUpdatingConfiguration callEnterTransition:NO];
- expect(testManager.configuration.lifecycleConfig.language).to(equal(SDLLanguageEnUs));
- expect(testManager.configuration.lifecycleConfig.appName).to(equal(@"Test App"));
- expect(testManager.configuration.lifecycleConfig.shortAppName).to(equal(@"Short Name"));
- expect(testManager.configuration.lifecycleConfig.ttsName).to(beNil());
+ expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnUs));
+ expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"Test App"));
+ expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"Short Name"));
+ expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(beNil());
OCMVerify([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any]]);
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
index ff2ae7931..84936f211 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
@@ -34,12 +34,15 @@ describe(@"a menu cell", ^{
});
it(@"should initialize properly as a submenu item", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testCell = [[SDLMenuCell alloc] initWithTitle:someTitle subCells:someSubcells];
expect(testCell.title).to(equal(someTitle));
expect(testCell.icon).to(beNil());
expect(testCell.voiceCommands).to(beNil());
expect(testCell.subCells).to(equal(someSubcells));
+ #pragma clang diagnostic pop
});
it(@"should initialize properly as a submenu item with icon", ^{
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
index f960f05ba..36f9d5594 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
@@ -66,7 +66,7 @@ describe(@"menu manager", ^{
textOnlyCell = [[SDLMenuCell alloc] initWithTitle:@"Test 1" icon:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" subCells:@[textOnlyCell, textAndImageCell]];
+ submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" icon:nil subCells:@[textOnlyCell, textAndImageCell]];
submenuImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 4" icon:testArtwork2 subCells:@[textOnlyCell]];
mockConnectionManager = [[TestConnectionManager alloc] init];
@@ -318,7 +318,7 @@ describe(@"menu manager", ^{
testTriggerSource = triggerSource;
}];
- SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" subCells:@[cellWithHandler]];
+ SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" icon:nil subCells:@[cellWithHandler]];
testManager.menuCells = @[submenuCell];
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
index 223810aaa..d9ae6869d 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
@@ -97,9 +97,10 @@ describe(@"present choice operation", ^{
[testConnectionManager respondToLastRequestWithResponse:response];
});
+
it(@"should not reset the keyboard properties and should be finished", ^{
expect(testConnectionManager.receivedRequests.lastObject).toNot(beAnInstanceOf([SDLSetGlobalProperties class]));
- expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
expect(testOp.isFinished).to(beTrue());
expect(testOp.selectedCell).to(equal(testChoices.firstObject));
expect(testOp.selectedTriggerSource).to(equal(responseTriggerSource));
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
index f5a12218d..8a5d42afc 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
@@ -239,7 +239,7 @@ describe(@"present keyboard operation", ^{
});
it(@"should be finished", ^{
- expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
expect(testOp.isFinished).to(beTrue());
});
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
index ef5b18623..645eceeab 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
@@ -7,6 +7,7 @@
#import "SDLHMILevel.h"
#import "SDLImage.h"
#import "SDLMetadataTags.h"
+#import "SDLPutFileResponse.h"
#import "SDLShow.h"
#import "SDLTextAndGraphicManager.h"
#import "SDLTextField.h"
@@ -740,8 +741,11 @@ describe(@"text and graphic manager", ^{
});
context(@"updating images", ^{
+ __block NSString *testTextFieldText = @"mainFieldText";
+
beforeEach(^{
testManager.batchUpdates = YES;
+ testManager.textField1 = testTextFieldText;
});
context(@"when the image is already on the head unit", ^{
@@ -755,9 +759,9 @@ describe(@"text and graphic manager", ^{
});
it(@"should immediately attempt to update", ^{
- expect(testManager.inProgressUpdate.mainField1).to(equal(@""));
expect(testManager.inProgressUpdate.graphic.value).to(equal(testArtworkName));
expect(testManager.inProgressUpdate.secondaryGraphic.value).to(equal(testArtworkName));
+ expect(testManager.inProgressUpdate.mainField1).to(equal(testTextFieldText));
});
});
@@ -772,13 +776,87 @@ describe(@"text and graphic manager", ^{
});
it(@"should immediately attempt to update without the images", ^{
- expect(testManager.inProgressUpdate.mainField1).to(equal(@""));
+ expect(testManager.inProgressUpdate.mainField1).to(equal(testTextFieldText));
expect(testManager.inProgressUpdate.graphic.value).to(beNil());
expect(testManager.inProgressUpdate.secondaryGraphic.value).to(beNil());
expect(testManager.queuedImageUpdate.graphic.value).to(equal(testArtworkName));
expect(testManager.queuedImageUpdate.secondaryGraphic.value).to(equal(testArtworkName));
});
});
+
+ describe(@"When an image fails to upload to the remote", ^{
+ __block SDLArtwork *testArtwork1 = nil;
+ __block SDLArtwork *testArtwork2 = nil;
+
+ beforeEach(^{
+ testArtwork1 = [[SDLArtwork alloc] initWithData:[@"Test data 1" dataUsingEncoding:NSUTF8StringEncoding] name:@"Test data 1" fileExtension:@"png" persistent:NO];
+ testArtwork2 = [[SDLArtwork alloc] initWithData:[@"Test data 2" dataUsingEncoding:NSUTF8StringEncoding] name:@"Test data 2" fileExtension:@"png" persistent:NO];
+ });
+
+ context(@"If the images for the primary and secondary graphics fail the upload process", ^{
+ it(@"Should skip sending an update", ^{
+ testManager.primaryGraphic = testArtwork1;
+ testManager.secondaryGraphic = testArtwork2;
+ testManager.batchUpdates = NO;
+
+ OCMStub([mockFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO);
+ NSArray<NSString *> *testSuccessfulArtworks = @[];
+ NSError *testError = [NSError errorWithDomain:@"errorDomain"
+ code:9
+ userInfo:@{testArtwork1.name:@"error 1", testArtwork2.name:@"error 2"}
+ ];
+ OCMStub([mockFileManager uploadArtworks:[OCMArg isNotNil] completionHandler:([OCMArg invokeBlockWithArgs:testSuccessfulArtworks, testError, nil])]);
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.textField1).to(equal(testTextFieldText));
+ expect(testManager.inProgressUpdate).to(beNil());
+ expect(testManager.queuedImageUpdate.graphic.value).to(equal(testArtwork1.name));
+ expect(testManager.queuedImageUpdate.secondaryGraphic.value).to(equal(testArtwork2.name));
+ });
+ });
+
+ context(@"If only one of images for the primary and secondary graphics fails to upload", ^{
+ it(@"Should show the primary graphic even if the secondary graphic upload fails", ^{
+ testManager.primaryGraphic = testArtwork1;
+ testManager.secondaryGraphic = testArtwork2;
+ testManager.batchUpdates = NO;
+
+ OCMStub([mockFileManager hasUploadedFile:testArtwork1]).andReturn(YES);
+ OCMStub([mockFileManager hasUploadedFile:testArtwork2]).andReturn(NO);
+ NSArray<NSString *> *testSuccessfulArtworks = @[testArtwork1.name];
+ NSError *testError = [NSError errorWithDomain:@"errorDomain" code:9 userInfo:@{testArtwork2.name:@"error 2"}];
+ OCMStub([mockFileManager uploadArtworks:[OCMArg isNotNil] completionHandler:([OCMArg invokeBlockWithArgs:testSuccessfulArtworks, testError, nil])]);
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.textField1).to(equal(testTextFieldText));
+ expect(testManager.inProgressUpdate.graphic.value).to(equal(testArtwork1.name));
+ expect(testManager.inProgressUpdate.secondaryGraphic).to(beNil());
+ expect(testManager.inProgressUpdate.mainField1).to(beNil());
+ expect(testManager.queuedImageUpdate.graphic.value).to(equal(testArtwork1.name));
+ expect(testManager.queuedImageUpdate.secondaryGraphic.value).to(equal(testArtwork2.name));
+ });
+
+ it(@"Should show the secondary graphic even if the primary graphic upload fails", ^{
+ testManager.primaryGraphic = testArtwork1;
+ testManager.secondaryGraphic = testArtwork2;
+ testManager.batchUpdates = NO;
+
+ OCMStub([mockFileManager hasUploadedFile:testArtwork1]).andReturn(NO);
+ OCMStub([mockFileManager hasUploadedFile:testArtwork2]).andReturn(YES);
+ NSArray<NSString *> *testSuccessfulArtworks = @[testArtwork2.name];
+ NSError *testError = [NSError errorWithDomain:@"errorDomain" code:9 userInfo:@{testArtwork1.name:@"error 2"}];
+ OCMStub([mockFileManager uploadArtworks:[OCMArg isNotNil] completionHandler:([OCMArg invokeBlockWithArgs:testSuccessfulArtworks, testError, nil])]);
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.textField1).to(equal(testTextFieldText));
+ expect(testManager.inProgressUpdate.graphic).to(beNil());
+ expect(testManager.inProgressUpdate.secondaryGraphic.value).to(equal(testArtwork2.name));
+ expect(testManager.inProgressUpdate.mainField1).to(beNil());
+ expect(testManager.queuedImageUpdate.graphic.value).to(equal(testArtwork1.name));
+ expect(testManager.queuedImageUpdate.secondaryGraphic.value).to(equal(testArtwork2.name));
+ });
+ });
+ });
});
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLUploadFileOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLUploadFileOperationSpec.m
index 6d9474568..b2a83fca6 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLUploadFileOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLUploadFileOperationSpec.m
@@ -9,7 +9,7 @@
#import "SDLPutFileResponse.h"
#import "SDLUploadFileOperation.h"
#import "TestConnectionManager.h"
-
+#import <zlib.h>
QuickSpecBegin(SDLUploadFileOperationSpec)
@@ -106,11 +106,14 @@ describe(@"Streaming upload of data", ^{
SDLPutFile *putFile = putFiles[index];
NSUInteger mtuSize = [[SDLGlobals sharedGlobals] mtuSizeForServiceType:SDLServiceTypeBulkData];
+ NSData *testBulkFileData = [testFileData subdataWithRange:NSMakeRange((index * mtuSize), MIN(putFile.length.unsignedIntegerValue, mtuSize))];
+ unsigned long testBulkFileDataCrc = crc32(0, testBulkFileData.bytes, (uInt)testBulkFileData.length);
expect(putFile.offset).to(equal(@(index * mtuSize)));
expect(putFile.persistentFile).to(equal(@NO));
expect(putFile.syncFileName).to(equal(testFileName));
- expect(putFile.bulkData).to(equal([testFileData subdataWithRange:NSMakeRange((index * mtuSize), MIN(putFile.length.unsignedIntegerValue, mtuSize))]));
+ expect(putFile.bulkData).to(equal(testBulkFileData));
+ expect(putFile.crc).to(equal([NSNumber numberWithUnsignedLong:testBulkFileDataCrc]));
// Length is used to inform the SDL Core of the total incoming packet size
if (index == 0) {
diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLResultSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLResultSpec.m
index 239140d19..c90ece5d3 100644
--- a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLResultSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLResultSpec.m
@@ -42,6 +42,7 @@ describe(@"Individual Enum Value Tests", ^ {
expect(SDLResultVehicleDataNotAllowed).to(equal(@"VEHICLE_DATA_NOT_ALLOWED"));
expect(SDLResultFileNotFound).to(equal(@"FILE_NOT_FOUND"));
expect(SDLResultCancelRoute).to(equal(@"CANCEL_ROUTE"));
+ expect(SDLResultCorruptedData).to(equal(@"CORRUPTED_DATA"));
expect(SDLResultTruncatedData).to(equal(@"TRUNCATED_DATA"));
expect(SDLResultSaved).to(equal(@"SAVED"));
expect(SDLResultInvalidCertificate).to(equal(@"INVALID_CERT"));
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddCommandSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddCommandSpec.m
index 27698a7e6..5f7bcf105 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddCommandSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddCommandSpec.m
@@ -122,6 +122,8 @@ describe(@"initializers", ^{
NSString *iconValue = @"Icon";
SDLImageType imageType = SDLImageTypeDynamic;
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testCommand = [[SDLAddCommand alloc] initWithId:commandId vrCommands:vrCommands menuName:menuName parentId:parentId position:position iconValue:iconValue iconType:imageType handler:nil];
expect(testCommand.cmdID).to(equal(commandId));
@@ -130,9 +132,12 @@ describe(@"initializers", ^{
expect(testCommand.menuParams.parentID).to(equal(parentId));
expect(testCommand.menuParams.position).to(equal(position));
expect(testCommand.cmdIcon).toNot(beNil());
+ #pragma clang diagnostic pop
});
it(@"should initialize without an image", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testCommand = [[SDLAddCommand alloc] initWithId:commandId vrCommands:vrCommands menuName:menuName parentId:parentId position:position iconValue:nil iconType:nil handler:nil];
expect(testCommand.cmdID).to(equal(commandId));
@@ -141,6 +146,7 @@ describe(@"initializers", ^{
expect(testCommand.menuParams.parentID).to(equal(parentId));
expect(testCommand.menuParams.position).to(equal(position));
expect(testCommand.cmdIcon).to(beNil());
+ #pragma clang diagnostic pop
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m
index f082671b5..18f09da8e 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m
@@ -21,7 +21,7 @@ describe(@"Getter/Setter Tests", ^ {
__block SDLImage *image = nil;
beforeEach(^{
- image = [[SDLImage alloc] initWithName:@"Test"];
+ image = [[SDLImage alloc] initWithName:@"Test" isTemplate:false];
});
it(@"should correctly initialize with initWithId:menuName:", ^{
@@ -34,12 +34,15 @@ describe(@"Getter/Setter Tests", ^ {
});
it(@"should correctly initialize with initWithId:menuName:position:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLAddSubMenu *testRequest = [[SDLAddSubMenu alloc] initWithId:menuId menuName:menuName position:position];
expect(testRequest.menuID).to(equal(@(menuId)));
expect(testRequest.position).to(equal(@(position)));
expect(testRequest.menuName).to(equal(menuName));
expect(testRequest.menuIcon).to(beNil());
+ #pragma clang diagnostic pop
});
it(@"should correctly initialize with initWithId:menuName:menuIcon:position:", ^{
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLGetVehicleDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLGetVehicleDataSpec.m
index d5575fe7b..360b87bae 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLGetVehicleDataSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLGetVehicleDataSpec.m
@@ -176,6 +176,8 @@ describe(@"initializers", ^{
});
context(@"initWithAccelerationPedalPosition:airbagStatus:beltStatus:bodyInformation:clusterModeStatus:deviceStatus:driverBraking:eCallInfo:emergencyEvent:engineTorque:externalTemperature:fuelLevel:fuelLevelState:gps:headLampStatus:instantFuelConsumption:myKey:odometer:prndl:rpm:speed:steeringWheelAngle:tirePressure:wiperStatus:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLGetVehicleData *testRequest = [[SDLGetVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:NO beltStatus:YES bodyInformation:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES emergencyEvent:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:YES gps:YES headLampStatus:YES instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES vin:YES wiperStatus:YES];
expect(testRequest.accPedalPosition).to(equal(@YES));
@@ -206,6 +208,7 @@ describe(@"initializers", ^{
expect(testRequest.tirePressure).to(equal(@YES));
expect(testRequest.turnSignal).to(equal(@NO));
expect(testRequest.wiperStatus).to(equal(@YES));
+ #pragma clang diagnostic pop
});
context(@"initWithAccelerationPedalPosition:airbagStatus:beltStatus:bodyInformation:clusterModeStatus:deviceStatus:driverBraking:eCallInfo:emergencyEvent:engineOilLife:engineTorque:externalTemperature:fuelLevel:fuelLevelState:gps:headLampStatus:instantFuelConsumption:myKey:odometer:prndl:rpm:speed:steeringWheelAngle:tirePressure:wiperStatus:", ^{
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLPutFileSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLPutFileSpec.m
index 54ad81b28..88b7310f5 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLPutFileSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLPutFileSpec.m
@@ -12,6 +12,12 @@
#import "SDLNames.h"
#import "SDLPutFile.h"
+#import <zlib.h>
+
+
+@interface SDLPutFile()
++ (unsigned long)sdl_getCRC32ChecksumForBulkData:(NSData *)data;
+@end
QuickSpecBegin(SDLPutFileSpec)
@@ -25,6 +31,7 @@ describe(@"Getter/Setter Tests", ^ {
testRequest.systemFile = @NO;
testRequest.offset = @987654321;
testRequest.length = @123456789;
+ testRequest.crc = @0xffffffff;
expect(testRequest.syncFileName).to(equal(@"fileName"));
expect(testRequest.fileType).to(equal(SDLFileTypeJPEG));
@@ -32,18 +39,20 @@ describe(@"Getter/Setter Tests", ^ {
expect(testRequest.systemFile).to(equal(@NO));
expect(testRequest.offset).to(equal(@987654321));
expect(testRequest.length).to(equal(@123456789));
+ expect(testRequest.crc).to(equal(0xffffffff));
});
- it(@"Should get correctly when initialized", ^ {
+ it(@"Should get and set correctly when initialized", ^ {
NSMutableDictionary* dict = [@{SDLNameRequest:
@{SDLNameParameters:
- @{SDLNameSyncFileName:@"fileName",
- SDLNameFileType:SDLFileTypeJPEG,
- SDLNamePersistentFile:@YES,
- SDLNameSystemFile:@NO,
- SDLNameOffset:@987654321,
- SDLNameLength:@123456789},
- SDLNameOperationName:SDLNamePutFile}} mutableCopy];
+ @{ SDLNameSyncFileName:@"fileName",
+ SDLNameFileType:SDLFileTypeJPEG,
+ SDLNamePersistentFile:@YES,
+ SDLNameSystemFile:@NO,
+ SDLNameOffset:@987654321,
+ SDLNameLength:@123456789,
+ SDLNameCRC:@0xffffffff},
+ SDLNameOperationName:SDLNamePutFile}} mutableCopy];
SDLPutFile* testRequest = [[SDLPutFile alloc] initWithDictionary:dict];
expect(testRequest.syncFileName).to(equal(@"fileName"));
@@ -52,17 +61,116 @@ describe(@"Getter/Setter Tests", ^ {
expect(testRequest.systemFile).to(equal(@NO));
expect(testRequest.offset).to(equal(@987654321));
expect(testRequest.length).to(equal(@123456789));
+ expect(testRequest.crc).to(equal(@0xffffffff));
});
-
- it(@"Should return nil if not set", ^ {
- SDLPutFile* testRequest = [[SDLPutFile alloc] init];
-
+});
+
+describe(@"When creating a CRC32 checksum for the bulk data", ^{
+ it(@"should create a checksum for data", ^{
+ NSData *testFileData = [@"Somerandomtextdata" dataUsingEncoding:NSUTF8StringEncoding];
+ unsigned long testFileCRC32Checksum = [SDLPutFile sdl_getCRC32ChecksumForBulkData:testFileData];
+
+ expect(testFileCRC32Checksum).to(equal(testFileCRC32Checksum));
+ });
+
+ it(@"should not create a checksum if the data is nil", ^{
+ NSData *testFileData = nil;
+ unsigned long testFileCRC32Checksum = [SDLPutFile sdl_getCRC32ChecksumForBulkData:testFileData];
+
+ expect(testFileCRC32Checksum).to(equal(0));
+ });
+
+ it(@"should not create a checksum if the data is empty", ^{
+ NSData *testFileData = [NSData data];
+ unsigned long testFileCRC32Checksum = [SDLPutFile sdl_getCRC32ChecksumForBulkData:testFileData];
+
+ expect(testFileCRC32Checksum).to(equal(0));
+ });
+});
+
+describe(@"initializers", ^{
+ context(@"init", ^{
+ SDLPutFile *testRequest = [[SDLPutFile alloc] init];
+
expect(testRequest.syncFileName).to(beNil());
expect(testRequest.fileType).to(beNil());
expect(testRequest.persistentFile).to(beNil());
expect(testRequest.systemFile).to(beNil());
expect(testRequest.offset).to(beNil());
expect(testRequest.length).to(beNil());
+ expect(testRequest.crc).to(beNil());
+ expect(testRequest.bulkData).to(beNil());
+ });
+
+ context(@"initWithFileName:fileType:", ^{
+ SDLPutFile *testRequest = [[SDLPutFile alloc] initWithFileName:@"fileName" fileType:SDLFileTypeWAV];
+
+ expect(testRequest.syncFileName).to(equal(@"fileName"));
+ expect(testRequest.fileType).to(equal(SDLFileTypeWAV));
+ expect(testRequest.persistentFile).to(beNil());
+ expect(testRequest.systemFile).to(beNil());
+ expect(testRequest.offset).to(beNil());
+ expect(testRequest.length).to(beNil());
+ expect(testRequest.crc).to(beNil());
+ expect(testRequest.bulkData).to(beNil());
+ });
+
+ context(@"initWithFileName:fileType:persistentFile:", ^{
+ SDLPutFile* testRequest = [[SDLPutFile alloc] initWithFileName:@"fileName" fileType:SDLFileTypePNG persistentFile:false];
+
+ expect(testRequest.syncFileName).to(equal(@"fileName"));
+ expect(testRequest.fileType).to(equal(SDLFileTypePNG));
+ expect(testRequest.persistentFile).to(beFalse());
+ expect(testRequest.systemFile).to(beNil());
+ expect(testRequest.offset).to(beNil());
+ expect(testRequest.length).to(beNil());
+ expect(testRequest.crc).to(beNil());
+ expect(testRequest.bulkData).to(beNil());
+ });
+
+ context(@"initWithFileName:fileType:persistentFile:systemFile:offset:length:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ SDLPutFile *testRequest = [[SDLPutFile alloc] initWithFileName:@"fileName" fileType:SDLFileTypeMP3 persistentFile:true systemFile:true offset:45 length:34];
+
+ expect(testRequest.syncFileName).to(equal(@"fileName"));
+ expect(testRequest.fileType).to(equal(SDLFileTypeMP3));
+ expect(testRequest.persistentFile).to(beTrue());
+ expect(testRequest.systemFile).to(beTrue());
+ expect(testRequest.offset).to(equal(@45));
+ expect(testRequest.length).to(equal(34));
+ expect(testRequest.crc).to(beNil());
+ expect(testRequest.bulkData).to(beNil());
+ #pragma clang diagnostic pop
+ });
+
+ context(@"initWithFileName:fileType:persistentFile:systemFile:offset:length:crc:", ^{
+ SDLPutFile* testRequest = [[SDLPutFile alloc] initWithFileName:@"fileName" fileType:SDLFileTypeMP3 persistentFile:true systemFile:true offset:45 length:34 crc:0xffffffff];
+
+ expect(testRequest.syncFileName).to(equal(@"fileName"));
+ expect(testRequest.fileType).to(equal(SDLFileTypeMP3));
+ expect(testRequest.persistentFile).to(beTrue());
+ expect(testRequest.systemFile).to(beTrue());
+ expect(testRequest.offset).to(equal(@45));
+ expect(testRequest.length).to(equal(@34));
+ expect(testRequest.crc).to(equal(0xffffffff));
+ expect(testRequest.bulkData).to(beNil());
+ });
+
+ context(@"initWithFileName:fileType:persistentFile:systemFile:offset:length:bulkData:", ^{
+ NSData *testFileData = [@"someTextData" dataUsingEncoding:NSUTF8StringEncoding];
+ unsigned long testFileCRC32Checksum = [SDLPutFile sdl_getCRC32ChecksumForBulkData:testFileData];
+
+ SDLPutFile* testRequest = [[SDLPutFile alloc] initWithFileName:@"fileName" fileType:SDLFileTypeAAC persistentFile:true systemFile:true offset:5 length:4 bulkData:testFileData];
+
+ expect(testRequest.syncFileName).to(equal(@"fileName"));
+ expect(testRequest.fileType).to(equal(SDLFileTypeAAC));
+ expect(testRequest.persistentFile).to(beTrue());
+ expect(testRequest.systemFile).to(beTrue());
+ expect(testRequest.offset).to(equal(@5));
+ expect(testRequest.length).to(equal(@4));
+ expect(testRequest.bulkData).to(equal(testFileData));
+ expect(testRequest.crc).to(equal(testFileCRC32Checksum));
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLShowSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLShowSpec.m
index e41d73cc8..cab6d5867 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLShowSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLShowSpec.m
@@ -97,7 +97,7 @@ describe(@"Getter/Setter Tests", ^ {
__block SDLMetadataTags *testTags = nil;
beforeEach(^{
- testGraphic = [[SDLImage alloc] initWithName:@"test name"];
+ testGraphic = [[SDLImage alloc] initWithName:@"test name" isTemplate:false];
testCustomPresets = @[testString1];
testButton = [[SDLSoftButton alloc] initWithType:SDLSoftButtonTypeText text:@"Test Button" image:nil highlighted:NO buttonId:0 systemAction:nil handler:nil];
testSoftButtons = @[testButton];
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSubscribeVehicleDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSubscribeVehicleDataSpec.m
index 3ec8a0adb..78d4fc072 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSubscribeVehicleDataSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSubscribeVehicleDataSpec.m
@@ -209,6 +209,8 @@ describe(@"initializers", ^{
});
context(@"initWithAccelerationPedalPosition:airbagStatus:beltStatus:bodyInformation:clusterModeStatus:deviceStatus:driverBraking:eCallInfo:emergencyEvent:engineTorque:externalTemperature:fuelLevel:fuelLevelState:gps:headLampStatus:instantFuelConsumption:myKey:odometer:prndl:rpm:speed:steeringWheelAngle:tirePressure:wiperStatus:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLSubscribeVehicleData* testRequest = [[SDLSubscribeVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:YES beltStatus:YES bodyInformation:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES emergencyEvent:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:NO gps:YES headLampStatus:YES instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES wiperStatus:YES];
expect(testRequest.accPedalPosition).to(equal(@YES));
@@ -239,6 +241,7 @@ describe(@"initializers", ^{
expect(testRequest.tirePressure).to(equal(@YES));
expect(testRequest.turnSignal).to(equal(@NO));
expect(testRequest.wiperStatus).to(equal(@YES));
+ #pragma clang diagnostic pop
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLUnsubscribeVehicleDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLUnsubscribeVehicleDataSpec.m
index d571d743e..bbb96614a 100644
--- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLUnsubscribeVehicleDataSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLUnsubscribeVehicleDataSpec.m
@@ -209,6 +209,8 @@ describe(@"initializers", ^{
});
context(@"initWithAccelerationPedalPosition:airbagStatus:beltStatus:bodyInformation:clusterModeStatus:deviceStatus:driverBraking:eCallInfo:emergencyEvent:engineTorque:externalTemperature:fuelLevel:fuelLevelState:gps:headLampStatus:instantFuelConsumption:myKey:odometer:prndl:rpm:speed:steeringWheelAngle:tirePressure:wiperStatus:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLUnsubscribeVehicleData *testRequest = [[SDLUnsubscribeVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:YES beltStatus:YES bodyInformation:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES emergencyEvent:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:YES gps:YES headLampStatus:NO instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES wiperStatus:YES];
expect(testRequest.accPedalPosition).to(equal(@YES));
@@ -239,6 +241,7 @@ describe(@"initializers", ^{
expect(testRequest.tirePressure).to(equal(@YES));
expect(testRequest.turnSignal).to(equal(@NO));
expect(testRequest.wiperStatus).to(equal(@YES));
+ #pragma clang diagnostic pop
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLPutFileResponseSpec.m b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLPutFileResponseSpec.m
index 09ae52453..9fb2f42ad 100644
--- a/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLPutFileResponseSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLPutFileResponseSpec.m
@@ -18,15 +18,16 @@ describe(@"Getter/Setter Tests", ^ {
SDLPutFileResponse* testResponse = [[SDLPutFileResponse alloc] init];
testResponse.spaceAvailable = @1248;
-
+
expect(testResponse.spaceAvailable).to(equal(@1248));
});
it(@"Should get correctly when initialized", ^ {
- NSMutableDictionary<NSString *, id> *dict = [@{SDLNameResponse:
+ NSDictionary<NSString *, id> *dict = @{SDLNameResponse:
@{SDLNameParameters:
- @{SDLNameSpaceAvailable:@1248},
- SDLNameOperationName:SDLNamePutFile}} mutableCopy];
+ @{SDLNameSpaceAvailable:@1248,
+ },
+ SDLNameOperationName:SDLNamePutFile}};
SDLPutFileResponse* testResponse = [[SDLPutFileResponse alloc] initWithDictionary:dict];
expect(testResponse.spaceAvailable).to(equal(@1248));
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlCapabilitiesSpec.m
index b45784e78..298dd27a3 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlCapabilitiesSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlCapabilitiesSpec.m
@@ -95,6 +95,8 @@ describe(@"Getter/Setter Tests", ^ {
});
it(@"Should get correctly when initialized with module data and other climate control capabilities parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLClimateControlCapabilities* testStruct = [[SDLClimateControlCapabilities alloc] initWithModuleName:@"Name" fanSpeedAvailable:YES desiredTemperatureAvailable:NO acEnableAvailable:NO acMaxEnableAvailable:YES circulateAirAvailable:NO autoModeEnableAvailable:NO dualModeEnableAvailable:NO defrostZoneAvailable:YES ventilationModeAvailable:YES];
expect(testStruct.moduleName).to(equal(@"Name"));
@@ -110,7 +112,8 @@ describe(@"Getter/Setter Tests", ^ {
expect(testStruct.heatedSteeringWheelAvailable).to(equal(@NO));
expect(testStruct.heatedWindshieldAvailable).to(equal(@NO));
expect(testStruct.heatedRearWindowAvailable).to(equal(@NO));
- expect(testStruct.heatedMirrorsAvailable).to(equal(@NO));;
+ expect(testStruct.heatedMirrorsAvailable).to(equal(@NO));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with module data and other climate control capabilities parameters", ^ {
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlDataSpec.m
index cb3fbff65..2075fb53d 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlDataSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLClimateControlDataSpec.m
@@ -61,6 +61,8 @@ describe(@"Getter/Setter Tests", ^ {
});
it(@"Should get correctly when initialized with FanSpeed and other climate control parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLClimateControlData* testStruct = [[SDLClimateControlData alloc] initWithFanSpeed:@43 desiredTemperature:desiredTemp acEnable:@YES circulateAirEnable:@YES autoModeEnable:@NO defrostZone:SDLDefrostZoneFront dualModeEnable:@NO acMaxEnable:@YES ventilationMode:SDLVentilationModeBoth];
expect(testStruct.fanSpeed).to(equal(@43));
@@ -76,6 +78,7 @@ describe(@"Getter/Setter Tests", ^ {
expect(testStruct.heatedWindshieldEnable).to(equal(NO));
expect(testStruct.heatedRearWindowEnable).to(equal(NO));
expect(testStruct.heatedMirrorsEnable).to(equal(NO));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with FanSpeed and other climate control parameters", ^ {
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m
index 4395a12e7..6c68a3e26 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m
@@ -23,6 +23,9 @@ SDLScreenParams* screenParams = [[SDLScreenParams alloc] init];
SDLTextField* textField = [[SDLTextField alloc] init];
SDLImageField* imageField = [[SDLImageField alloc] init];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
describe(@"Getter/Setter Tests", ^ {
it(@"Should set and get correctly", ^ {
SDLDisplayCapabilities* testStruct = [[SDLDisplayCapabilities alloc] init];
@@ -86,4 +89,6 @@ describe(@"Getter/Setter Tests", ^ {
});
});
+#pragma clang diagnostic pop
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageSpec.m
index 56939ee0e..a88619d1b 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageSpec.m
@@ -93,12 +93,15 @@ describe(@"initializers", ^{
});
context(@"initWithName:ofType:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testImage = [[SDLImage alloc] initWithName:testValue ofType:testImageType];
expect(testImage).toNot(beNil());
expect(testImage.value).to(equal(testValue));
expect(testImage.imageType).to(equal(testImageType));
expect(testImage.isTemplate).to(beFalse());
+ #pragma clang diagnostic pop
});
context(@"initWithName:ofType:isTemplate", ^{
@@ -111,12 +114,15 @@ describe(@"initializers", ^{
});
context(@"initWithName:", ^{
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
testImage = [[SDLImage alloc] initWithName:testValue];
expect(testImage).toNot(beNil());
expect(testImage.value).to(equal(testValue));
expect(testImage.imageType).to(equal(SDLImageTypeDynamic));
expect(testImage.isTemplate).to(beFalse());
+ #pragma clang diagnostic pop
});
context(@"initWithName:isTemplate", ^{
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlCapabilitiesSpec.m
index 70873d96e..d51d7910e 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlCapabilitiesSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlCapabilitiesSpec.m
@@ -101,7 +101,9 @@ describe(@"Initialization tests", ^{
});
- it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
+ it(@"Should get correctly when initialized with Module Name and other radio control capability parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLRadioControlCapabilities* testStruct = [[SDLRadioControlCapabilities alloc] initWithModuleName:@"someName" radioEnableAvailable:YES radioBandAvailable:NO radioFrequencyAvailable:YES hdChannelAvailable:NO rdsDataAvailable:NO availableHDsAvailable:NO stateAvailable:YES signalStrengthAvailable:YES signalChangeThresholdAvailable:NO];
expect(testStruct.moduleName).to(equal(@"someName"));
@@ -116,6 +118,7 @@ describe(@"Initialization tests", ^{
expect(testStruct.signalChangeThresholdAvailable).to(equal(@NO));
expect(testStruct.hdRadioEnableAvailable).to(equal(@NO));
expect(testStruct.siriusXMRadioAvailable).to(equal(@NO));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlDataSpec.m
index 02e38bcaa..ec56d4513 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlDataSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRadioControlDataSpec.m
@@ -36,11 +36,9 @@ describe(@"Initialization tests", ^{
expect(testStruct.state).to(beNil());
expect(testStruct.hdRadioEnable).to(beNil());
expect(testStruct.sisData).to(beNil());
-
});
it(@"should properly initialize initWithDictionary", ^{
-
NSMutableDictionary* dict = [@{SDLNameFrequencyInteger : @101,
SDLNameFrequencyFraction : @7,
SDLNameBand : SDLRadioBandAM,
@@ -68,7 +66,6 @@ describe(@"Initialization tests", ^{
expect(testStruct.state).to(equal(SDLRadioStateNotFound));
expect(testStruct.hdRadioEnable).to(equal(@NO));
expect(testStruct.sisData).to(equal(someSisData));
-
});
it(@"Should set and get correctly", ^{
@@ -101,6 +98,8 @@ describe(@"Initialization tests", ^{
});
it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLRadioControlData* testStruct = [[SDLRadioControlData alloc] initWithFrequencyInteger:@101 frequencyFraction:@7 band:SDLRadioBandAM hdChannel:@2 radioEnable:@YES];
expect(testStruct.frequencyInteger).to(equal(@101));
@@ -108,9 +107,12 @@ describe(@"Initialization tests", ^{
expect(testStruct.band).to(equal(SDLRadioBandAM));
expect(testStruct.hdChannel).to(equal(@2));
expect(testStruct.radioEnable).to(equal(@YES));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLRadioControlData* testStruct = [[SDLRadioControlData alloc] initWithFrequencyInteger:@101 frequencyFraction:@7 band:SDLRadioBandAM hdChannel:@2 radioEnable:@YES];
expect(testStruct.frequencyInteger).to(equal(@101));
@@ -118,9 +120,12 @@ describe(@"Initialization tests", ^{
expect(testStruct.band).to(equal(SDLRadioBandAM));
expect(testStruct.hdChannel).to(equal(@2));
expect(testStruct.radioEnable).to(equal(@YES));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLRadioControlData* testStruct = [[SDLRadioControlData alloc] initWithFrequencyInteger:@101 frequencyFraction:@7 band:SDLRadioBandAM hdChannel:@2 radioEnable:@YES];
expect(testStruct.frequencyInteger).to(equal(@101));
@@ -129,6 +134,7 @@ describe(@"Initialization tests", ^{
expect(testStruct.hdChannel).to(equal(@2));
expect(testStruct.radioEnable).to(equal(@YES));
expect(testStruct.sisData).to(beNil());
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with Module Name and other radio control capabilite's parameters", ^ {
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRemoteControlCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRemoteControlCapabilitiesSpec.m
index f7547af26..7067d058d 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRemoteControlCapabilitiesSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRemoteControlCapabilitiesSpec.m
@@ -89,12 +89,15 @@ describe(@"Initialization tests", ^{
});
it(@"Should get correctly when initialized with climateControlCapabilities and other RemoteControlCapabilities parameters", ^ {
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLRemoteControlCapabilities* testStruct = [[SDLRemoteControlCapabilities alloc] initWithClimateControlCapabilities:[@[someClimateControlCapabilities] copy] radioControlCapabilities:[@[someRadioControlCapabilities] copy] buttonCapabilities:[@[someButtonControlCapabilities] copy]];
expect(testStruct.seatControlCapabilities).to(beNil());
expect(testStruct.climateControlCapabilities).to(equal(([@[someClimateControlCapabilities] copy])));
expect(testStruct.radioControlCapabilities).to(equal([@[someRadioControlCapabilities] copy]));
expect(testStruct.buttonCapabilities).to(equal([@[someButtonControlCapabilities] copy]));
+ #pragma clang diagnostic pop
});
it(@"Should get correctly when initialized with climateControlCapabilities and other RemoteControlCapabilities parameters", ^ {
diff --git a/SmartDeviceLinkTests/SDLFileManagerConfigurationSpec.m b/SmartDeviceLinkTests/SDLFileManagerConfigurationSpec.m
new file mode 100644
index 000000000..5b7742be2
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLFileManagerConfigurationSpec.m
@@ -0,0 +1,50 @@
+//
+// SDLFileManagerConfigurationSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 8/1/18.
+// Copyright © 2018 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLFileManagerConfiguration.h"
+
+QuickSpecBegin(SDLFileManagerConfigurationSpec)
+
+describe(@"A file manager configuration", ^{
+ __block SDLFileManagerConfiguration *testConfig = nil;
+
+ it(@"should get and set correctly", ^{
+ testConfig = [[SDLFileManagerConfiguration alloc] init];
+ testConfig.artworkRetryCount = 5;
+ testConfig.fileRetryCount = 1;
+
+ expect(testConfig.artworkRetryCount).to(equal(5));
+ expect(testConfig.fileRetryCount).to(equal(1));
+ });
+
+ it(@"should be set to default configuration if parameters are not set", ^{
+ testConfig = [[SDLFileManagerConfiguration alloc] init];
+
+ expect(testConfig.artworkRetryCount).to(equal(1));
+ expect(testConfig.fileRetryCount).to(equal(1));
+ });
+
+ it(@"should instantiate correctly with the default configuration", ^{
+ testConfig = [SDLFileManagerConfiguration defaultConfiguration];
+
+ expect(testConfig.artworkRetryCount).to(equal(1));
+ expect(testConfig.fileRetryCount).to(equal(1));
+ });
+
+ it(@"should instantiate correctly with initWithArtworkRetryCount:fileRetryCount:", ^{
+ testConfig = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:2 fileRetryCount:3];
+
+ expect(testConfig.artworkRetryCount).to(equal(2));
+ expect(testConfig.fileRetryCount).to(equal(3));
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLink_Example/Classes/ProxyManager.m b/SmartDeviceLink_Example/Classes/ProxyManager.m
index 247f8f925..7facc514e 100644
--- a/SmartDeviceLink_Example/Classes/ProxyManager.m
+++ b/SmartDeviceLink_Example/Classes/ProxyManager.m
@@ -113,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)sdlex_setupConfigurationWithLifecycleConfiguration:(SDLLifecycleConfiguration *)lifecycleConfiguration {
- SDLConfiguration *config = [SDLConfiguration configurationWithLifecycle:lifecycleConfiguration lockScreen:[SDLLockScreenConfiguration enabledConfigurationWithAppIcon:[UIImage imageNamed:ExampleAppLogoName] backgroundColor:nil] logging:[self.class sdlex_logConfiguration]];
+ SDLConfiguration *config = [SDLConfiguration configurationWithLifecycle:lifecycleConfiguration lockScreen:[SDLLockScreenConfiguration enabledConfigurationWithAppIcon:[UIImage imageNamed:ExampleAppLogoName] backgroundColor:nil] logging:[self.class sdlex_logConfiguration] fileManager:[SDLFileManagerConfiguration defaultConfiguration]];
self.sdlManager = [[SDLManager alloc] initWithConfiguration:config delegate:self];
[self startManager];
@@ -129,6 +129,7 @@ NS_ASSUME_NONNULL_BEGIN
config.ttsName = [SDLTTSChunk textChunksFromString:ExampleAppName];
config.language = SDLLanguageEnUs;
config.languagesSupported = @[SDLLanguageEnUs, SDLLanguageFrCa, SDLLanguageEsMx];
+ config.appType = SDLAppHMITypeDefault;
SDLRGBColor *green = [[SDLRGBColor alloc] initWithRed:126 green:188 blue:121];
SDLRGBColor *white = [[SDLRGBColor alloc] initWithRed:249 green:251 blue:254];
diff --git a/SmartDeviceLink_Example/ProxyManager.swift b/SmartDeviceLink_Example/ProxyManager.swift
index 20c9ef48e..e5c30aeca 100644
--- a/SmartDeviceLink_Example/ProxyManager.swift
+++ b/SmartDeviceLink_Example/ProxyManager.swift
@@ -99,7 +99,7 @@ private extension ProxyManager {
lifecycleConfiguration.nightColorScheme = SDLTemplateColorScheme(primaryRGBColor: green, secondaryRGBColor: grey, backgroundRGBColor: darkGrey)
let lockScreenConfiguration = appIcon != nil ? SDLLockScreenConfiguration.enabledConfiguration(withAppIcon: appIcon!, backgroundColor: nil) : SDLLockScreenConfiguration.enabled()
- return SDLConfiguration(lifecycle: lifecycleConfiguration, lockScreen: lockScreenConfiguration, logging: logConfiguration())
+ return SDLConfiguration(lifecycle: lifecycleConfiguration, lockScreen: lockScreenConfiguration, logging: logConfiguration(), fileManager:.default())
}
/// Sets the type of SDL debug logs that are visible and where to port the logs. There are 4 levels of log filtering, verbose, debug, warning and error. Verbose prints all SDL logs; error prints only the error logs. Adding SDLLogTargetFile to the targest will log to a text file on the iOS device. This file can be accessed via: iTunes > Your Device Name > File Sharing > Your App Name. Make sure `UIFileSharingEnabled` has been added to the application's info.plist and is set to `true`.