summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2020-03-18 13:46:19 -0400
committerJoel Fischer <joeljfischer@gmail.com>2020-03-18 13:46:19 -0400
commitea063fff4f479426c8260e38843e08143f001a8a (patch)
treee57dc9a7fc16218db373e751f5d1046b4486f8d5
parentc6154d868b253c4eeb14ebfc7e31341176cd01a9 (diff)
parent08c365cfa2842e05af6d140ba88bed853f49c31c (diff)
downloadsdl_ios-ea063fff4f479426c8260e38843e08143f001a8a.tar.gz
Merge branch 'develop' into bugfix/issue_1569_streaming_media_manager_incorrect_value_for_isStreamingSupported
-rw-r--r--Example Apps/Example ObjC/PerformInteractionManager.m4
-rw-r--r--Example Apps/Example Swift/PerformInteractionManager.swift4
-rw-r--r--SmartDeviceLink/SDLChoiceSetManager.m107
-rw-r--r--SmartDeviceLink/SDLDisplayCapability.h6
-rw-r--r--SmartDeviceLink/SDLDisplayCapability.m8
-rw-r--r--SmartDeviceLink/SDLError.m12
-rw-r--r--SmartDeviceLink/SDLImageField.h6
-rw-r--r--SmartDeviceLink/SDLImageField.m11
-rw-r--r--SmartDeviceLink/SDLMenuManager.m90
-rw-r--r--SmartDeviceLink/SDLOnHMIStatus.h8
-rw-r--r--SmartDeviceLink/SDLOnHMIStatus.m13
-rw-r--r--SmartDeviceLink/SDLPreloadChoicesOperation.h2
-rw-r--r--SmartDeviceLink/SDLPreloadChoicesOperation.m50
-rw-r--r--SmartDeviceLink/SDLProxy.m89
-rw-r--r--SmartDeviceLink/SDLSoftButtonManager.m64
-rw-r--r--SmartDeviceLink/SDLSoftButtonReplaceOperation.h2
-rw-r--r--SmartDeviceLink/SDLSoftButtonReplaceOperation.m6
-rw-r--r--SmartDeviceLink/SDLSystemCapabilityManager.m1
-rw-r--r--SmartDeviceLink/SDLTextAndGraphicManager.m20
-rw-r--r--SmartDeviceLink/SDLTextField.h7
-rw-r--r--SmartDeviceLink/SDLTextField.m12
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m92
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m28
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m93
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m103
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/NotificationSpecs/SDLOnHMIStatusSpec.m66
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageFieldSpec.m44
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLTextFieldSpec.m46
-rw-r--r--SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m36
29 files changed, 721 insertions, 309 deletions
diff --git a/Example Apps/Example ObjC/PerformInteractionManager.m b/Example Apps/Example ObjC/PerformInteractionManager.m
index 0cc389f92..d80c706b0 100644
--- a/Example Apps/Example ObjC/PerformInteractionManager.m
+++ b/Example Apps/Example ObjC/PerformInteractionManager.m
@@ -66,16 +66,19 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - SDLChoiceSetDelegate
- (void)choiceSet:(SDLChoiceSet *)choiceSet didSelectChoice:(SDLChoiceCell *)choice withSource:(SDLTriggerSource)source atRowIndex:(NSUInteger)rowIndex {
+ SDLLogD(@"User selected row: %lu, choice: %@", (unsigned long)rowIndex, choice);
[self.manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSGoodJob]];
}
- (void)choiceSet:(SDLChoiceSet *)choiceSet didReceiveError:(NSError *)error {
+ SDLLogE(@"Error presenting choice set: %@", error);
[self.manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSYouMissed]];
}
#pragma mark - SDLKeyboardDelegate
- (void)userDidSubmitInput:(NSString *)inputText withEvent:(SDLKeyboardEvent)source {
+ SDLLogD(@"User did submit keyboard input: %@, with event: %@", inputText, source);
if ([source isEqualToEnum:SDLKeyboardEventSubmitted]) {
[self.manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSGoodJob]];
} else if ([source isEqualToEnum:SDLKeyboardEventVoice]) {
@@ -84,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)keyboardDidAbortWithReason:(SDLKeyboardEvent)event {
+ SDLLogW(@"Keyboard aborted with reason: %@", event);
[self.manager sendRequest:[[SDLSpeak alloc] initWithTTS:TTSYouMissed]];
}
diff --git a/Example Apps/Example Swift/PerformInteractionManager.swift b/Example Apps/Example Swift/PerformInteractionManager.swift
index 793f6526c..38bf9f606 100644
--- a/Example Apps/Example Swift/PerformInteractionManager.swift
+++ b/Example Apps/Example Swift/PerformInteractionManager.swift
@@ -56,16 +56,19 @@ private extension PerformInteractionManager {
extension PerformInteractionManager: SDLChoiceSetDelegate {
func choiceSet(_ choiceSet: SDLChoiceSet, didSelectChoice choice: SDLChoiceCell, withSource source: SDLTriggerSource, atRowIndex rowIndex: UInt) {
+ SDLLog.d("User selected row: \(rowIndex), choice: \(choice)")
manager.send(SDLSpeak(tts: TTSGoodJob))
}
func choiceSet(_ choiceSet: SDLChoiceSet, didReceiveError error: Error) {
+ SDLLog.e("Error presenting choice set: \(error)")
manager.send(SDLSpeak(tts: TTSYouMissed))
}
}
extension PerformInteractionManager: SDLKeyboardDelegate {
func keyboardDidAbort(withReason event: SDLKeyboardEvent) {
+ SDLLog.w("Keyboard aborted with reason: \(event)")
switch event {
case SDLKeyboardEvent.cancelled:
manager.send(SDLSpeak(tts: TTSYouMissed))
@@ -76,6 +79,7 @@ extension PerformInteractionManager: SDLKeyboardDelegate {
}
func userDidSubmitInput(_ inputText: String, withEvent source: SDLKeyboardEvent) {
+ SDLLog.d("User did submit keyboard input: \(inputText), with event: \(source)")
switch source {
case SDLKeyboardEvent.voice: break
// Start Voice search
diff --git a/SmartDeviceLink/SDLChoiceSetManager.m b/SmartDeviceLink/SDLChoiceSetManager.m
index 793876db7..a3f658b6c 100644
--- a/SmartDeviceLink/SDLChoiceSetManager.m
+++ b/SmartDeviceLink/SDLChoiceSetManager.m
@@ -36,8 +36,10 @@
#import "SDLRPCResponseNotification.h"
#import "SDLSetDisplayLayoutResponse.h"
#import "SDLStateMachine.h"
-#import "SDLSystemContext.h"
+#import "SDLSystemCapability.h"
#import "SDLSystemCapabilityManager.h"
+#import "SDLWindowCapability.h"
+#import "SDLWindowCapability+ShowManagerExtensions.h"
NS_ASSUME_NONNULL_BEGIN
@@ -64,7 +66,7 @@ typedef NSNumber * SDLChoiceId;
@property (strong, nonatomic) NSOperationQueue *transactionQueue;
@property (copy, nonatomic, nullable) SDLHMILevel currentHMILevel;
-@property (copy, nonatomic, nullable) SDLSystemContext currentSystemContext;
+@property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability;
@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *preloadedMutableChoices;
@property (strong, nonatomic, readonly) NSSet<SDLChoiceCell *> *pendingPreloadChoices;
@@ -102,6 +104,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
_nextCancelId = ChoiceCellCancelIdMin;
_vrOptional = YES;
_keyboardConfiguration = [self sdl_defaultKeyboardConfiguration];
+ _currentHMILevel = SDLHMILevelNone;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_hmiStatusNotification:) name:SDLDidChangeHMIStatusNotification object:nil];
@@ -109,6 +112,8 @@ UInt16 const ChoiceCellCancelIdMin = 1;
}
- (void)start {
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate:)];
+
if ([self.currentState isEqualToString:SDLChoiceManagerStateShutdown]) {
[self.stateMachine transitionToState:SDLChoiceManagerStateCheckingVoiceOptional];
}
@@ -139,11 +144,23 @@ UInt16 const ChoiceCellCancelIdMin = 1;
return queue;
}
+/// Suspend the transaction queue if we are in HMI NONE
+/// OR if the text field name "menu name" (i.e. is the primary choice text) cannot be used, we assume we cannot present a PI.
+- (void)sdl_updateTransactionQueueSuspended {
+ if ([self.currentHMILevel isEqualToEnum:SDLHMILevelNone]
+ || (![self.currentWindowCapability hasTextFieldOfName:SDLTextFieldNameMenuName])) {
+ SDLLogD(@"Suspending the transaction queue. Current HMI level is: %@, window capability has MenuName (choice primary text): %@", self.currentHMILevel, ([self.currentWindowCapability hasTextFieldOfName:SDLTextFieldNameMenuName] ? @"YES" : @"NO"));
+ self.transactionQueue.suspended = YES;
+ } else {
+ SDLLogD(@"Starting the transaction queue");
+ self.transactionQueue.suspended = NO;
+ }
+}
+
#pragma mark - State Management
- (void)didEnterStateShutdown {
- _currentHMILevel = nil;
- _currentSystemContext = nil;
+ _currentHMILevel = SDLHMILevelNone;
[self.transactionQueue cancelAllOperations];
self.transactionQueue = [self sdl_newTransactionQueue];
@@ -163,9 +180,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
__weak typeof(self) weakself = self;
__weak typeof(checkOp) weakOp = checkOp;
checkOp.completionBlock = ^{
- if ([self.currentState isEqualToString:SDLChoiceManagerStateShutdown]) {
- return;
- }
+ if ([self.currentState isEqualToString:SDLChoiceManagerStateShutdown]) { return; }
weakself.vrOptional = weakOp.isVROptional;
if (weakOp.error != nil) {
@@ -187,9 +202,11 @@ UInt16 const ChoiceCellCancelIdMin = 1;
#pragma mark Upload / Delete
- (void)preloadChoices:(NSArray<SDLChoiceCell *> *)choices withCompletionHandler:(nullable SDLPreloadChoiceCompletionHandler)handler {
+ SDLLogV(@"Request to preload choices: %@", choices);
if ([self.currentState isEqualToString:SDLChoiceManagerStateShutdown]) {
+ NSError *error = [NSError sdl_choiceSetManager_incorrectState:self.currentState];
+ SDLLogE(@"Attempted to preload choices but the choice set manager is shut down: %@", error);
if (handler != nil) {
- NSError *error = [NSError sdl_choiceSetManager_incorrectState:self.currentState];
handler(error);
}
return;
@@ -214,12 +231,15 @@ UInt16 const ChoiceCellCancelIdMin = 1;
// Upload pending preloads
// For backward compatibility with Gen38Inch display type head units
+ SDLLogD(@"Preloading choices");
+ SDLLogV(@"Choices to be uploaded: %@", choicesToUpload);
NSString *displayName = self.systemCapabilityManager.displays.firstObject.displayName;
- SDLPreloadChoicesOperation *preloadOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager displayName:displayName defaultMainWindowCapability:self.systemCapabilityManager.defaultMainWindowCapability isVROptional:self.isVROptional cellsToPreload:choicesToUpload];
+ SDLPreloadChoicesOperation *preloadOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager displayName:displayName windowCapability:self.systemCapabilityManager.defaultMainWindowCapability isVROptional:self.isVROptional cellsToPreload:choicesToUpload];
__weak typeof(self) weakSelf = self;
__weak typeof(preloadOp) weakPreloadOp = preloadOp;
preloadOp.completionBlock = ^{
+ SDLLogD(@"Choices finished preloading");
[weakSelf.preloadedMutableChoices unionSet:choicesToUpload];
[weakSelf.pendingMutablePreloadChoices minusSet:choicesToUpload];
@@ -231,7 +251,11 @@ UInt16 const ChoiceCellCancelIdMin = 1;
}
- (void)deleteChoices:(NSArray<SDLChoiceCell *> *)choices {
- if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) { return; }
+ SDLLogV(@"Request to delete choices: %@", choices);
+ if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) {
+ SDLLogE(@"Attempted to delete choices in an incorrect state: %@, they will not be deleted", self.currentState);
+ return;
+ }
// Find cells to be deleted that are already uploaded or are pending upload
NSSet<SDLChoiceCell *> *cellsToBeDeleted = [self sdl_choicesToBeDeletedWithArray:choices];
@@ -272,6 +296,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
return;
}
+ SDLLogD(@"Finished deleting choices");
[weakself.preloadedMutableChoices minusSet:cellsToBeDeleted];
};
[self.transactionQueue addOperation:deleteOp];
@@ -280,7 +305,10 @@ UInt16 const ChoiceCellCancelIdMin = 1;
#pragma mark Present
- (void)presentChoiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode withKeyboardDelegate:(nullable id<SDLKeyboardDelegate>)delegate {
- if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) { return; }
+ if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) {
+ SDLLogE(@"Attempted to present choices in an incorrect state: %@, it will not be presented", self.currentState);
+ return;
+ }
if (choiceSet == nil) {
SDLLogW(@"Attempted to present a nil choice set, ignoring.");
@@ -288,9 +316,11 @@ UInt16 const ChoiceCellCancelIdMin = 1;
}
if (self.pendingPresentationSet != nil) {
+ SDLLogW(@"A choice set is pending: %@. We will try to cancel it in favor of presenting a different choice set: %@. If it's already on screen it cannot be cancelled", self.pendingPresentationSet, choiceSet);
[self.pendingPresentOperation cancel];
}
+ SDLLogD(@"Preloading and presenting choice set: %@", choiceSet);
self.pendingPresentationSet = choiceSet;
[self preloadChoices:self.pendingPresentationSet.choices withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
@@ -316,6 +346,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
self.pendingPresentOperation.completionBlock = ^{
__strong typeof(weakOp) strongOp = weakOp;
+ SDLLogD(@"Finished presenting choice set: %@", strongOp.choiceSet);
if (strongOp.error != nil && strongOp.choiceSet.delegate != nil) {
[strongOp.choiceSet.delegate choiceSet:strongOp.choiceSet didReceiveError:strongOp.error];
} else if (strongOp.selectedCell != nil && strongOp.choiceSet.delegate != nil) {
@@ -325,17 +356,23 @@ UInt16 const ChoiceCellCancelIdMin = 1;
weakself.pendingPresentationSet = nil;
weakself.pendingPresentOperation = nil;
};
+
[self.transactionQueue addOperation:presentOp];
}
- (nullable NSNumber<SDLInt> *)presentKeyboardWithInitialText:(NSString *)initialText delegate:(id<SDLKeyboardDelegate>)delegate {
- if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) { return nil; }
+ if (![self.currentState isEqualToString:SDLChoiceManagerStateReady]) {
+ SDLLogE(@"Attempted to present keyboard in an incorrect state: %@, it will not be presented", self.currentState);
+ return nil;
+ }
if (self.pendingPresentationSet != nil) {
+ SDLLogW(@"There's already a pending presentation set, cancelling it in favor of a keyboard");
[self.pendingPresentOperation cancel];
self.pendingPresentationSet = nil;
}
+ SDLLogD(@"Presenting keyboard with initial text: %@", initialText);
// Present a keyboard with the choice set that we used to test VR's optional state
UInt16 keyboardCancelId = self.nextCancelId++;
self.pendingPresentOperation = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:self.connectionManager keyboardProperties:self.keyboardConfiguration initialText:initialText keyboardDelegate:delegate cancelID:keyboardCancelId];
@@ -350,6 +387,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
SDLPresentKeyboardOperation *keyboardOperation = (SDLPresentKeyboardOperation *)op;
if (keyboardOperation.cancelId != cancelID.unsignedShortValue) { continue; }
+ SDLLogD(@"Dismissing keyboard with cancel ID: %@", cancelID);
[keyboardOperation dismissKeyboard];
break;
}
@@ -403,8 +441,10 @@ UInt16 const ChoiceCellCancelIdMin = 1;
- (void)setKeyboardConfiguration:(nullable SDLKeyboardProperties *)keyboardConfiguration {
if (keyboardConfiguration == nil) {
+ SDLLogD(@"Updating keyboard configuration to the default");
_keyboardConfiguration = [self sdl_defaultKeyboardConfiguration];
} else {
+ SDLLogD(@"Updating keyboard configuration to a new configuration: %@", keyboardConfiguration);
_keyboardConfiguration = [[SDLKeyboardProperties alloc] initWithLanguage:keyboardConfiguration.language layout:keyboardConfiguration.keyboardLayout keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:keyboardConfiguration.limitedCharacterList autoCompleteText:keyboardConfiguration.autoCompleteText autoCompleteList:keyboardConfiguration.autoCompleteList];
if (keyboardConfiguration.keypressMode != SDLKeypressModeResendCurrentEntry) {
@@ -433,35 +473,32 @@ UInt16 const ChoiceCellCancelIdMin = 1;
#pragma mark - RPC Responses / Notifications
-- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification {
- // We can only present a choice set if we're in FULL
- SDLOnHMIStatus *hmiStatus = (SDLOnHMIStatus *)notification.notification;
-
- if (hmiStatus.windowID != nil && hmiStatus.windowID.integerValue != SDLPredefinedWindowsDefaultWindow) {
- return;
- }
-
- SDLHMILevel oldHMILevel = self.currentHMILevel;
- self.currentHMILevel = hmiStatus.hmiLevel;
+- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability {
+ NSArray<SDLDisplayCapability *> *capabilities = systemCapability.displayCapabilities;
+ if (capabilities == nil || capabilities.count == 0) {
+ self.currentWindowCapability = nil;
+ } else {
+ SDLDisplayCapability *mainDisplay = capabilities[0];
+ for (SDLWindowCapability *windowCapability in mainDisplay.windowCapabilities) {
+ NSUInteger currentWindowID = windowCapability.windowID != nil ? windowCapability.windowID.unsignedIntegerValue : SDLPredefinedWindowsDefaultWindow;
+ if (currentWindowID != SDLPredefinedWindowsDefaultWindow) { continue; }
- if ([self.currentHMILevel isEqualToEnum:SDLHMILevelNone]) {
- self.transactionQueue.suspended = YES;
+ self.currentWindowCapability = windowCapability;
+ break;
+ }
}
- if ([oldHMILevel isEqualToEnum:SDLHMILevelNone] && ![self.currentHMILevel isEqualToEnum:SDLHMILevelNone]) {
- self.transactionQueue.suspended = NO;
- }
+ [self sdl_updateTransactionQueueSuspended];
+}
- // We need to check for this to make sure we can currently present the dialog. If the current context is HMI_OBSCURED or ALERT, we have to wait for MAIN to present
- self.currentSystemContext = hmiStatus.systemContext;
+- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification {
+ // We can only present a choice set if we're in FULL
+ SDLOnHMIStatus *hmiStatus = (SDLOnHMIStatus *)notification.notification;
+ if (hmiStatus.windowID != nil && hmiStatus.windowID.integerValue != SDLPredefinedWindowsDefaultWindow) { return; }
- if ([self.currentSystemContext isEqualToEnum:SDLSystemContextHMIObscured] || [self.currentSystemContext isEqualToEnum:SDLSystemContextAlert]) {
- self.transactionQueue.suspended = YES;
- }
+ self.currentHMILevel = hmiStatus.hmiLevel;
- if ([self.currentSystemContext isEqualToEnum:SDLSystemContextMain] && ![self.currentHMILevel isEqualToEnum:SDLHMILevelNone]) {
- self.transactionQueue.suspended = NO;
- }
+ [self sdl_updateTransactionQueueSuspended];
}
@end
diff --git a/SmartDeviceLink/SDLDisplayCapability.h b/SmartDeviceLink/SDLDisplayCapability.h
index f29c092af..7be6a589e 100644
--- a/SmartDeviceLink/SDLDisplayCapability.h
+++ b/SmartDeviceLink/SDLDisplayCapability.h
@@ -23,15 +23,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (instancetype)initWithDisplayName:(NSString *)displayName;
+/// This method is broken (the types don't match the parameter names) and will always return nil. Use initWithDisplayName:windowCapabilities:windowTypeSupported: instead.
+- (instancetype)initWithDisplayName:(NSString *)displayName windowTypeSupported:(nullable NSArray<SDLWindowCapability *> *)windowTypeSupported windowCapabilities:(nullable NSArray<SDLWindowTypeCapabilities *> *)windowCapabilities __deprecated_msg("This method is broken and will return nil every time. Use initWithDisplayName:windowCapabilities:windowTypeSupported: instead");
/**
Init with all the properities
@param displayName Name of the display.
- @param windowTypeSupported Informs the application how many windows the app is allowed to create per type.
@param windowCapabilities Contains a list of capabilities of all windows related to the app. @see windowCapabilities
+ @param windowTypeSupported Informs the application how many windows the app is allowed to create per type.
*/
-- (instancetype)initWithDisplayName:(NSString *)displayName windowTypeSupported:(nullable NSArray<SDLWindowCapability *> *)windowTypeSupported windowCapabilities:(nullable NSArray<SDLWindowTypeCapabilities *> *)windowCapabilities;
+- (instancetype)initWithDisplayName:(NSString *)displayName windowCapabilities:(nullable NSArray<SDLWindowCapability *> *)windowCapabilities windowTypeSupported:(nullable NSArray<SDLWindowTypeCapabilities *> *)windowTypeSupported;
/**
diff --git a/SmartDeviceLink/SDLDisplayCapability.m b/SmartDeviceLink/SDLDisplayCapability.m
index b4d8b319a..04c23cca2 100644
--- a/SmartDeviceLink/SDLDisplayCapability.m
+++ b/SmartDeviceLink/SDLDisplayCapability.m
@@ -28,7 +28,13 @@
return self;
}
-- (instancetype)initWithDisplayName:(NSString *)displayName windowTypeSupported:(nullable NSArray<SDLWindowTypeCapabilities *> *)windowTypeSupported windowCapabilities:(nullable NSArray<SDLWindowCapability *> *)windowCapabilities{
+- (instancetype)initWithDisplayName:(NSString *)displayName windowTypeSupported:(NSArray<SDLWindowCapability *> *)windowTypeSupported windowCapabilities:(NSArray<SDLWindowTypeCapabilities *> *)windowCapabilities {
+ SDLLogE(@"This method is broken (the types don't match the parameter names) and will always return nil. Use initWithDisplayName:windowCapabilities:windowTypeSupported: instead.");
+
+ return nil;
+}
+
+- (instancetype)initWithDisplayName:(NSString *)displayName windowCapabilities:(nullable NSArray<SDLWindowCapability *> *)windowCapabilities windowTypeSupported:(nullable NSArray<SDLWindowTypeCapabilities *> *)windowTypeSupported {
self = [self initWithDisplayName:displayName];
if (!self) {
return nil;
diff --git a/SmartDeviceLink/SDLError.m b/SmartDeviceLink/SDLError.m
index b06d3dc3e..d98609d89 100644
--- a/SmartDeviceLink/SDLError.m
+++ b/SmartDeviceLink/SDLError.m
@@ -70,8 +70,7 @@ SDLErrorDomain *const SDLErrorDomainRPCStore = @"com.sdl.rpcStore.error";
+ (NSError *)sdl_lifecycle_rpcErrorWithDescription:(NSString *)description andReason:(NSString *)reason {
NSDictionary<NSString *, NSString *> *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(description, nil),
- NSLocalizedFailureReasonErrorKey: NSLocalizedString(reason, nil),
- NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Have you tried turning it off and on again?", nil)
+ NSLocalizedFailureReasonErrorKey: NSLocalizedString(reason, nil)
};
return [NSError errorWithDomain:SDLErrorDomainLifecycleManager
code:SDLManagerErrorRPCRequestFailed
@@ -81,8 +80,7 @@ SDLErrorDomain *const SDLErrorDomainRPCStore = @"com.sdl.rpcStore.error";
+ (NSError *)sdl_lifecycle_notConnectedError {
NSDictionary<NSString *, NSString *> *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Could not find a connection", nil),
- NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The SDL library could not find a current connection to an SDL hardware device", nil),
- NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Have you tried turning it off and on again?", nil)
+ NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The SDL library could not find a current connection to an SDL hardware device", nil)
};
return [NSError errorWithDomain:SDLErrorDomainLifecycleManager
@@ -93,8 +91,7 @@ SDLErrorDomain *const SDLErrorDomainRPCStore = @"com.sdl.rpcStore.error";
+ (NSError *)sdl_lifecycle_notReadyError {
NSDictionary<NSString *, NSString *> *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Lifecycle manager not ready", nil),
- NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The SDL library is not finished setting up the connection, please wait until the lifecycleState is SDLLifecycleStateReady", nil),
- NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Have you tried turning it off and on again?", nil)
+ NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The SDL library is not finished setting up the connection, please wait until the lifecycleState is SDLLifecycleStateReady", nil)
};
return [NSError errorWithDomain:SDLErrorDomainLifecycleManager
@@ -105,8 +102,7 @@ SDLErrorDomain *const SDLErrorDomainRPCStore = @"com.sdl.rpcStore.error";
+ (NSError *)sdl_lifecycle_unknownRemoteErrorWithDescription:(NSString *)description andReason:(NSString *)reason {
NSDictionary<NSString *, NSString *> *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(description, nil),
- NSLocalizedFailureReasonErrorKey: NSLocalizedString(reason, nil),
- NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Have you tried turning it off and on again?", nil)
+ NSLocalizedFailureReasonErrorKey: NSLocalizedString(reason, nil)
};
return [NSError errorWithDomain:SDLErrorDomainLifecycleManager
code:SDLManagerErrorUnknownRemoteError
diff --git a/SmartDeviceLink/SDLImageField.h b/SmartDeviceLink/SDLImageField.h
index 5e8d9ab6b..717ab935b 100644
--- a/SmartDeviceLink/SDLImageField.h
+++ b/SmartDeviceLink/SDLImageField.h
@@ -36,6 +36,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nullable, strong, nonatomic) SDLImageResolution *imageResolution;
+/// Convenience initalizer for the ImageField RPC struct
+/// @param name The name identifying this image field
+/// @param imageTypeSupported The image data types this field supports
+/// @param imageResolution The native resolution of this image field
+- (instancetype)initWithName:(SDLImageFieldName)name imageTypeSupported:(NSArray<SDLFileType> *)imageTypeSupported imageResolution:(SDLImageResolution *)imageResolution;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLImageField.m b/SmartDeviceLink/SDLImageField.m
index e866db1d7..f0fc0e4c5 100644
--- a/SmartDeviceLink/SDLImageField.m
+++ b/SmartDeviceLink/SDLImageField.m
@@ -38,6 +38,17 @@ NS_ASSUME_NONNULL_BEGIN
return [self.store sdl_objectForName:SDLRPCParameterNameImageResolution ofClass:SDLImageResolution.class error:nil];
}
+- (instancetype)initWithName:(SDLImageFieldName)name imageTypeSupported:(NSArray<SDLFileType> *)imageTypeSupported imageResolution:(SDLImageResolution *)imageResolution {
+ self = [self init];
+ if (!self) { return nil; }
+
+ self.name = name;
+ self.imageTypeSupported = imageTypeSupported;
+ self.imageResolution = imageResolution;
+
+ return self;
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m
index aa3a1e22f..28a70f754 100644
--- a/SmartDeviceLink/SDLMenuManager.m
+++ b/SmartDeviceLink/SDLMenuManager.m
@@ -197,6 +197,56 @@ UInt32 const MenuCellIdMin = 1;
}
}
+#pragma mark - Open Menu
+
+- (BOOL)openMenu {
+ if ([SDLGlobals.sharedGlobals.rpcVersion isLessThanVersion:[[SDLVersion alloc] initWithMajor:6 minor:0 patch:0]]) {
+ SDLLogE(@"The openMenu method is not supported on this head unit.");
+ return NO;
+ }
+
+ SDLShowAppMenu *openMenu = [[SDLShowAppMenu alloc] init];
+
+ [self.connectionManager sendConnectionRequest:openMenu withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if ([response.resultCode isEqualToEnum:SDLResultWarnings]) {
+ SDLLogW(@"Warning opening application menu: %@", error);
+ } else if (![response.resultCode isEqualToEnum:SDLResultSuccess]) {
+ SDLLogE(@"Error opening application menu: %@", error);
+ } else {
+ SDLLogD(@"Successfully opened application main menu");
+ }
+ }];
+
+ return YES;
+}
+
+- (BOOL)openSubmenu:(SDLMenuCell *)cell {
+ if (cell.subCells.count == 0) {
+ SDLLogE(@"The cell %@ does not contain any sub cells, so no submenu can be opened", cell);
+ return NO;
+ } else if ([SDLGlobals.sharedGlobals.rpcVersion isLessThanVersion:[[SDLVersion alloc] initWithMajor:6 minor:0 patch:0]]) {
+ SDLLogE(@"The openSubmenu method is not supported on this head unit.");
+ return NO;
+ } else if (![self.menuCells containsObject:cell]) {
+ SDLLogE(@"This cell has not been sent to the head unit, so no submenu can be opened. Make sure that the cell exists in the SDLManager.menu array");
+ return NO;
+ }
+
+ SDLShowAppMenu *subMenu = [[SDLShowAppMenu alloc] initWithMenuID:cell.cellId];
+
+ [self.connectionManager sendConnectionRequest:subMenu withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if ([response.resultCode isEqualToEnum:SDLResultWarnings]) {
+ SDLLogW(@"Warning opening application menu to submenu cell %@, with error: %@", cell, error);
+ } else if (![response.resultCode isEqualToEnum:SDLResultSuccess]) {
+ SDLLogE(@"Error opening application menu to submenu cell %@, with error: %@", cell, error);
+ } else {
+ SDLLogD(@"Successfully opened application menu to submenu cell: %@", cell);
+ }
+ }];
+
+ return YES;
+}
+
#pragma mark - Build Deletes, Keeps, Adds
- (void)sdl_startSubMenuUpdatesWithOldKeptCells:(NSArray<SDLMenuCell *> *)oldKeptCells newKeptCells:(NSArray<SDLMenuCell *> *)newKeptCells atIndex:(NSUInteger)startIndex {
@@ -672,46 +722,6 @@ UInt32 const MenuCellIdMin = 1;
}
}
-- (BOOL)openMenu {
- if ([SDLGlobals.sharedGlobals.rpcVersion isLessThanVersion:[[SDLVersion alloc] initWithMajor:6 minor:0 patch:0]]) {
- SDLLogE(@"The openMenu method is not supported on this head unit.");
- return NO;
- }
-
- SDLShowAppMenu *openMenu = [[SDLShowAppMenu alloc] init];
-
- [self.connectionManager sendConnectionRequest:openMenu withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
- if (error != nil) {
- SDLLogE(@"Error opening application menu: %@", error);
- }
- }];
-
- return YES;
-}
-
-- (BOOL)openSubmenu:(SDLMenuCell *)cell {
- if (cell.subCells.count == 0) {
- SDLLogE(@"The cell %@ does not contain any sub cells, so no submenu can be opened", cell);
- return NO;
- } else if ([SDLGlobals.sharedGlobals.rpcVersion isLessThanVersion:[[SDLVersion alloc] initWithMajor:6 minor:0 patch:0]]) {
- SDLLogE(@"The openSubmenu method is not supported on this head unit.");
- return NO;
- } else if (![self.menuCells containsObject:cell]) {
- SDLLogE(@"This cell has not been sent to the head unit, so no submenu can be opened. Make sure that the cell exists in the SDLManager.menu array");
- return NO;
- }
-
- SDLShowAppMenu *subMenu = [[SDLShowAppMenu alloc] initWithMenuID:cell.cellId];
-
- [self.connectionManager sendConnectionRequest:subMenu withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
- if (error != nil) {
- SDLLogE(@"Error opening application to submenu cell: %@, with error: %@", cell, error);
- }
- }];
-
- return YES;
-}
-
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLOnHMIStatus.h b/SmartDeviceLink/SDLOnHMIStatus.h
index 232f85d96..22a43500a 100644
--- a/SmartDeviceLink/SDLOnHMIStatus.h
+++ b/SmartDeviceLink/SDLOnHMIStatus.h
@@ -51,6 +51,14 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (strong, nonatomic, nullable) NSNumber<SDLUInt> *windowID;
+/// Initialize an SDLOnHMIStatus RPC with initial parameters
+/// @param hmiLevel The HMI level
+/// @param systemContext The system context
+/// @param audioStreamingState The ability for an audio app to be heard
+/// @param videoStreamingState The ability for a video straming app to stream
+/// @param windowID Which window this status relates to
+- (instancetype)initWithHMILevel:(SDLHMILevel)hmiLevel systemContext:(SDLSystemContext)systemContext audioStreamingState:(SDLAudioStreamingState)audioStreamingState videoStreamingState:(nullable SDLVideoStreamingState)videoStreamingState windowID:(nullable NSNumber<SDLUInt> *)windowID;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLOnHMIStatus.m b/SmartDeviceLink/SDLOnHMIStatus.m
index f80b4b4fb..09534e9fa 100644
--- a/SmartDeviceLink/SDLOnHMIStatus.m
+++ b/SmartDeviceLink/SDLOnHMIStatus.m
@@ -23,6 +23,19 @@ NS_ASSUME_NONNULL_BEGIN
}
#pragma clang diagnostic pop
+- (instancetype)initWithHMILevel:(SDLHMILevel)hmiLevel systemContext:(SDLSystemContext)systemContext audioStreamingState:(SDLAudioStreamingState)audioStreamingState videoStreamingState:(nullable SDLVideoStreamingState)videoStreamingState windowID:(nullable NSNumber<SDLUInt> *)windowID {
+ self = [self init];
+ if (!self) { return nil; }
+
+ self.hmiLevel = hmiLevel;
+ self.systemContext = systemContext;
+ self.audioStreamingState = audioStreamingState;
+ self.videoStreamingState = videoStreamingState;
+ self.windowID = windowID;
+
+ return self;
+}
+
- (void)setHmiLevel:(SDLHMILevel)hmiLevel {
[self.parameters sdl_setObject:hmiLevel forName:SDLRPCParameterNameHMILevel];
}
diff --git a/SmartDeviceLink/SDLPreloadChoicesOperation.h b/SmartDeviceLink/SDLPreloadChoicesOperation.h
index b62ff5296..965a0c176 100644
--- a/SmartDeviceLink/SDLPreloadChoicesOperation.h
+++ b/SmartDeviceLink/SDLPreloadChoicesOperation.h
@@ -29,7 +29,7 @@ typedef NS_ENUM(NSUInteger, SDLPreloadChoicesOperationState) {
@property (assign, nonatomic) SDLPreloadChoicesOperationState currentState;
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager displayName:(NSString *)displayName defaultMainWindowCapability:(SDLWindowCapability *)defaultMainWindowCapability isVROptional:(BOOL)isVROptional cellsToPreload:(NSSet<SDLChoiceCell *> *)cells;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager displayName:(NSString *)displayName windowCapability:(SDLWindowCapability *)defaultMainWindowCapability isVROptional:(BOOL)isVROptional cellsToPreload:(NSSet<SDLChoiceCell *> *)cells;
- (BOOL)removeChoicesFromUpload:(NSSet<SDLChoiceCell *> *)choices;
diff --git a/SmartDeviceLink/SDLPreloadChoicesOperation.m b/SmartDeviceLink/SDLPreloadChoicesOperation.m
index ddb0e36c8..d812ed525 100644
--- a/SmartDeviceLink/SDLPreloadChoicesOperation.m
+++ b/SmartDeviceLink/SDLPreloadChoicesOperation.m
@@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) NSUUID *operationId;
@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *cellsToUpload;
-@property (strong, nonatomic) SDLWindowCapability *defaultMainWindowCapability;
+@property (strong, nonatomic) SDLWindowCapability *windowCapability;
@property (strong, nonatomic) NSString *displayName;
@property (assign, nonatomic, getter=isVROptional) BOOL vrOptional;
@@ -45,14 +45,14 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLPreloadChoicesOperation
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager displayName:(NSString *)displayName defaultMainWindowCapability:(SDLWindowCapability *)defaultMainWindowCapability isVROptional:(BOOL)isVROptional cellsToPreload:(NSSet<SDLChoiceCell *> *)cells {
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager displayName:(NSString *)displayName windowCapability:(SDLWindowCapability *)defaultMainWindowCapability isVROptional:(BOOL)isVROptional cellsToPreload:(NSSet<SDLChoiceCell *> *)cells {
self = [super init];
if (!self) { return nil; }
_connectionManager = connectionManager;
_fileManager = fileManager;
_displayName = displayName;
- _defaultMainWindowCapability = defaultMainWindowCapability;
+ _windowCapability = defaultMainWindowCapability;
_vrOptional = isVROptional;
_cellsToUpload = [cells mutableCopy];
_operationId = [NSUUID UUID];
@@ -87,11 +87,11 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray<SDLArtwork *> *artworksToUpload = [NSMutableArray arrayWithCapacity:self.cellsToUpload.count];
for (SDLChoiceCell *cell in self.cellsToUpload) {
- if ([self.defaultMainWindowCapability hasImageFieldOfName:SDLImageFieldNameChoiceImage]
+ if ([self.windowCapability hasImageFieldOfName:SDLImageFieldNameChoiceImage]
&& [self sdl_artworkNeedsUpload:cell.artwork]) {
[artworksToUpload addObject:cell.artwork];
}
- if ([self.defaultMainWindowCapability hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage]
+ if ([self.windowCapability hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage]
&& [self sdl_artworkNeedsUpload:cell.secondaryArtwork]) {
[artworksToUpload addObject:cell.secondaryArtwork];
}
@@ -165,29 +165,53 @@ NS_ASSUME_NONNULL_BEGIN
}
NSString *menuName = nil;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- if ([self.displayName isEqualToString:SDLDisplayTypeGen38Inch] || [self.defaultMainWindowCapability hasTextFieldOfName:SDLTextFieldNameMenuName]) {
+ if ([self sdl_shouldSendChoiceText]) {
menuName = cell.text;
}
-#pragma clang diagnostic pop
if(!menuName) {
SDLLogE(@"Could not convert SDLChoiceCell to SDLCreateInteractionChoiceSet. It will not be shown. Cell: %@", cell);
return nil;
}
- NSString *secondaryText = [self.defaultMainWindowCapability hasTextFieldOfName:SDLTextFieldNameSecondaryText] ? cell.secondaryText : nil;
- NSString *tertiaryText = [self.defaultMainWindowCapability hasTextFieldOfName:SDLTextFieldNameTertiaryText] ? cell.tertiaryText : nil;
+ NSString *secondaryText = [self sdl_shouldSendChoiceSecondaryText] ? cell.secondaryText : nil;
+ NSString *tertiaryText = [self sdl_shouldSendChoiceTertiaryText] ? cell.tertiaryText : nil;
- SDLImage *image = ([self.defaultMainWindowCapability hasImageFieldOfName:SDLImageFieldNameChoiceImage] && cell.artwork != nil) ? cell.artwork.imageRPC : nil;
- SDLImage *secondaryImage = ([self.defaultMainWindowCapability hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage] && cell.secondaryArtwork != nil) ? cell.secondaryArtwork.imageRPC : nil;
+ SDLImage *image = [self sdl_shouldSendChoicePrimaryImage] ? cell.artwork.imageRPC : nil;
+ SDLImage *secondaryImage = [self sdl_shouldSendChoiceSecondaryImage] ? cell.secondaryArtwork.imageRPC : nil;
SDLChoice *choice = [[SDLChoice alloc] initWithId:cell.choiceId menuName:(NSString *_Nonnull)menuName vrCommands:(NSArray<NSString *> * _Nonnull)vrCommands image:image secondaryText:secondaryText secondaryImage:secondaryImage tertiaryText:tertiaryText];
return [[SDLCreateInteractionChoiceSet alloc] initWithId:(UInt32)choice.choiceID.unsignedIntValue choiceSet:@[choice]];
}
+- (BOOL)sdl_shouldSendChoiceText {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ if ([self.displayName isEqualToString:SDLDisplayTypeGen38Inch]) {
+ return YES;
+ }
+#pragma clang diagnostic pop
+
+ return (self.windowCapability.textFields != nil) ? [self.windowCapability hasTextFieldOfName:SDLTextFieldNameMenuName] : YES;
+}
+
+- (BOOL)sdl_shouldSendChoiceSecondaryText {
+ return (self.windowCapability.textFields != nil) ? [self.windowCapability hasTextFieldOfName:SDLTextFieldNameSecondaryText] : YES;
+}
+
+- (BOOL)sdl_shouldSendChoiceTertiaryText {
+ return (self.windowCapability.textFields != nil) ? [self.windowCapability hasTextFieldOfName:SDLTextFieldNameTertiaryText] : YES;
+}
+
+- (BOOL)sdl_shouldSendChoicePrimaryImage {
+ return (self.windowCapability.imageFields != nil) ? [self.windowCapability hasImageFieldOfName:SDLImageFieldNameChoiceImage] : YES;
+}
+
+- (BOOL)sdl_shouldSendChoiceSecondaryImage {
+ return (self.windowCapability.imageFields != nil) ? [self.windowCapability hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage] : YES;
+}
+
#pragma mark - Property Overrides
- (void)finishOperation {
diff --git a/SmartDeviceLink/SDLProxy.m b/SmartDeviceLink/SDLProxy.m
index d7d78fc83..9b48e54b0 100644
--- a/SmartDeviceLink/SDLProxy.m
+++ b/SmartDeviceLink/SDLProxy.m
@@ -65,7 +65,7 @@ static float DefaultConnectionTimeout = 45.0;
@property (strong, nonatomic) NSMutableSet<NSObject<SDLProxyListener> *> *mutableProxyListeners;
@property (nullable, nonatomic, strong) SDLDisplayCapabilities *displayCapabilities;
@property (nonatomic, strong) NSMutableDictionary<SDLVehicleMake *, Class> *securityManagers;
-@property (nonatomic, strong) NSURLSession* urlSession;
+@property (nonatomic, strong) NSURLSession *urlSession;
@end
@@ -189,17 +189,20 @@ static float DefaultConnectionTimeout = 45.0;
SDLLogV(@"Proxy dealloc");
}
-- (void)notifyProxyClosed {
+- (void)sdl_notifyProxyClosed {
if (_isConnected) {
_isConnected = NO;
- [self invokeMethodOnDelegates:@selector(onProxyClosed) withObject:nil];
+ [self sdl_invokeMethodOnDelegates:@selector(onProxyClosed) withObject:nil];
}
}
#pragma mark - Application Lifecycle
-- (void)sendMobileHMIState {
+/// This method sends an OnHMIStatus with the Mobile's HMI level to the head unit.
+/// This was originally designed to make sure that the head unit properly knew about the mobile app's ability to run timers in the background, which affected heartbeat.
+/// It may still affect some features on the head unit and the ability for the head unit to know which app is in the foreground is useful. It should not be removed due to unknown backward compatibility issues.
+- (void)sdl_sendMobileHMIState {
__block UIApplicationState appState = UIApplicationStateInactive;
if ([NSThread isMainThread]) {
appState = [UIApplication sharedApplication].applicationState;
@@ -268,7 +271,7 @@ static float DefaultConnectionTimeout = 45.0;
}
}
-- (nullable id<SDLSecurityType>)securityManagerForMake:(NSString *)make {
+- (nullable id<SDLSecurityType>)sdl_securityManagerForMake:(NSString *)make {
if ((make != nil) && (self.securityManagers[make] != nil)) {
Class securityManagerClass = self.securityManagers[make];
self.protocol.appId = self.appId;
@@ -292,22 +295,22 @@ static float DefaultConnectionTimeout = 45.0;
__weak typeof(self) weakSelf = self;
self.startSessionTimer.elapsedBlock = ^{
SDLLogW(@"Start session timed out");
- [weakSelf performSelector:@selector(notifyProxyClosed) withObject:nil afterDelay:NotifyProxyClosedDelay];
+ [weakSelf performSelector:@selector(sdl_notifyProxyClosed) withObject:nil afterDelay:NotifyProxyClosedDelay];
};
}
[self.startSessionTimer start];
}
- (void)onProtocolClosed {
- [self notifyProxyClosed];
+ [self sdl_notifyProxyClosed];
}
- (void)onError:(NSString *)info exception:(NSException *)e {
- [self invokeMethodOnDelegates:@selector(onError:) withObject:e];
+ [self sdl_invokeMethodOnDelegates:@selector(onError:) withObject:e];
}
- (void)onTransportError:(NSError *)error {
- [self invokeMethodOnDelegates:@selector(onTransportError:) withObject:error];
+ [self sdl_invokeMethodOnDelegates:@selector(onTransportError:) withObject:error];
}
- (void)handleProtocolStartServiceACKMessage:(SDLProtocolMessage *)startServiceACK {
@@ -316,7 +319,7 @@ static float DefaultConnectionTimeout = 45.0;
SDLLogV(@"StartSession (response)\nSessionId: %d for serviceType %d", startServiceACK.header.sessionID, startServiceACK.header.serviceType);
if (startServiceACK.header.serviceType == SDLServiceTypeRPC) {
- [self invokeMethodOnDelegates:@selector(onProxyOpened) withObject:nil];
+ [self sdl_invokeMethodOnDelegates:@selector(onProxyOpened) withObject:nil];
}
}
@@ -461,15 +464,15 @@ static float DefaultConnectionTimeout = 45.0;
}
if ([functionName isEqualToString:@"OnEncodedSyncPData"]) {
- [self handleSyncPData:newMessage];
+ [self sdl_handleSyncPData:newMessage];
}
if ([functionName isEqualToString:@"OnSystemRequest"]) {
- [self handleSystemRequest:dict];
+ [self sdl_handleSystemRequest:dict];
}
if ([functionName isEqualToString:@"SystemRequestResponse"]) {
- [self handleSystemRequestResponse:newMessage];
+ [self sdl_handleSystemRequestResponse:newMessage];
}
@@ -499,17 +502,17 @@ static float DefaultConnectionTimeout = 45.0;
//Intercepting SDLRPCFunctionNameOnAppInterfaceUnregistered must happen after it is broadcasted as a notification above. This will prevent reconnection attempts in the lifecycle manager when the AppInterfaceUnregisteredReason should prevent reconnections.
if ([functionName isEqualToString:SDLRPCFunctionNameOnAppInterfaceUnregistered] || [functionName isEqualToString:SDLRPCFunctionNameUnregisterAppInterface]) {
- [self handleRPCUnregistered:dict];
+ [self sdl_handleRPCUnregistered:dict];
}
// When an OnHMIStatus notification comes in, after passing it on (above), generate an "OnLockScreenNotification"
if ([functionName isEqualToString:@"OnHMIStatus"]) {
- [self handleAfterHMIStatus:newMessage];
+ [self sdl_handleAfterHMIStatus:newMessage];
}
// When an OnDriverDistraction notification comes in, after passing it on (above), generate an "OnLockScreenNotification"
if ([functionName isEqualToString:@"OnDriverDistraction"]) {
- [self handleAfterDriverDistraction:newMessage];
+ [self sdl_handleAfterDriverDistraction:newMessage];
}
}
@@ -517,34 +520,34 @@ static float DefaultConnectionTimeout = 45.0;
// Formulate the name of the method to call and invoke the method on the delegate(s)
NSString *handlerName = [NSString stringWithFormat:@"on%@:", functionName];
SEL handlerSelector = NSSelectorFromString(handlerName);
- [self invokeMethodOnDelegates:handlerSelector withObject:message];
+ [self sdl_invokeMethodOnDelegates:handlerSelector withObject:message];
}
#pragma mark - RPC Handlers
-- (void)handleRPCUnregistered:(NSDictionary<NSString *, id> *)messageDictionary {
+- (void)sdl_handleRPCUnregistered:(NSDictionary<NSString *, id> *)messageDictionary {
SDLLogW(@"Unregistration forced by module. %@", messageDictionary);
- [self notifyProxyClosed];
+ [self sdl_notifyProxyClosed];
}
- (void)handleRegisterAppInterfaceResponse:(SDLRPCResponse *)response {
SDLRegisterAppInterfaceResponse *registerResponse = (SDLRegisterAppInterfaceResponse *)response;
- self.protocol.securityManager = [self securityManagerForMake:registerResponse.vehicleType.make];
+ self.protocol.securityManager = [self sdl_securityManagerForMake:registerResponse.vehicleType.make];
if (self.protocol.securityManager && [self.protocol.securityManager respondsToSelector:@selector(setAppId:)]) {
self.protocol.securityManager.appId = self.appId;
}
if ([SDLGlobals sharedGlobals].protocolVersion.major >= 4) {
- [self sendMobileHMIState];
+ [self sdl_sendMobileHMIState];
// Send SDL updates to application state
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationDidBecomeActiveNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationDidEnterBackgroundNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_sendMobileHMIState) name:UIApplicationDidBecomeActiveNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_sendMobileHMIState) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
}
-- (void)handleSyncPData:(SDLRPCMessage *)message {
+- (void)sdl_handleSyncPData:(SDLRPCMessage *)message {
// If URL != nil, perform HTTP Post and don't pass the notification to proxy listeners
SDLLogV(@"OnEncodedSyncPData: %@", message);
@@ -553,11 +556,11 @@ static float DefaultConnectionTimeout = 45.0;
NSNumber *encodedSyncPTimeout = (NSNumber *)message.parameters[SDLRPCParameterNameTimeoutCapitalized];
if (urlString && encodedSyncPData && encodedSyncPTimeout) {
- [self sendEncodedSyncPData:encodedSyncPData toURL:urlString withTimeout:encodedSyncPTimeout];
+ [self sdl_sendEncodedSyncPData:encodedSyncPData toURL:urlString withTimeout:encodedSyncPTimeout];
}
}
-- (void)handleSystemRequest:(NSDictionary<NSString *, id> *)dict {
+- (void)sdl_handleSystemRequest:(NSDictionary<NSString *, id> *)dict {
SDLLogV(@"OnSystemRequest");
#pragma clang diagnostic push
@@ -568,7 +571,7 @@ static float DefaultConnectionTimeout = 45.0;
// Handle the various OnSystemRequest types
if ([requestType isEqualToEnum:SDLRequestTypeProprietary]) {
- [self handleSystemRequestProprietary:systemRequest];
+ [self sdl_handleSystemRequestProprietary:systemRequest];
} else if ([requestType isEqualToEnum:SDLRequestTypeLockScreenIconURL]) {
[self sdl_handleSystemRequestLockScreenIconURL:systemRequest];
} else if ([requestType isEqualToEnum:SDLRequestTypeIconURL]) {
@@ -580,7 +583,7 @@ static float DefaultConnectionTimeout = 45.0;
}
}
-- (void)handleSystemRequestResponse:(SDLRPCMessage *)message {
+- (void)sdl_handleSystemRequestResponse:(SDLRPCMessage *)message {
SDLLogV(@"SystemRequestResponse to be discarded");
}
@@ -669,21 +672,21 @@ static float DefaultConnectionTimeout = 45.0;
#pragma mark Handle Post-Invoke of Delegate Methods
-- (void)handleAfterHMIStatus:(SDLRPCMessage *)message {
+- (void)sdl_handleAfterHMIStatus:(SDLRPCMessage *)message {
SDLHMILevel hmiLevel = (SDLHMILevel)message.parameters[SDLRPCParameterNameHMILevel];
_lsm.hmiLevel = hmiLevel;
SEL callbackSelector = NSSelectorFromString(@"onOnLockScreenNotification:");
- [self invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification];
+ [self sdl_invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification];
}
-- (void)handleAfterDriverDistraction:(SDLRPCMessage *)message {
+- (void)sdl_handleAfterDriverDistraction:(SDLRPCMessage *)message {
NSString *stateString = (NSString *)message.parameters[SDLRPCParameterNameState];
BOOL state = [stateString isEqualToString:@"DD_ON"] ? YES : NO;
_lsm.driverDistracted = state;
SEL callbackSelector = NSSelectorFromString(@"onOnLockScreenNotification:");
- [self invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification];
+ [self sdl_invokeMethodOnDelegates:callbackSelector withObject:_lsm.lockScreenStatusNotification];
}
@@ -704,8 +707,8 @@ static float DefaultConnectionTimeout = 45.0;
[[UIApplication sharedApplication] openURL:URLScheme];
}
-- (void)handleSystemRequestProprietary:(SDLOnSystemRequest *)request {
- NSDictionary<NSString *, id> *JSONDictionary = [self validateAndParseSystemRequest:request];
+- (void)sdl_handleSystemRequestProprietary:(SDLOnSystemRequest *)request {
+ NSDictionary<NSString *, id> *JSONDictionary = [self sdl_validateAndParseSystemRequest:request];
if (JSONDictionary == nil || request.url == nil) {
return;
}
@@ -724,8 +727,8 @@ static float DefaultConnectionTimeout = 45.0;
// Send the HTTP Request
__weak typeof(self) weakSelf = self;
- [self uploadForBodyDataDictionary:JSONDictionary
- URLString:request.url
+ [self sdl_uploadForBodyDataDictionary:JSONDictionary
+ urlString:request.url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
@@ -770,7 +773,7 @@ static float DefaultConnectionTimeout = 45.0;
}
UIImage *icon = [UIImage imageWithData:data];
- [strongSelf invokeMethodOnDelegates:@selector(onReceivedLockScreenIcon:) withObject:icon];
+ [strongSelf sdl_invokeMethodOnDelegates:@selector(onReceivedLockScreenIcon:) withObject:icon];
}];
}
@@ -837,7 +840,7 @@ static float DefaultConnectionTimeout = 45.0;
*
* @return A parsed JSON dictionary, or nil if it couldn't be parsed
*/
-- (nullable NSDictionary<NSString *, id> *)validateAndParseSystemRequest:(SDLOnSystemRequest *)request {
+- (nullable NSDictionary<NSString *, id> *)sdl_validateAndParseSystemRequest:(SDLOnSystemRequest *)request {
NSString *urlString = request.url;
SDLFileType fileType = request.fileType;
@@ -890,7 +893,7 @@ static float DefaultConnectionTimeout = 45.0;
* @param urlString A string containing the URL to send the upload to
* @param completionHandler A completion handler returning the response from the server to the upload task
*/
-- (void)uploadForBodyDataDictionary:(NSDictionary<NSString *, id> *)dictionary URLString:(NSString *)urlString completionHandler:(URLSessionTaskCompletionHandler)completionHandler {
+- (void)sdl_uploadForBodyDataDictionary:(NSDictionary<NSString *, id> *)dictionary urlString:(NSString *)urlString completionHandler:(URLSessionTaskCompletionHandler)completionHandler {
NSParameterAssert(dictionary != nil);
NSParameterAssert(urlString != nil);
NSParameterAssert(completionHandler != NULL);
@@ -949,7 +952,7 @@ static float DefaultConnectionTimeout = 45.0;
}
}
-- (void)invokeMethodOnDelegates:(SEL)aSelector withObject:(nullable id)object {
+- (void)sdl_invokeMethodOnDelegates:(SEL)aSelector withObject:(nullable id)object {
// Occurs on the processing serial queue
for (id<SDLProxyListener> listener in self.proxyListeners) {
if ([listener respondsToSelector:aSelector]) {
@@ -962,7 +965,7 @@ static float DefaultConnectionTimeout = 45.0;
#pragma mark - System Request and SyncP handling
-- (void)sendEncodedSyncPData:(NSDictionary<NSString *, id> *)encodedSyncPData toURL:(NSString *)urlString withTimeout:(NSNumber *)timeout {
+- (void)sdl_sendEncodedSyncPData:(NSDictionary<NSString *, id> *)encodedSyncPData toURL:(NSString *)urlString withTimeout:(NSNumber *)timeout {
// Configure HTTP URL & Request
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
@@ -986,14 +989,14 @@ static float DefaultConnectionTimeout = 45.0;
[[self.urlSession uploadTaskWithRequest:request
fromData:data
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
- [weakSelf syncPDataNetworkRequestCompleteWithData:data response:response error:error];
+ [weakSelf sdl_syncPDataNetworkRequestCompleteWithData:data response:response error:error];
}] resume];
SDLLogV(@"OnEncodedSyncPData (HTTP Request)");
}
// Handle the OnEncodedSyncPData HTTP Response
-- (void)syncPDataNetworkRequestCompleteWithData:(NSData *)data response:(NSURLResponse *)response error:(NSError *)error {
+- (void)sdl_syncPDataNetworkRequestCompleteWithData:(NSData *)data response:(NSURLResponse *)response error:(NSError *)error {
// Sample of response: {"data":["SDLKGLSDKFJLKSjdslkfjslkJLKDSGLKSDJFLKSDJF"]}
SDLLogV(@"OnEncodedSyncPData (HTTP Response): %@", response);
diff --git a/SmartDeviceLink/SDLSoftButtonManager.m b/SmartDeviceLink/SDLSoftButtonManager.m
index a8dd84629..01a8d0c05 100644
--- a/SmartDeviceLink/SDLSoftButtonManager.m
+++ b/SmartDeviceLink/SDLSoftButtonManager.m
@@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) NSOperationQueue *transactionQueue;
-@property (strong, nonatomic, nullable) SDLWindowCapability *windowCapability;
+@property (strong, nonatomic, nullable) SDLSoftButtonCapabilities *softButtonCapabilities;
@property (copy, nonatomic, nullable) SDLHMILevel currentLevel;
@property (strong, nonatomic) NSMutableArray<SDLAsynchronousOperation *> *batchQueue;
@@ -82,7 +82,7 @@ NS_ASSUME_NONNULL_BEGIN
_softButtonObjects = @[];
_currentMainField1 = nil;
_currentLevel = nil;
- _windowCapability = nil;
+ _softButtonCapabilities = nil;
[_transactionQueue cancelAllOperations];
self.transactionQueue = [self sdl_newTransactionQueue];
@@ -100,12 +100,25 @@ NS_ASSUME_NONNULL_BEGIN
return queue;
}
+/// Suspend the queue if the soft button capabilities are nil (we assume that soft buttons are not supported)
+/// OR if the HMI level is NONE since we want to delay sending RPCs until we're in non-NONE
+- (void)sdl_updateTransactionQueueSuspended {
+ if (self.softButtonCapabilities == nil || [self.currentLevel isEqualToEnum:SDLHMILevelNone]) {
+ SDLLogD(@"Suspending the transaction queue. Current HMI level is NONE: %@, soft button capabilities are nil: %@", ([self.currentLevel isEqualToEnum:SDLHMILevelNone] ? @"YES" : @"NO"), (self.softButtonCapabilities == nil ? @"YES" : @"NO"));
+ self.transactionQueue.suspended = YES;
+ } else {
+ SDLLogD(@"Starting the transaction queue");
+ self.transactionQueue.suspended = NO;
+ }
+}
+
#pragma mark - Sending Soft Buttons
- (void)setSoftButtonObjects:(NSArray<SDLSoftButtonObject *> *)softButtonObjects {
// Only update if something changed. This prevents, for example, an empty array being reset
if (_softButtonObjects == softButtonObjects) {
+ SDLLogD(@"New soft button objects are equivalent to existing soft button objects, skipping...");
return;
}
@@ -128,7 +141,8 @@ NS_ASSUME_NONNULL_BEGIN
_softButtonObjects = softButtonObjects;
- SDLSoftButtonReplaceOperation *op = [[SDLSoftButtonReplaceOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager capabilities:self.windowCapability.softButtonCapabilities.firstObject softButtonObjects:_softButtonObjects mainField1:self.currentMainField1];
+ // We only need to pass the first `softButtonCapabilities` in the array due to the fact that all soft button capabilities are the same (i.e. there is no way to assign a `softButtonCapabilities` to a specific soft button).
+ SDLSoftButtonReplaceOperation *op = [[SDLSoftButtonReplaceOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager capabilities:self.softButtonCapabilities softButtonObjects:_softButtonObjects mainField1:self.currentMainField1];
if (self.isBatchingUpdates) {
[self.batchQueue removeAllObjects];
@@ -140,7 +154,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)sdl_transitionSoftButton:(SDLSoftButtonObject *)softButton {
- SDLSoftButtonTransitionOperation *op = [[SDLSoftButtonTransitionOperation alloc] initWithConnectionManager:self.connectionManager capabilities:self.windowCapability.softButtonCapabilities.firstObject softButtons:self.softButtonObjects mainField1:self.currentMainField1];
+ SDLSoftButtonTransitionOperation *op = [[SDLSoftButtonTransitionOperation alloc] initWithConnectionManager:self.connectionManager capabilities:self.softButtonCapabilities softButtons:self.softButtonObjects mainField1:self.currentMainField1];
if (self.isBatchingUpdates) {
for (SDLAsynchronousOperation *sbOperation in self.batchQueue) {
@@ -194,15 +208,34 @@ NS_ASSUME_NONNULL_BEGIN
}
}
-
-#pragma mark - RPC Responses
+#pragma mark - Observers
- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability {
- self.windowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
+ SDLSoftButtonCapabilities *oldCapabilities = self.softButtonCapabilities;
- // Auto-send an updated Show to account for changes to the capabilities
- if (self.softButtonObjects.count > 0) {
- SDLSoftButtonReplaceOperation *op = [[SDLSoftButtonReplaceOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager capabilities:self.windowCapability.softButtonCapabilities.firstObject softButtonObjects:self.softButtonObjects mainField1:self.currentMainField1];
+ // Extract and update the capabilities
+ NSArray<SDLDisplayCapability *> *capabilities = systemCapability.displayCapabilities;
+ if (capabilities == nil || capabilities.count == 0) {
+ self.softButtonCapabilities = nil;
+ } else {
+ SDLDisplayCapability *mainDisplay = capabilities[0];
+ for (SDLWindowCapability *windowCapability in mainDisplay.windowCapabilities) {
+ NSUInteger currentWindowID = windowCapability.windowID != nil ? windowCapability.windowID.unsignedIntegerValue : SDLPredefinedWindowsDefaultWindow;
+ if (currentWindowID != SDLPredefinedWindowsDefaultWindow) { continue; }
+
+ self.softButtonCapabilities = windowCapability.softButtonCapabilities.firstObject;
+ break;
+ }
+ }
+
+ // Update the queue's suspend state
+ [self sdl_updateTransactionQueueSuspended];
+
+ // Auto-send an updated Show if we have new capabilities
+ if (self.softButtonObjects.count > 0
+ && self.softButtonCapabilities != nil
+ && ![self.softButtonCapabilities isEqual:oldCapabilities]) {
+ SDLSoftButtonReplaceOperation *op = [[SDLSoftButtonReplaceOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager capabilities:self.softButtonCapabilities softButtonObjects:self.softButtonObjects mainField1:self.currentMainField1];
[self.transactionQueue addOperation:op];
}
}
@@ -213,17 +246,10 @@ NS_ASSUME_NONNULL_BEGIN
if (hmiStatus.windowID != nil && hmiStatus.windowID.integerValue != SDLPredefinedWindowsDefaultWindow) {
return;
}
-
- SDLHMILevel oldHMILevel = self.currentLevel;
- if (![oldHMILevel isEqualToEnum:hmiStatus.hmiLevel]) {
- if ([hmiStatus.hmiLevel isEqualToEnum:SDLHMILevelNone]) {
- self.transactionQueue.suspended = YES;
- } else {
- self.transactionQueue.suspended = NO;
- }
- }
self.currentLevel = hmiStatus.hmiLevel;
+
+ [self sdl_updateTransactionQueueSuspended];
}
@end
diff --git a/SmartDeviceLink/SDLSoftButtonReplaceOperation.h b/SmartDeviceLink/SDLSoftButtonReplaceOperation.h
index 9adb5afb4..f7a66b331 100644
--- a/SmartDeviceLink/SDLSoftButtonReplaceOperation.h
+++ b/SmartDeviceLink/SDLSoftButtonReplaceOperation.h
@@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
@param mainField1 The primary text field of the system template
@return The operation
*/
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager capabilities:(SDLSoftButtonCapabilities *)capabilities softButtonObjects:(NSArray<SDLSoftButtonObject *> *)softButtonObjects mainField1:(NSString *)mainField1;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager capabilities:(nullable SDLSoftButtonCapabilities *)capabilities softButtonObjects:(NSArray<SDLSoftButtonObject *> *)softButtonObjects mainField1:(NSString *)mainField1;
@end
diff --git a/SmartDeviceLink/SDLSoftButtonReplaceOperation.m b/SmartDeviceLink/SDLSoftButtonReplaceOperation.m
index 0275dc4ff..91191f3b0 100644
--- a/SmartDeviceLink/SDLSoftButtonReplaceOperation.m
+++ b/SmartDeviceLink/SDLSoftButtonReplaceOperation.m
@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLSoftButtonReplaceOperation ()
-@property (strong, nonatomic) SDLSoftButtonCapabilities *softButtonCapabilities;
+@property (strong, nonatomic, nullable) SDLSoftButtonCapabilities *softButtonCapabilities;
@property (strong, nonatomic) NSArray<SDLSoftButtonObject *> *softButtonObjects;
@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
@@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLSoftButtonReplaceOperation
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager capabilities:(SDLSoftButtonCapabilities *)capabilities softButtonObjects:(NSArray<SDLSoftButtonObject *> *)softButtonObjects mainField1:(NSString *)mainField1 {
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager capabilities:(nullable SDLSoftButtonCapabilities *)capabilities softButtonObjects:(NSArray<SDLSoftButtonObject *> *)softButtonObjects mainField1:(NSString *)mainField1 {
self = [super init];
if (!self) { return nil; }
@@ -273,7 +273,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (BOOL)sdl_supportsSoftButtonImages {
- return self.softButtonCapabilities ? self.softButtonCapabilities.imageSupported.boolValue : NO;
+ return self.softButtonCapabilities.imageSupported.boolValue;
}
#pragma mark - Property Overrides
diff --git a/SmartDeviceLink/SDLSystemCapabilityManager.m b/SmartDeviceLink/SDLSystemCapabilityManager.m
index d248da7ec..ea1dee9b5 100644
--- a/SmartDeviceLink/SDLSystemCapabilityManager.m
+++ b/SmartDeviceLink/SDLSystemCapabilityManager.m
@@ -779,7 +779,6 @@ typedef NSString * SDLServiceID;
[self sdl_callObserversForUpdate:systemCapability error:nil handler:nil];
}
-
/**
* Called when an `OnSystemCapabilityUpdated` notification is received from Core. The updated system capabilty is saved.
*
diff --git a/SmartDeviceLink/SDLTextAndGraphicManager.m b/SmartDeviceLink/SDLTextAndGraphicManager.m
index 0e484176f..2d04f74ed 100644
--- a/SmartDeviceLink/SDLTextAndGraphicManager.m
+++ b/SmartDeviceLink/SDLTextAndGraphicManager.m
@@ -286,13 +286,13 @@ NS_ASSUME_NONNULL_BEGIN
- (SDLShow *)sdl_assembleShowText:(SDLShow *)show {
[self sdl_setBlankTextFieldsWithShow:show];
- if (self.mediaTrackTextField != nil) {
+ if (self.mediaTrackTextField != nil && [self sdl_shouldUpdateMediaTextField]) {
show.mediaTrack = self.mediaTrackTextField;
} else {
show.mediaTrack = @"";
}
- if (self.title != nil) {
+ if (self.title != nil && [self sdl_shouldUpdateTitleField]) {
show.templateTitle = self.title;
} else {
show.templateTitle = @"";
@@ -301,7 +301,7 @@ NS_ASSUME_NONNULL_BEGIN
NSArray *nonNilFields = [self sdl_findNonNilTextFields];
if (nonNilFields.count == 0) { return show; }
- NSUInteger numberOfLines = self.windowCapability ? self.windowCapability.maxNumberOfMainFieldLines : 4;
+ NSUInteger numberOfLines = (self.windowCapability.textFields != nil) ? self.windowCapability.maxNumberOfMainFieldLines : 4;
if (numberOfLines == 1) {
show = [self sdl_assembleOneLineShowText:show withShowFields:nonNilFields];
} else if (numberOfLines == 2) {
@@ -512,7 +512,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (BOOL)sdl_shouldUpdatePrimaryImage {
- BOOL templateSupportsPrimaryArtwork = self.windowCapability ? [self.windowCapability hasImageFieldOfName:SDLImageFieldNameGraphic] : YES;
+ BOOL templateSupportsPrimaryArtwork = (self.windowCapability.imageFields != nil) ? [self.windowCapability hasImageFieldOfName:SDLImageFieldNameGraphic] : YES;
return (templateSupportsPrimaryArtwork
&& ![self.currentScreenData.graphic.value isEqualToString:self.primaryGraphic.name]
@@ -520,7 +520,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (BOOL)sdl_shouldUpdateSecondaryImage {
- BOOL templateSupportsSecondaryArtwork = self.windowCapability ? ([self.windowCapability hasImageFieldOfName:SDLImageFieldNameGraphic] || [self.windowCapability hasImageFieldOfName:SDLImageFieldNameSecondaryGraphic]) : YES;
+ BOOL templateSupportsSecondaryArtwork = (self.windowCapability.imageFields != nil) ? ([self.windowCapability hasImageFieldOfName:SDLImageFieldNameGraphic] || [self.windowCapability hasImageFieldOfName:SDLImageFieldNameSecondaryGraphic]) : YES;
// Cannot detect if there is a secondary image, so we'll just try to detect if there's a primary image and allow it if there is.
return (templateSupportsSecondaryArtwork
@@ -528,6 +528,14 @@ NS_ASSUME_NONNULL_BEGIN
&& self.secondaryGraphic != nil);
}
+- (BOOL)sdl_shouldUpdateMediaTextField {
+ return (self.windowCapability.textFields != nil) ? [self.windowCapability hasTextFieldOfName:SDLTextFieldNameMediaTrack] : YES;
+}
+
+- (BOOL)sdl_shouldUpdateTitleField {
+ return (self.windowCapability.textFields != nil) ? [self.windowCapability hasTextFieldOfName:SDLTextFieldNameTemplateTitle] : YES;
+}
+
- (NSArray<NSString *> *)sdl_findNonNilTextFields {
NSMutableArray *array = [NSMutableArray array];
self.textField1.length > 0 ? [array addObject:self.textField1] : nil;
@@ -549,7 +557,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (BOOL)sdl_hasData {
- BOOL hasTextFields = ([self sdl_findNonNilTextFields].count > 0);
+ BOOL hasTextFields = ([self sdl_findNonNilTextFields].count > 0) || (self.title.length > 0) || (self.mediaTrackTextField.length > 0);
BOOL hasImageFields = (self.primaryGraphic != nil) || (self.secondaryGraphic != nil);
return hasTextFields || hasImageFields;
diff --git a/SmartDeviceLink/SDLTextField.h b/SmartDeviceLink/SDLTextField.h
index aebfb61c5..d1dcedb1d 100644
--- a/SmartDeviceLink/SDLTextField.h
+++ b/SmartDeviceLink/SDLTextField.h
@@ -48,6 +48,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (strong, nonatomic) NSNumber<SDLInt> *rows;
+/// Convenience initalizer for the TextField RPC struct
+/// @param name The name identifying this text field
+/// @param characterSet The character set of this text field
+/// @param width The number of characters per row allowed in this text field
+/// @param rows The number of rows allowed in this text field
+- (instancetype)initWithName:(SDLTextFieldName)name characterSet:(SDLCharacterSet)characterSet width:(NSUInteger)width rows:(NSUInteger)rows;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLTextField.m b/SmartDeviceLink/SDLTextField.m
index cc50aa743..80941cc5f 100644
--- a/SmartDeviceLink/SDLTextField.m
+++ b/SmartDeviceLink/SDLTextField.m
@@ -48,6 +48,18 @@ NS_ASSUME_NONNULL_BEGIN
return [self.store sdl_objectForName:SDLRPCParameterNameRows ofClass:NSNumber.class error:&error];
}
+- (instancetype)initWithName:(SDLTextFieldName)name characterSet:(SDLCharacterSet)characterSet width:(NSUInteger)width rows:(NSUInteger)rows {
+ self = [self init];
+ if (!self) { return nil; }
+
+ self.name = name;
+ self.characterSet = characterSet;
+ self.width = @(width);
+ self.rows = @(rows);
+
+ return self;
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
index 1d72c106f..40edaeed3 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
@@ -9,19 +9,27 @@
#import "SDLChoiceSet.h"
#import "SDLChoiceSetDelegate.h"
#import "SDLDeleteChoicesOperation.h"
+#import "SDLDisplayCapability.h"
#import "SDLFileManager.h"
+#import "SDLGlobals.h"
#import "SDLHMILevel.h"
#import "SDLKeyboardDelegate.h"
#import "SDLKeyboardProperties.h"
+#import "SDLNotificationConstants.h"
+#import "SDLOnHMIStatus.h"
#import "SDLPreloadChoicesOperation.h"
#import "SDLPresentChoiceSetOperation.h"
#import "SDLPresentKeyboardOperation.h"
-#import "SDLGlobals.h"
+#import "SDLRPCNotificationNotification.h"
#import "SDLStateMachine.h"
#import "SDLSystemContext.h"
+#import "SDLSystemCapability.h"
#import "SDLSystemCapabilityManager.h"
-#import "TestConnectionManager.h"
+#import "SDLTextField.h"
#import "SDLVersion.h"
+#import "SDLWindowCapability.h"
+
+#import "TestConnectionManager.h"
@interface SDLPresentChoiceSetOperation()
@@ -43,6 +51,7 @@
@property (copy, nonatomic, nullable) SDLHMILevel currentHMILevel;
@property (copy, nonatomic, nullable) SDLSystemContext currentSystemContext;
+@property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability;
@property (strong, nonatomic) NSMutableSet<SDLChoiceCell *> *preloadedMutableChoices;
@property (strong, nonatomic, readonly) NSSet<SDLChoiceCell *> *pendingPreloadChoices;
@@ -52,6 +61,9 @@
@property (assign, nonatomic, getter=isVROptional) BOOL vrOptional;
+- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification;
+- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability;
+
@end
QuickSpecBegin(SDLChoiceSetManagerSpec)
@@ -63,6 +75,10 @@ describe(@"choice set manager tests", ^{
__block SDLFileManager *testFileManager = nil;
__block SDLSystemCapabilityManager *testSystemCapabilityManager = nil;
+ __block SDLWindowCapability *enabledWindowCapability = nil;
+ __block SDLWindowCapability *disabledWindowCapability = nil;
+ __block SDLWindowCapability *blankWindowCapability = nil;
+
__block SDLChoiceCell *testCell1 = nil;
__block SDLChoiceCell *testCell2 = nil;
__block SDLChoiceCell *testCell3 = nil;
@@ -77,6 +93,13 @@ describe(@"choice set manager tests", ^{
testCell1 = [[SDLChoiceCell alloc] initWithText:@"test1"];
testCell2 = [[SDLChoiceCell alloc] initWithText:@"test2"];
testCell3 = [[SDLChoiceCell alloc] initWithText:@"test3"];
+
+ enabledWindowCapability = [[SDLWindowCapability alloc] init];
+ enabledWindowCapability.textFields = @[[[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetType5 width:500 rows:1]];
+ disabledWindowCapability = [[SDLWindowCapability alloc] init];
+ disabledWindowCapability.textFields = @[];
+ blankWindowCapability = [[SDLWindowCapability alloc] init];
+ blankWindowCapability.textFields = @[];
});
it(@"should be in the correct startup state", ^{
@@ -86,10 +109,73 @@ describe(@"choice set manager tests", ^{
expect(testManager.keyboardConfiguration).to(equal(defaultProperties));
});
+ describe(@"receiving an HMI status update", ^{
+ __block SDLOnHMIStatus *newStatus = nil;
+ beforeEach(^{
+ newStatus = [[SDLOnHMIStatus alloc] init];
+ });
+
+ context(@"when starting with the queue suspended", ^{
+ beforeEach(^{
+ testManager.transactionQueue.suspended = YES;
+ testManager.currentHMILevel = SDLHMILevelFull;
+ testManager.currentWindowCapability = enabledWindowCapability;
+ });
+
+ it(@"should enable the queue when entering HMI FULL", ^{
+ testManager.currentHMILevel = SDLHMILevelNone;
+
+ SDLOnHMIStatus *newHMIStatus = [[SDLOnHMIStatus alloc] initWithHMILevel:SDLHMILevelFull systemContext:SDLSystemContextMain audioStreamingState:SDLAudioStreamingStateNotAudible videoStreamingState:nil windowID:@0];
+ SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:newHMIStatus];
+ [testManager sdl_hmiStatusNotification:notification];
+
+ expect(testManager.transactionQueue.isSuspended).to(beFalse());
+ });
+
+ it(@"should enable the queue when receiving a good window capability", ^{
+ testManager.currentWindowCapability = disabledWindowCapability;
+
+ SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[enabledWindowCapability] windowTypeSupported:nil];
+ [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
+
+ expect(testManager.transactionQueue.isSuspended).to(beFalse());
+ });
+ });
+
+ context(@"when starting with the queue enabled", ^{
+ beforeEach(^{
+ testManager.transactionQueue.suspended = NO;
+ testManager.currentHMILevel = SDLHMILevelFull;
+ testManager.currentWindowCapability = enabledWindowCapability;
+ });
+
+ it(@"should suspend the queue when entering HMI NONE", ^{
+ SDLOnHMIStatus *newHMIStatus = [[SDLOnHMIStatus alloc] initWithHMILevel:SDLHMILevelNone systemContext:SDLSystemContextMain audioStreamingState:SDLAudioStreamingStateNotAudible videoStreamingState:nil windowID:@0];
+ SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:newHMIStatus];
+ [testManager sdl_hmiStatusNotification:notification];
+
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ });
+
+ it(@"should suspend the queue when receiving a bad display capability", ^{
+ SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[disabledWindowCapability] windowTypeSupported:nil];
+ [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
+
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ });
+
+ it(@"should not suspend the queue when receiving an empty display capability", ^{
+ SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[blankWindowCapability] windowTypeSupported:nil];
+ [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
+
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ });
+ });
+ });
+
describe(@"once started", ^{
beforeEach(^{
[testManager start];
- testManager.transactionQueue.suspended = YES;
});
it(@"should start checking for VR Optional", ^{
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m
index f4056cccb..986a01c61 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPreloadChoicesOperationSpec.m
@@ -80,7 +80,7 @@ describe(@"a preload choices operation", ^{
primaryTextField.name = SDLTextFieldNameMenuName;
windowCapability.textFields = @[];
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
@@ -89,16 +89,16 @@ describe(@"a preload choices operation", ^{
});
});
- context(@"disallowed display capabilities", ^{
+ context(@"only main text capabilities", ^{
it(@"should skip to preloading cells", ^{
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
[testOp start];
expect(@(testOp.currentState)).to(equal(SDLPreloadChoicesOperationStatePreloadingChoices));
});
});
- context(@"mixed display capabilities", ^{
+ context(@"only main text and image capabilities", ^{
beforeEach(^{
SDLImageField *choiceField = [[SDLImageField alloc] init];
choiceField.name = SDLImageFieldNameChoiceImage;
@@ -106,7 +106,7 @@ describe(@"a preload choices operation", ^{
OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO);
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
[testOp start];
});
@@ -119,7 +119,7 @@ describe(@"a preload choices operation", ^{
});
});
- context(@"allowed display capabilities", ^{
+ context(@"main text and all image display capabilities", ^{
beforeEach(^{
SDLImageField *choiceField = [[SDLImageField alloc] init];
choiceField.name = SDLImageFieldNameChoiceImage;
@@ -133,7 +133,7 @@ describe(@"a preload choices operation", ^{
beforeEach(^{
OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(YES);
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
[testOp start];
});
@@ -148,7 +148,7 @@ describe(@"a preload choices operation", ^{
context(@"when artworks are static icons", ^{
beforeEach(^{
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithStaticIcon];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithStaticIcon];
[testOp start];
});
@@ -161,7 +161,7 @@ describe(@"a preload choices operation", ^{
beforeEach(^{
OCMStub([testFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(NO);
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithArtwork];
[testOp start];
});
@@ -191,7 +191,7 @@ describe(@"a preload choices operation", ^{
describe(@"assembling choices", ^{
it(@"should be correct with no text and VR required", ^{
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
@@ -207,7 +207,7 @@ describe(@"a preload choices operation", ^{
primaryTextField.name = SDLTextFieldNameMenuName;
windowCapability.textFields = @[primaryTextField];
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
@@ -226,7 +226,7 @@ describe(@"a preload choices operation", ^{
secondaryTextField.name = SDLTextFieldNameSecondaryText;
windowCapability.textFields = @[primaryTextField, secondaryTextField];
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
@@ -247,7 +247,7 @@ describe(@"a preload choices operation", ^{
tertiaryTextField.name = SDLTextFieldNameTertiaryText;
windowCapability.textFields = @[primaryTextField, secondaryTextField, tertiaryTextField];
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:NO cellsToPreload:cellsWithoutArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
@@ -261,7 +261,7 @@ describe(@"a preload choices operation", ^{
it(@"should be correct with VR optional", ^{
- testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric defaultMainWindowCapability:windowCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork];
+ testOp = [[SDLPreloadChoicesOperation alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager displayName:SDLDisplayTypeGeneric windowCapability:windowCapability isVROptional:YES cellsToPreload:cellsWithoutArtwork];
[testOp start];
NSArray<SDLCreateInteractionChoiceSet *> *receivedRequests = (NSArray<SDLCreateInteractionChoiceSet *> *)testConnectionManager.receivedRequests;
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
index 6534b49df..730af59f7 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
@@ -4,9 +4,13 @@
#import "SDLArtwork.h"
#import "SDLDisplayCapabilities.h"
+#import "SDLDisplayCapability.h"
#import "SDLFileManager.h"
#import "SDLHMILevel.h"
#import "SDLImage.h"
+#import "SDLNotificationConstants.h"
+#import "SDLOnHMIStatus.h"
+#import "SDLRPCNotificationNotification.h"
#import "SDLShow.h"
#import "SDLSoftButton.h"
#import "SDLSoftButtonCapabilities.h"
@@ -15,7 +19,9 @@
#import "SDLSoftButtonReplaceOperation.h"
#import "SDLSoftButtonState.h"
#import "SDLSoftButtonTransitionOperation.h"
+#import "SDLSystemCapability.h"
#import "SDLSystemCapabilityManager.h"
+#import "SDLWindowCapability.h"
#import "TestConnectionManager.h"
@interface SDLSoftButtonObject()
@@ -34,11 +40,14 @@
@property (strong, nonatomic) NSOperationQueue *transactionQueue;
-@property (strong, nonatomic, nullable, readonly) SDLWindowCapability *windowCapability;
+@property (strong, nonatomic, nullable) SDLSoftButtonCapabilities *softButtonCapabilities;
@property (copy, nonatomic, nullable) SDLHMILevel currentLevel;
@property (strong, nonatomic) NSMutableArray<SDLAsynchronousOperation *> *batchQueue;
+- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification;
+- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability;
+
@end
QuickSpecBegin(SDLSoftButtonManagerSpec)
@@ -75,8 +84,20 @@ describe(@"a soft button manager", ^{
testManager = [[SDLSoftButtonManager alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager systemCapabilityManager:testSystemCapabilityManager];
[testManager start];
- expect(testManager.currentLevel).to(beNil());
- testManager.currentLevel = SDLHMILevelFull;
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+
+ SDLSoftButtonCapabilities *softButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ softButtonCapabilities.imageSupported = @YES;
+ softButtonCapabilities.textSupported = @YES;
+ softButtonCapabilities.longPressAvailable = @YES;
+ softButtonCapabilities.shortPressAvailable = @YES;
+
+ SDLWindowCapability *windowCapability = [[SDLWindowCapability alloc] init];
+ windowCapability.softButtonCapabilities = @[softButtonCapabilities];
+ SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[windowCapability] windowTypeSupported:nil];
+ [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
});
it(@"should instantiate correctly", ^{
@@ -85,13 +106,21 @@ describe(@"a soft button manager", ^{
expect(testManager.softButtonObjects).to(beEmpty());
expect(testManager.currentMainField1).to(beNil());
- expect(testManager.windowCapability).to(beNil());
expect(testManager.transactionQueue).toNot(beNil());
+ expect(testManager.transactionQueue.isSuspended).to(beFalse());
+ expect(testManager.softButtonCapabilities).toNot(beNil());
+ expect(testManager.currentLevel).to(equal(SDLHMILevelFull));
+
+ // These are set up earlier for future tests and therefore won't be nil
+// expect(testManager.windowCapability).to(beNil());
+// expect(testManager.currentLevel).to(beNil());
});
context(@"when in HMI NONE", ^{
beforeEach(^{
- testManager.currentLevel = SDLHMILevelNone;
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelNone;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
testObject1 = [[SDLSoftButtonObject alloc] initWithName:@"name1" states:@[object1State1, object1State2] initialStateName:object1State1Name handler:nil];
testObject2 = [[SDLSoftButtonObject alloc] initWithName:@"name2" state:object2State1 handler:nil];
@@ -105,19 +134,16 @@ describe(@"a soft button manager", ^{
});
});
- context(@"when no HMI level has been received", ^{
+ context(@"when there are no soft button capabilities", ^{
beforeEach(^{
- testManager.currentLevel = nil;
-
- testObject1 = [[SDLSoftButtonObject alloc] initWithName:@"name1" states:@[object1State1, object1State2] initialStateName:object1State1Name handler:nil];
- testObject2 = [[SDLSoftButtonObject alloc] initWithName:@"name2" state:object2State1 handler:nil];
-
- testManager.softButtonObjects = @[testObject1, testObject2];
+ SDLWindowCapability *windowCapability = [[SDLWindowCapability alloc] init];
+ SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[windowCapability] windowTypeSupported:nil];
+ [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
});
- it(@"should set the soft buttons, but not update", ^{
- expect(testManager.softButtonObjects).toNot(beEmpty());
- expect(testManager.transactionQueue.suspended).to(beTrue());
+ it(@"should set the buttons but have the queue suspended", ^{
+ expect(testManager.softButtonObjects).toNot(beNil());
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
});
});
@@ -143,21 +169,6 @@ describe(@"a soft button manager", ^{
testManager.softButtonObjects = @[testObject1, testObject2];
});
- describe(@"while batching", ^{
- beforeEach(^{
- testManager.batchUpdates = YES;
-
- [testObject1 transitionToNextState];
- [testObject2 transitionToNextState];
- testManager.softButtonObjects = @[testObject2, testObject1];
- });
-
- it(@"should properly queue the batching updates", ^{
- expect(testManager.transactionQueue.operationCount).to(equal(1));
- expect(testManager.batchQueue).to(haveCount(1));
- });
- });
-
it(@"should set soft buttons correctly", ^{
expect(testManager.softButtonObjects).toNot(beNil());
expect(testObject1.buttonId).to(equal(0));
@@ -165,6 +176,7 @@ describe(@"a soft button manager", ^{
expect(testObject1.manager).to(equal(testManager));
expect(testObject2.manager).to(equal(testManager));
+ // One replace operation
expect(testManager.transactionQueue.operationCount).to(equal(1));
});
@@ -181,9 +193,26 @@ describe(@"a soft button manager", ^{
expect([testManager softButtonObjectNamed:object1Name].name).to(equal(object1Name));
});
+ describe(@"while batching", ^{
+ beforeEach(^{
+ testManager.batchUpdates = YES;
+
+ [testObject1 transitionToNextState];
+ [testObject2 transitionToNextState];
+ testManager.softButtonObjects = @[testObject2, testObject1];
+ });
+
+ it(@"should properly queue the batching updates", ^{
+ expect(testManager.transactionQueue.operationCount).to(equal(1));
+ expect(testManager.batchQueue).to(haveCount(1));
+ });
+ });
+
context(@"when the HMI level is now NONE", ^{
beforeEach(^{
- testManager.currentLevel = SDLHMILevelNone;
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelNone;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
});
it(@"should not transition buttons", ^{
@@ -246,7 +275,7 @@ describe(@"a soft button manager", ^{
expect(testManager.currentMainField1).to(beNil());
expect(testManager.transactionQueue.operationCount).to(equal(0));
expect(testManager.currentLevel).to(beNil());
- expect(testManager.windowCapability).to(beNil());
+ expect(testManager.softButtonCapabilities).to(beNil());
});
});
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
index 35c3f0a08..fb7298988 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
@@ -370,6 +370,31 @@ describe(@"text and graphic manager", ^{
testManager.textField4Type = nil;
});
+ context(@"when textFields are nil", ^{
+ beforeEach(^{
+ testManager.windowCapability = [[SDLWindowCapability alloc] init];
+ });
+
+ it(@"should send everything", ^{
+ testManager.mediaTrackTextField = textMediaTrack;
+ testManager.title = textTitle;
+ testManager.textField1 = textLine1;
+ testManager.textField2 = textLine2;
+ testManager.textField3 = textLine3;
+ testManager.textField4 = textLine4;
+
+ testManager.batchUpdates = NO;
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ expect(testManager.inProgressUpdate.mainField1).to(equal(textLine1));
+ expect(testManager.inProgressUpdate.mainField2).to(equal(textLine2));
+ expect(testManager.inProgressUpdate.mainField3).to(equal(textLine3));
+ expect(testManager.inProgressUpdate.mainField4).to(equal(textLine4));
+ });
+ });
+
context(@"with one line available", ^{
beforeEach(^{
testManager.windowCapability = [[SDLWindowCapability alloc] init];
@@ -378,24 +403,24 @@ describe(@"text and graphic manager", ^{
testManager.windowCapability.textFields = @[lineOneField];
});
- it(@"should set mediatrack properly", ^{
+ it(@"should not set mediatrack", ^{
testManager.mediaTrackTextField = textMediaTrack;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.mediaTrack).toNot(equal(textMediaTrack));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
- it(@"should set title properly", ^{
+ it(@"should not set title", ^{
testManager.title = textTitle;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ expect(testManager.inProgressUpdate.templateTitle).toNot(equal(textTitle));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
@@ -469,6 +494,31 @@ describe(@"text and graphic manager", ^{
expect(testManager.inProgressUpdate.mainField2).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField2).to(beNil());
});
+
+ context(@"when media track and title are available", ^{
+ beforeEach(^{
+ NSMutableArray<SDLTextField *> *existingFieldsMutable = [testManager.windowCapability.textFields mutableCopy];
+ SDLTextField *mediaTrack = [[SDLTextField alloc] init];
+ mediaTrack.name = SDLTextFieldNameMediaTrack;
+ [existingFieldsMutable addObject:mediaTrack];
+
+ SDLTextField *title = [[SDLTextField alloc] init];
+ title.name = SDLTextFieldNameTemplateTitle;
+ [existingFieldsMutable addObject:title];
+ testManager.windowCapability.textFields = [existingFieldsMutable copy];
+ });
+
+ it(@"should set media track and title properly", ^{
+ testManager.mediaTrackTextField = textMediaTrack;
+ testManager.title = textTitle;
+
+ testManager.batchUpdates = NO;
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ });
+ });
});
context(@"with two lines available", ^{
@@ -479,24 +529,24 @@ describe(@"text and graphic manager", ^{
testManager.windowCapability.textFields = @[lineTwoField];
});
- it(@"should set mediatrack properly", ^{
+ it(@"should not set mediatrack", ^{
testManager.mediaTrackTextField = textMediaTrack;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.mediaTrack).toNot(equal(textMediaTrack));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
- it(@"should set title properly", ^{
+ it(@"should not set title", ^{
testManager.title = textTitle;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ expect(testManager.inProgressUpdate.templateTitle).toNot(equal(textTitle));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
@@ -589,24 +639,24 @@ describe(@"text and graphic manager", ^{
testManager.windowCapability.textFields = @[lineThreeField];
});
- it(@"should set mediatrack properly", ^{
+ it(@"should not set mediatrack", ^{
testManager.mediaTrackTextField = textMediaTrack;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.mediaTrack).toNot(equal(textMediaTrack));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
- it(@"should set title properly", ^{
+ it(@"should not set title", ^{
testManager.title = textTitle;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ expect(testManager.inProgressUpdate.templateTitle).toNot(equal(textTitle));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
@@ -703,24 +753,24 @@ describe(@"text and graphic manager", ^{
testManager.windowCapability.textFields = @[lineFourField];
});
- it(@"should set mediatrack properly", ^{
+ it(@"should not set mediatrack", ^{
testManager.mediaTrackTextField = textMediaTrack;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.mediaTrack).to(equal(textMediaTrack));
+ expect(testManager.inProgressUpdate.mediaTrack).toNot(equal(textMediaTrack));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
- it(@"should set title properly", ^{
+ it(@"should not set title", ^{
testManager.title = textTitle;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- expect(testManager.inProgressUpdate.templateTitle).to(equal(textTitle));
+ expect(testManager.inProgressUpdate.templateTitle).toNot(equal(textTitle));
expect(testManager.inProgressUpdate.mainField1).to(beEmpty());
expect(testManager.inProgressUpdate.metadataTags.mainField1).to(beNil());
});
@@ -820,18 +870,35 @@ describe(@"text and graphic manager", ^{
context(@"when the image is already on the head unit", ^{
beforeEach(^{
OCMStub([mockFileManager hasUploadedFile:[OCMArg isNotNil]]).andReturn(YES);
+ });
+ it(@"should immediately attempt to update", ^{
testManager.primaryGraphic = testArtwork;
testManager.secondaryGraphic = testArtwork;
testManager.batchUpdates = NO;
[testManager updateWithCompletionHandler:nil];
- });
- it(@"should immediately attempt to update", ^{
expect(testManager.inProgressUpdate.graphic.value).to(equal(testArtworkName));
expect(testManager.inProgressUpdate.secondaryGraphic.value).to(equal(testArtworkName));
expect(testManager.inProgressUpdate.mainField1).to(equal(testTextFieldText));
});
+
+ context(@"when imageFields are nil", ^{
+ beforeEach(^{
+ testManager.windowCapability = [[SDLWindowCapability alloc] init];
+ });
+
+ it(@"should send everything", ^{
+ testManager.primaryGraphic = testArtwork;
+ testManager.secondaryGraphic = testArtwork;
+ testManager.batchUpdates = NO;
+ [testManager updateWithCompletionHandler:nil];
+
+ expect(testManager.inProgressUpdate.graphic.value).to(equal(testArtworkName));
+ expect(testManager.inProgressUpdate.secondaryGraphic.value).to(equal(testArtworkName));
+ expect(testManager.inProgressUpdate.mainField1).to(equal(testTextFieldText));
+ });
+ });
});
context(@"when the image is a static icon", ^{
diff --git a/SmartDeviceLinkTests/RPCSpecs/NotificationSpecs/SDLOnHMIStatusSpec.m b/SmartDeviceLinkTests/RPCSpecs/NotificationSpecs/SDLOnHMIStatusSpec.m
index 61b1165d3..918a34667 100644
--- a/SmartDeviceLinkTests/RPCSpecs/NotificationSpecs/SDLOnHMIStatusSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/NotificationSpecs/SDLOnHMIStatusSpec.m
@@ -19,37 +19,55 @@
QuickSpecBegin(SDLOnHMIStatusSpec)
describe(@"Getter/Setter Tests", ^ {
+ __block SDLHMILevel testLevel = nil;
+ __block SDLSystemContext testContext = nil;
+ __block SDLAudioStreamingState testAudioState = nil;
+ __block SDLVideoStreamingState testVideoState = nil;
+ __block NSNumber<SDLInt> *testWindowID = nil;
+
+ beforeEach(^{
+ testLevel = SDLHMILevelFull;
+ testContext = SDLSystemContextAlert;
+ testAudioState = SDLAudioStreamingStateAttenuated;
+ testVideoState = SDLVideoStreamingStateStreamable;
+ testWindowID = @0;
+ });
+
it(@"Should set and get correctly", ^ {
SDLOnHMIStatus* testNotification = [[SDLOnHMIStatus alloc] init];
- testNotification.hmiLevel = SDLHMILevelLimited;
- testNotification.audioStreamingState = SDLAudioStreamingStateAttenuated;
- testNotification.systemContext = SDLSystemContextHMIObscured;
- testNotification.videoStreamingState = SDLVideoStreamingStateStreamable;
+ testNotification.hmiLevel = testLevel;
+ testNotification.audioStreamingState = testAudioState;
+ testNotification.systemContext = testContext;
+ testNotification.videoStreamingState = testVideoState;
+ testNotification.windowID = testWindowID;
- expect(testNotification.hmiLevel).to(equal(SDLHMILevelLimited));
- expect(testNotification.audioStreamingState).to(equal(SDLAudioStreamingStateAttenuated));
- expect(testNotification.systemContext).to(equal(SDLSystemContextHMIObscured));
- expect(testNotification.videoStreamingState).to(equal(SDLVideoStreamingStateStreamable));
+ expect(testNotification.hmiLevel).to(equal(testLevel));
+ expect(testNotification.audioStreamingState).to(equal(testAudioState));
+ expect(testNotification.systemContext).to(equal(testContext));
+ expect(testNotification.videoStreamingState).to(equal(testVideoState));
+ expect(testNotification.windowID).to(equal(testWindowID));
});
it(@"Should get correctly when initialized", ^ {
- NSMutableDictionary* dict = [@{SDLRPCParameterNameNotification:
- @{SDLRPCParameterNameParameters:
- @{SDLRPCParameterNameHMILevel: SDLHMILevelLimited,
- SDLRPCParameterNameAudioStreamingState: SDLAudioStreamingStateAttenuated,
- SDLRPCParameterNameSystemContext: SDLSystemContextHMIObscured,
- SDLRPCParameterNameVideoStreamingState: SDLVideoStreamingStateStreamable},
- SDLRPCParameterNameOperationName:SDLRPCFunctionNameOnHMIStatus}} mutableCopy];
+ NSDictionary* dict = @{SDLRPCParameterNameNotification:
+ @{SDLRPCParameterNameParameters:
+ @{SDLRPCParameterNameHMILevel: testLevel,
+ SDLRPCParameterNameAudioStreamingState: testAudioState,
+ SDLRPCParameterNameSystemContext: testContext,
+ SDLRPCParameterNameVideoStreamingState: testVideoState,
+ SDLRPCParameterNameWindowId: testWindowID},
+ SDLRPCParameterNameOperationName:SDLRPCFunctionNameOnHMIStatus}};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLOnHMIStatus* testNotification = [[SDLOnHMIStatus alloc] initWithDictionary:dict];
#pragma clang diagnostic pop
- expect(testNotification.hmiLevel).to(equal(SDLHMILevelLimited));
- expect(testNotification.audioStreamingState).to(equal(SDLAudioStreamingStateAttenuated));
- expect(testNotification.systemContext).to(equal(SDLSystemContextHMIObscured));
- expect(testNotification.videoStreamingState).to(equal(SDLVideoStreamingStateStreamable));
+ expect(testNotification.hmiLevel).to(equal(testLevel));
+ expect(testNotification.audioStreamingState).to(equal(testAudioState));
+ expect(testNotification.systemContext).to(equal(testContext));
+ expect(testNotification.videoStreamingState).to(equal(testVideoState));
+ expect(testNotification.windowID).to(equal(testWindowID));
});
it(@"Should return nil if not set", ^ {
@@ -59,6 +77,16 @@ describe(@"Getter/Setter Tests", ^ {
expect(testNotification.audioStreamingState).to(beNil());
expect(testNotification.systemContext).to(beNil());
expect(testNotification.videoStreamingState).to(beNil());
+ expect(testNotification.windowID).to(beNil());
+ });
+
+ it(@"should initialize properly with initWithHMILevel:systemContext:audioStreamingState:videoStreamingState:windowID:", ^{
+ SDLOnHMIStatus *testStatus = [[SDLOnHMIStatus alloc] initWithHMILevel:testLevel systemContext:testContext audioStreamingState:testAudioState videoStreamingState:testVideoState windowID:testWindowID];
+ expect(testStatus.hmiLevel).to(equal(testLevel));
+ expect(testStatus.systemContext).to(equal(testContext));
+ expect(testStatus.audioStreamingState).to(equal(testAudioState));
+ expect(testStatus.videoStreamingState).to(equal(testVideoState));
+ expect(testStatus.windowID).to(equal(testWindowID));
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageFieldSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageFieldSpec.m
index 26317d657..25d17673b 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageFieldSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLImageFieldSpec.m
@@ -17,33 +17,41 @@
QuickSpecBegin(SDLImageFieldSpec)
-SDLImageResolution* resolution = [[SDLImageResolution alloc] init];
-
describe(@"Getter/Setter Tests", ^ {
+ __block SDLImageFieldName testName = nil;
+ __block NSArray<SDLFileType> *testFileTypes = nil;
+ __block SDLImageResolution *testResolution = nil;
+
+ beforeEach(^{
+ testName = SDLImageFieldNameAppIcon;
+ testFileTypes = @[SDLFileTypePNG, SDLFileTypeJPEG];
+ testResolution = [[SDLImageResolution alloc] initWithWidth:800 height:800];
+ });
+
it(@"Should set and get correctly", ^ {
SDLImageField* testStruct = [[SDLImageField alloc] init];
- testStruct.name = SDLImageFieldNameTurnIcon;
- testStruct.imageTypeSupported = [@[SDLFileTypePNG, SDLFileTypeJPEG] copy];
- testStruct.imageResolution = resolution;
+ testStruct.name = testName;
+ testStruct.imageTypeSupported = testFileTypes;
+ testStruct.imageResolution = testResolution;
- expect(testStruct.name).to(equal(SDLImageFieldNameTurnIcon));
- expect(testStruct.imageTypeSupported).to(equal([@[SDLFileTypePNG, SDLFileTypeJPEG] copy]));
- expect(testStruct.imageResolution).to(equal(resolution));
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.imageTypeSupported).to(equal(testFileTypes));
+ expect(testStruct.imageResolution).to(equal(testResolution));
});
it(@"Should get correctly when initialized", ^ {
- NSMutableDictionary* dict = [@{SDLRPCParameterNameName:SDLImageFieldNameTurnIcon,
- SDLRPCParameterNameImageTypeSupported:[@[SDLFileTypePNG, SDLFileTypeJPEG] copy],
- SDLRPCParameterNameImageResolution:resolution} mutableCopy];
+ NSDictionary *dict = @{SDLRPCParameterNameName: testName,
+ SDLRPCParameterNameImageTypeSupported: testFileTypes,
+ SDLRPCParameterNameImageResolution: testResolution};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLImageField* testStruct = [[SDLImageField alloc] initWithDictionary:dict];
#pragma clang diagnostic pop
- expect(testStruct.name).to(equal(SDLImageFieldNameTurnIcon));
- expect(testStruct.imageTypeSupported).to(equal([@[SDLFileTypePNG, SDLFileTypeJPEG] copy]));
- expect(testStruct.imageResolution).to(equal(resolution));
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.imageTypeSupported).to(equal(testFileTypes));
+ expect(testStruct.imageResolution).to(equal(testResolution));
});
it(@"Should return nil if not set", ^ {
@@ -53,6 +61,14 @@ describe(@"Getter/Setter Tests", ^ {
expect(testStruct.imageTypeSupported).to(beNil());
expect(testStruct.imageResolution).to(beNil());
});
+
+ it(@"should initialize correctly with initWithName:imageTypeSupported:imageResolution:", ^{
+ SDLImageField *testStruct = [[SDLImageField alloc] initWithName:testName imageTypeSupported:testFileTypes imageResolution:testResolution];
+
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.imageTypeSupported).to(equal(testFileTypes));
+ expect(testStruct.imageResolution).to(equal(testResolution));
+ });
});
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLTextFieldSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLTextFieldSpec.m
index 330d53a3f..fcde49e1e 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLTextFieldSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLTextFieldSpec.m
@@ -17,34 +17,39 @@
QuickSpecBegin(SDLTextFieldSpec)
describe(@"Getter/Setter Tests", ^ {
+ __block SDLTextFieldName testName = SDLTextFieldNameETA;
+ __block SDLCharacterSet testCharacterSet = SDLCharacterSetCID1;
+ __block NSUInteger testWidth = 100;
+ __block NSUInteger testRows = 4;
+
it(@"Should set and get correctly", ^ {
SDLTextField* testStruct = [[SDLTextField alloc] init];
- testStruct.name = SDLTextFieldNameTertiaryText;
- testStruct.characterSet = SDLCharacterSetType5;
- testStruct.width = @111;
- testStruct.rows = @4;
+ testStruct.name = testName;
+ testStruct.characterSet = testCharacterSet;
+ testStruct.width = @(testWidth);
+ testStruct.rows = @(testRows);
- expect(testStruct.name).to(equal(SDLTextFieldNameTertiaryText));
- expect(testStruct.characterSet).to(equal(SDLCharacterSetType5));
- expect(testStruct.width).to(equal(@111));
- expect(testStruct.rows).to(equal(@4));
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.characterSet).to(equal(testCharacterSet));
+ expect(testStruct.width).to(equal(@(testWidth)));
+ expect(testStruct.rows).to(equal(@(testRows)));
});
it(@"Should get correctly when initialized", ^ {
- NSMutableDictionary* dict = [@{SDLRPCParameterNameName:SDLTextFieldNameTertiaryText,
- SDLRPCParameterNameCharacterSet:SDLCharacterSetType5,
- SDLRPCParameterNameWidth:@111,
- SDLRPCParameterNameRows:@4} mutableCopy];
+ NSDictionary *dict = @{SDLRPCParameterNameName:testName,
+ SDLRPCParameterNameCharacterSet:testCharacterSet,
+ SDLRPCParameterNameWidth:@(testWidth),
+ SDLRPCParameterNameRows:@(testRows)};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
SDLTextField* testStruct = [[SDLTextField alloc] initWithDictionary:dict];
#pragma clang diagnostic pop
- expect(testStruct.name).to(equal(SDLTextFieldNameTertiaryText));
- expect(testStruct.characterSet).to(equal(SDLCharacterSetType5));
- expect(testStruct.width).to(equal(@111));
- expect(testStruct.rows).to(equal(@4));
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.characterSet).to(equal(testCharacterSet));
+ expect(testStruct.width).to(equal(@(testWidth)));
+ expect(testStruct.rows).to(equal(@(testRows)));
});
it(@"Should return nil if not set", ^ {
@@ -55,6 +60,15 @@ describe(@"Getter/Setter Tests", ^ {
expect(testStruct.width).to(beNil());
expect(testStruct.rows).to(beNil());
});
+
+ it(@"should initialize correctly with initWithName:characterSet:width:rows:", ^{
+ SDLTextField *testStruct = [[SDLTextField alloc] initWithName:testName characterSet:testCharacterSet width:testWidth rows:testRows];
+
+ expect(testStruct.name).to(equal(testName));
+ expect(testStruct.characterSet).to(equal(testCharacterSet));
+ expect(testStruct.width).to(equal(@(testWidth)));
+ expect(testStruct.rows).to(equal(@(testRows)));
+ });
});
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m b/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m
index 5ce732c86..4336f7eab 100644
--- a/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m
+++ b/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m
@@ -697,13 +697,12 @@ describe(@"System capability manager", ^{
expect(handlerTriggeredCount).toEventually(equal(1));
expect(observerTriggeredCount).toEventually(equal(1));
- expect(phoneObserver.selectorCalledCount).toEventually(equal(1));
-
- expect(navigationObserver.selectorCalledCount).toEventually(equal(1));
+ expect(phoneObserver.selectorCalledCount).toEventually(equal(0));
+ expect(navigationObserver.selectorCalledCount).toEventually(equal(0));
- expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(1));
- expect(videoStreamingObserver.subscribedValuesReceived).toEventually(haveCount(1));
- expect(videoStreamingObserver.subscribedValuesReceived.firstObject).toEventually(beFalse());
+ expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(0));
+ expect(videoStreamingObserver.subscribedValuesReceived).toEventually(haveCount(0));
+ expect(videoStreamingObserver.subscribedValuesReceived.firstObject).toEventually(beNil());
expect(displaysObserver.selectorCalledCount).toEventually(equal(1));
expect(displaysObserver.subscribedValuesReceived).toEventually(haveCount(1));
@@ -727,11 +726,9 @@ describe(@"System capability manager", ^{
expect(handlerTriggeredCount).toEventually(equal(1));
expect(observerTriggeredCount).toEventually(equal(1));
- expect(phoneObserver.selectorCalledCount).toEventually(equal(1)); // No change from above
-
- expect(navigationObserver.selectorCalledCount).toEventually(equal(1));
-
- expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(1));
+ expect(phoneObserver.selectorCalledCount).toEventually(equal(0)); // No change from above
+ expect(navigationObserver.selectorCalledCount).toEventually(equal(0));
+ expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(0));
expect(displaysObserver.selectorCalledCount).toEventually(equal(1));
});
@@ -764,13 +761,12 @@ describe(@"System capability manager", ^{
expect(handlerTriggeredCount).toEventually(equal(2));
expect(observerTriggeredCount).toEventually(equal(2));
- expect(phoneObserver.selectorCalledCount).toEventually(equal(2));
-
- expect(navigationObserver.selectorCalledCount).toEventually(equal(1));
+ expect(phoneObserver.selectorCalledCount).toEventually(equal(1));
+ expect(navigationObserver.selectorCalledCount).toEventually(equal(0));
- expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(1));
- expect(videoStreamingObserver.subscribedValuesReceived).toEventually(haveCount(1));
- expect(videoStreamingObserver.subscribedValuesReceived.firstObject).toEventually(beFalse());
+ expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(0));
+ expect(videoStreamingObserver.subscribedValuesReceived).toEventually(haveCount(0));
+ expect(videoStreamingObserver.subscribedValuesReceived.firstObject).toEventually(beNil());
expect(displaysObserver.selectorCalledCount).toEventually(equal(1));
expect(displaysObserver.subscribedValuesReceived).toEventually(haveCount(1));
@@ -790,10 +786,10 @@ describe(@"System capability manager", ^{
});
it(@"should not notify the subscriber of the new data", ^{
- expect(phoneObserver.selectorCalledCount).toEventually(equal(2)); // No change from above
+ expect(phoneObserver.selectorCalledCount).toEventually(equal(1)); // No change from above
expect(observerTriggeredCount).toEventually(equal(2));
- expect(navigationObserver.selectorCalledCount).toEventually(equal(1));
- expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(1));
+ expect(navigationObserver.selectorCalledCount).toEventually(equal(0));
+ expect(videoStreamingObserver.selectorCalledCount).toEventually(equal(0));
expect(displaysObserver.selectorCalledCount).toEventually(equal(1));
});
});