summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2021-03-04 13:05:38 -0500
committerJoel Fischer <joeljfischer@gmail.com>2021-03-04 13:05:38 -0500
commit3561365177c1cfc9d51d921bcd0fded64a8001d2 (patch)
tree7a7e0779f1d82caf206bbcea88ccad7fce7771b4
parent78342fccbba9607895c2d2327646c2b08bad1bd3 (diff)
parentee70ad16db0c0eb3793196860a153bab4387cef7 (diff)
downloadsdl_ios-3561365177c1cfc9d51d921bcd0fded64a8001d2.tar.gz
Merge branch 'develop' into feature/issue-1024-sdl-0180-broaden-choiceCell-uniqueness
# Conflicts: # SmartDeviceLink-iOS.xcodeproj/project.pbxproj # SmartDeviceLink/private/SDLMenuManager.m # SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m # SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
-rw-r--r--.github/workflows/test.yml4
-rw-r--r--DEPENDENCIES.md31
-rw-r--r--Example Apps/Example ObjC/AlertManager.m26
-rw-r--r--Example Apps/Example ObjC/MenuManager.m26
-rw-r--r--Example Apps/Example ObjC/ProxyManager.m8
-rw-r--r--Example Apps/Example Swift/AlertManager.swift23
-rw-r--r--Example Apps/Example Swift/MenuManager.swift26
-rw-r--r--Example Apps/Example Swift/ProxyManager.swift12
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj164
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-ObjC.xcscheme2
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme2
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLinkSwift.xcscheme2
-rw-r--r--SmartDeviceLink/private/SDLAlertManager.h52
-rw-r--r--SmartDeviceLink/private/SDLAlertManager.m171
-rw-r--r--SmartDeviceLink/private/SDLChoiceSetManager.m38
-rw-r--r--SmartDeviceLink/private/SDLConnectionManagerType.h5
-rw-r--r--SmartDeviceLink/private/SDLControlFramePayloadConstants.h22
-rw-r--r--SmartDeviceLink/private/SDLControlFramePayloadConstants.m22
-rw-r--r--SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.h46
-rw-r--r--SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.m74
-rw-r--r--SmartDeviceLink/private/SDLEncryptionLifecycleManager.m20
-rw-r--r--SmartDeviceLink/private/SDLError.h7
-rw-r--r--SmartDeviceLink/private/SDLError.m39
-rw-r--r--SmartDeviceLink/private/SDLGlobals.m2
-rw-r--r--SmartDeviceLink/private/SDLLifecycleManager.h2
-rw-r--r--SmartDeviceLink/private/SDLLifecycleManager.m43
-rw-r--r--SmartDeviceLink/private/SDLLogFileModuleMap.m5
-rw-r--r--SmartDeviceLink/private/SDLMenuManager.m15
-rw-r--r--SmartDeviceLink/private/SDLPresentAlertOperation.h38
-rw-r--r--SmartDeviceLink/private/SDLPresentAlertOperation.m451
-rw-r--r--SmartDeviceLink/private/SDLPresentChoiceSetOperation.h3
-rw-r--r--SmartDeviceLink/private/SDLPresentChoiceSetOperation.m18
-rw-r--r--SmartDeviceLink/private/SDLPresentKeyboardOperation.h4
-rw-r--r--SmartDeviceLink/private/SDLPresentKeyboardOperation.m21
-rw-r--r--SmartDeviceLink/private/SDLProtocol.h4
-rw-r--r--SmartDeviceLink/private/SDLProtocol.m17
-rw-r--r--SmartDeviceLink/private/SDLRPCParameterNames.h6
-rw-r--r--SmartDeviceLink/private/SDLRPCParameterNames.m6
-rw-r--r--SmartDeviceLink/private/SDLSoftButtonManager.m33
-rw-r--r--SmartDeviceLink/private/SDLStreamingAudioLifecycleManager.m22
-rw-r--r--SmartDeviceLink/private/SDLStreamingVideoLifecycleManager.m13
-rw-r--r--SmartDeviceLink/private/SDLTextAndGraphicManager.m25
-rw-r--r--SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.h15
-rw-r--r--SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.m65
-rw-r--r--SmartDeviceLink/public/SDLAlertAudioData.h22
-rw-r--r--SmartDeviceLink/public/SDLAlertAudioData.m25
-rw-r--r--SmartDeviceLink/public/SDLAlertView.h76
-rw-r--r--SmartDeviceLink/public/SDLAlertView.m146
-rw-r--r--SmartDeviceLink/public/SDLAudioData.h55
-rw-r--r--SmartDeviceLink/public/SDLAudioData.m135
-rw-r--r--SmartDeviceLink/public/SDLErrorConstants.h16
-rw-r--r--SmartDeviceLink/public/SDLErrorConstants.m1
-rw-r--r--SmartDeviceLink/public/SDLFileManager.h2
-rw-r--r--SmartDeviceLink/public/SDLFileManager.m2
-rw-r--r--SmartDeviceLink/public/SDLKeyboardCapabilities.h64
-rw-r--r--SmartDeviceLink/public/SDLKeyboardCapabilities.m70
-rw-r--r--SmartDeviceLink/public/SDLKeyboardDelegate.h8
-rw-r--r--SmartDeviceLink/public/SDLKeyboardEvent.h10
-rw-r--r--SmartDeviceLink/public/SDLKeyboardEvent.m2
-rw-r--r--SmartDeviceLink/public/SDLKeyboardInputMask.h46
-rw-r--r--SmartDeviceLink/public/SDLKeyboardInputMask.m37
-rw-r--r--SmartDeviceLink/public/SDLKeyboardLayout.h5
-rw-r--r--SmartDeviceLink/public/SDLKeyboardLayout.m1
-rw-r--r--SmartDeviceLink/public/SDLKeyboardLayoutCapability.h62
-rw-r--r--SmartDeviceLink/public/SDLKeyboardLayoutCapability.m72
-rw-r--r--SmartDeviceLink/public/SDLKeyboardProperties.h35
-rw-r--r--SmartDeviceLink/public/SDLKeyboardProperties.m26
-rw-r--r--SmartDeviceLink/public/SDLManagerDelegate.h8
-rw-r--r--SmartDeviceLink/public/SDLMenuCell.h18
-rw-r--r--SmartDeviceLink/public/SDLMenuCell.m8
-rw-r--r--SmartDeviceLink/public/SDLRegisterAppInterfaceResponse.h16
-rw-r--r--SmartDeviceLink/public/SDLScreenManager.h29
-rw-r--r--SmartDeviceLink/public/SDLScreenManager.m25
-rw-r--r--SmartDeviceLink/public/SDLSystemCapabilityManager.m9
-rw-r--r--SmartDeviceLink/public/SDLSystemInfo.h43
-rw-r--r--SmartDeviceLink/public/SDLSystemInfo.m49
-rw-r--r--SmartDeviceLink/public/SDLTextFieldName.h2
-rw-r--r--SmartDeviceLink/public/SDLVehicleType.h11
-rw-r--r--SmartDeviceLink/public/SDLVehicleType.m12
-rw-r--r--SmartDeviceLink/public/SDLWindowCapability.h27
-rw-r--r--SmartDeviceLink/public/SDLWindowCapability.m14
-rw-r--r--SmartDeviceLink/public/SmartDeviceLink.h7
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m58
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m263
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m14
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m38
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m29
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m36
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m128
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLStreamingAudioLifecycleManagerSpec.m25
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLStreamingVideoLifecycleManagerSpec.m20
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLSystemInfoSpec.m83
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m16
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLControlFramePayloadConstantsSpec.m27
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m43
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m173
-rw-r--r--SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m12
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardEventSpec.m6
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardInputMaskSpec.m23
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardLayoutSpec.m5
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLRegisterAppInterfaceResponseSpec.m20
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardCapabilitiesSpec.m75
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardLayoutCapabilitySpec.m75
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardPropertiesSpec.m207
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVehicleTypeSpec.m58
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m392
-rw-r--r--SmartDeviceLinkTests/SDLAlertAudioDataSpec.m98
-rw-r--r--SmartDeviceLinkTests/SDLAlertManagerSpec.m316
-rw-r--r--SmartDeviceLinkTests/SDLAlertViewSpec.m307
-rw-r--r--SmartDeviceLinkTests/SDLAudioDataSpec.m301
-rw-r--r--SmartDeviceLinkTests/SDLEncryptionLifecycleManagerSpec.m206
-rw-r--r--SmartDeviceLinkTests/SDLMenuUpdateAlgorithmSpec.m26
-rw-r--r--SmartDeviceLinkTests/SDLPresentAlertOperationSpec.m1147
-rw-r--r--SmartDeviceLinkTests/SDLScreenManagerSpec.m32
-rw-r--r--SmartDeviceLinkTests/TestUtilities/TestConnectionManager.h2
-rw-r--r--SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m1
-rw-r--r--generator/test/test_functions.py8
-rw-r--r--generator/transformers/functions_producer.py6
118 files changed, 6175 insertions, 927 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f675f0b41..45d857d1b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -75,12 +75,10 @@ jobs:
# Upload coverage reports to Codecov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.0.10
- with:
- yml: ./codecov.yml
rpcTest:
name: RPC Generator Tests
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
steps:
diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md
index 0ab2739ed..ed9735a78 100644
--- a/DEPENDENCIES.md
+++ b/DEPENDENCIES.md
@@ -536,34 +536,3 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-### FBSnapshotTestCase
-BSD License
-
-For the FBSnapshotTestCase software
-
-Copyright (c) 2013, Facebook, Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name Facebook nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/Example Apps/Example ObjC/AlertManager.m b/Example Apps/Example ObjC/AlertManager.m
index df902dc0a..a352696ff 100644
--- a/Example Apps/Example ObjC/AlertManager.m
+++ b/Example Apps/Example ObjC/AlertManager.m
@@ -15,19 +15,23 @@ NS_ASSUME_NONNULL_BEGIN
@implementation AlertManager
+ (void)sendAlertWithManager:(SDLManager *)sdlManager image:(nullable NSString *)imageName textField1:(NSString *)textField1 textField2:(nullable NSString *)textField2 {
- SDLSoftButton *okSoftButton = [[SDLSoftButton alloc] initWithType:SDLSoftButtonTypeText text:AlertOKButtonText image:nil highlighted:YES buttonId:10000 systemAction:nil handler:nil];
- SDLAlert *alert = [[SDLAlert alloc] initWithAlertText1:textField1 alertText2:textField2 alertText3:nil softButtons:@[okSoftButton] playTone:YES ttsChunks:nil duration:5000 progressIndicator:NO alertIcon:nil cancelID:0];
+ SDLSoftButtonObject *okSoftButton = [[SDLSoftButtonObject alloc] initWithName:AlertOKButtonText text:AlertOKButtonText artwork:nil handler:nil];
+ SDLAlertView *alert = [[SDLAlertView alloc] initWithText:textField1 buttons:@[okSoftButton]];
+ alert.secondaryText = textField2;
- if (imageName == nil) {
- [sdlManager sendRequest:alert];
- } else {
- [self sdlex_sendImageWithName:imageName sdlManager:sdlManager completionHandler:^(BOOL success, NSString * _Nullable artworkName) {
- if (success) {
- alert.alertIcon = [[SDLImage alloc] initWithName:artworkName isTemplate:YES];
- }
- [sdlManager sendRequest:alert];
- }];
+ SDLAlertAudioData *alertAudioData = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"alert"];
+ alertAudioData.playTone = YES;
+ alert.audio = alertAudioData;
+
+ if (imageName != nil) {
+ alert.icon = [SDLArtwork artworkWithImage:[[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG];
}
+
+ [sdlManager.screenManager presentAlert:alert withCompletionHandler:^(NSError * _Nullable error) {
+ if (error != nil) {
+ SDLLogD(@"There was an error presenting the alert: %@", error);
+ }
+ }];
}
+ (void)sendSubtleAlertWithManager:(SDLManager *)sdlManager image:(nullable NSString *)imageName textField1:(NSString *)textField1 textField2:(nullable NSString *)textField2 {
diff --git a/Example Apps/Example ObjC/MenuManager.m b/Example Apps/Example ObjC/MenuManager.m
index b4f370477..be553c459 100644
--- a/Example Apps/Example ObjC/MenuManager.m
+++ b/Example Apps/Example ObjC/MenuManager.m
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Menu Items
+ (SDLMenuCell *)sdlex_menuCellSpeakNameWithManager:(SDLManager *)manager {
- return [[SDLMenuCell alloc] initWithTitle:ACSpeakAppNameMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:SpeakBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACSpeakAppNameMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACSpeakAppNameMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:SpeakBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil voiceCommands:@[ACSpeakAppNameMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
[manager sendRequest:[[SDLSpeak alloc] initWithTTS:ExampleAppNameTTS]];
}];
}
@@ -52,13 +52,13 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray *submenuItems = [[NSMutableArray alloc] init];
NSArray<NSString *> *allVehicleDataTypes = [self sdlex_allVehicleDataTypes];
for (NSString *vehicleDataType in allVehicleDataTypes) {
- SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:vehicleDataType icon:[SDLArtwork artworkWithStaticIcon:SDLStaticIconNameSettings] voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:vehicleDataType secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithStaticIcon:SDLStaticIconNameSettings] secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[VehicleDataManager getAllVehicleDataWithManager:manager triggerSource:triggerSource vehicleDataType:vehicleDataType];
}];
[submenuItems addObject:cell];
}
- return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] submenuLayout:SDLMenuLayoutTiles subCells:submenuItems secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil submenuLayout:SDLMenuLayoutTiles subCells:submenuItems];
}
+ (NSArray<NSString *> *)sdlex_allVehicleDataTypes {
@@ -66,20 +66,20 @@ NS_ASSUME_NONNULL_BEGIN
}
+ (SDLMenuCell *)sdlex_menuCellShowPerformInteractionWithManager:(SDLManager *)manager performManager:(PerformInteractionManager *)performManager {
- return [[SDLMenuCell alloc] initWithTitle:ACShowChoiceSetMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACShowChoiceSetMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACShowChoiceSetMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil voiceCommands:@[ACShowChoiceSetMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
[performManager showWithTriggerSource:triggerSource];
}];
}
+ (SDLMenuCell *)sdlex_menuCellRecordInCarMicrophoneAudioWithManager:(SDLManager *)manager {
AudioManager *audioManager = [[AudioManager alloc] initWithManager:manager];
- return [[SDLMenuCell alloc] initWithTitle:ACRecordInCarMicrophoneAudioMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MicrophoneBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACRecordInCarMicrophoneAudioMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACRecordInCarMicrophoneAudioMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MicrophoneBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil voiceCommands:@[ACRecordInCarMicrophoneAudioMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
[audioManager startRecording];
}];
}
+ (SDLMenuCell *)sdlex_menuCellDialNumberWithManager:(SDLManager *)manager {
- return [[SDLMenuCell alloc] initWithTitle:ACDialPhoneNumberMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:PhoneBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:@[ACDialPhoneNumberMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACDialPhoneNumberMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:PhoneBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil voiceCommands:@[ACDialPhoneNumberMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
if (![RPCPermissionsManager isDialNumberRPCAllowedWithManager:manager]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertDialNumberPermissionsWarningText textField2:nil];
return;
@@ -96,7 +96,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *errorMessage = @"Changing the template failed";
// Non - Media
- SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:@"Non - Media (Default)" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:@"Non - Media (Default)" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[manager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithPredefinedLayout:SDLPredefinedLayoutNonMedia] withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[AlertManager sendAlertWithManager:manager image:nil textField1:errorMessage textField2:nil];
@@ -106,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN
[submenuItems addObject:cell];
// Graphic With Text
- SDLMenuCell *cell2 = [[SDLMenuCell alloc] initWithTitle:@"Graphic With Text" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ SDLMenuCell *cell2 = [[SDLMenuCell alloc] initWithTitle:@"Graphic With Text" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[manager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithPredefinedLayout:SDLPredefinedLayoutGraphicWithText] withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[AlertManager sendAlertWithManager:manager image:nil textField1:errorMessage textField2:nil];
@@ -115,23 +115,23 @@ NS_ASSUME_NONNULL_BEGIN
}];
[submenuItems addObject:cell2];
- return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName icon:nil submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy] secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy]];
}
+ (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager {
NSMutableArray *submenuItems = [NSMutableArray array];
for (int i = 0; i < 75; i++) {
- SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:[NSString stringWithFormat:@"%@ %i", ACSubmenuItemMenuName, i] icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ SDLMenuCell *cell = [[SDLMenuCell alloc] initWithTitle:[NSString stringWithFormat:@"%@ %i", ACSubmenuItemMenuName, i] secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[AlertManager sendAlertWithManager:manager image:nil textField1:[NSString stringWithFormat:@"You selected %@ %i", ACSubmenuItemMenuName, i] textField2:nil];
}];
[submenuItems addObject:cell];
}
- return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy] secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName secondaryText:nil tertiaryText:nil icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] secondaryArtwork:nil submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy]];
}
+ (SDLMenuCell *)sdlex_sliderMenuCellWithManager:(SDLManager *)manager {
- return [[SDLMenuCell alloc] initWithTitle:ACSliderMenuName icon:nil voiceCommands:@[ACSliderMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACSliderMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[ACSliderMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
SDLSlider *sliderRPC = [[SDLSlider alloc] initWithNumTicks:3 position:1 sliderHeader:@"Select a letter" sliderFooters:@[@"A", @"B", @"C"] timeout:10000];
[manager sendRequest:sliderRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if(![response.resultCode isEqualToEnum:SDLResultSuccess]) {
@@ -148,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN
}
+ (SDLMenuCell *)sdlex_scrollableMessageMenuCellWithManager:(SDLManager *)manager {
- return [[SDLMenuCell alloc] initWithTitle:ACScrollableMessageMenuName icon:nil voiceCommands:@[ACScrollableMessageMenuName] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ return [[SDLMenuCell alloc] initWithTitle:ACScrollableMessageMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[ACScrollableMessageMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
SDLScrollableMessage *messageRPC = [[SDLScrollableMessage alloc] initWithMessage:@"This is a scrollable message\nIt can contain many lines"];
[manager sendRequest:messageRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if(![response.resultCode isEqualToEnum:SDLResultSuccess]) {
diff --git a/Example Apps/Example ObjC/ProxyManager.m b/Example Apps/Example ObjC/ProxyManager.m
index 0d13454d7..9cb17a9e0 100644
--- a/Example Apps/Example ObjC/ProxyManager.m
+++ b/Example Apps/Example ObjC/ProxyManager.m
@@ -229,8 +229,7 @@ NS_ASSUME_NONNULL_BEGIN
}
#pragma mark - SDLManagerDelegate
-
-/// Called when the connection beween this app and the module has closed.
+/// Called when the connection between this app and the module has closed.
- (void)managerDidDisconnect {
if (self.state != ProxyStateStopped) {
[self sdlex_updateProxyState:ProxyStateSearchingForConnection];
@@ -318,6 +317,11 @@ NS_ASSUME_NONNULL_BEGIN
return update;
}
+- (BOOL)didReceiveSystemInfo:(SDLSystemInfo *)systemInfo {
+ SDLLogD(@"Example app did receive system info: %@", systemInfo);
+ return YES;
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Example Apps/Example Swift/AlertManager.swift b/Example Apps/Example Swift/AlertManager.swift
index bf0f1af96..71769c51d 100644
--- a/Example Apps/Example Swift/AlertManager.swift
+++ b/Example Apps/Example Swift/AlertManager.swift
@@ -8,6 +8,7 @@
import Foundation
import SmartDeviceLink
+import SmartDeviceLinkSwift
class AlertManager {
/// Sends an alert with up to two lines of text, an image, and a close button that will dismiss the alert when tapped.
@@ -17,18 +18,22 @@ class AlertManager {
/// - textField2: The second line of text in the alert
/// - sdlManager: The SDLManager
class func sendAlert(imageName: String? = nil, textField1: String, textField2: String? = nil, sdlManager: SDLManager) {
- let okSoftButton = SDLSoftButton(type: .text, text: AlertOKButtonText, image: nil, highlighted: true, buttonId: 10000, systemAction: nil, handler: nil)
- let alert = SDLAlert(alertText1: textField1, alertText2: textField2, alertText3: nil, softButtons: [okSoftButton], playTone: true, ttsChunks: nil, duration: 5000, progressIndicator: false, alertIcon: nil, cancelID: 0)
+ let okSoftButton = SDLSoftButtonObject(name: AlertOKButtonText, text: AlertOKButtonText, artwork: nil, handler: nil)
+ let alert = SDLAlertView(text: textField1, buttons: [okSoftButton])
+ alert.secondaryText = textField2
+
+ let alertAudioData = SDLAlertAudioData(speechSynthesizerString: "alert")
+ alertAudioData.playTone = true
+ alert.audio = alertAudioData
if let imageName = imageName {
- sendImage(imageName, sdlManager: sdlManager) { (success, artworkName) in
- if success {
- alert.alertIcon = SDLImage(name: artworkName, isTemplate: true)
- }
- sdlManager.send(alert)
+ alert.icon = SDLArtwork(image: UIImage(named: imageName)!.withRenderingMode(.alwaysTemplate), persistent: false, as: .PNG)
+ }
+
+ sdlManager.screenManager.presentAlert(alert) { error in
+ if let error = error {
+ SDLLog.e("There was an error presenting the alert: \(error.localizedDescription)")
}
- } else {
- sdlManager.send(alert)
}
}
diff --git a/Example Apps/Example Swift/MenuManager.swift b/Example Apps/Example Swift/MenuManager.swift
index f7466f06d..1da1f3ced 100644
--- a/Example Apps/Example Swift/MenuManager.swift
+++ b/Example Apps/Example Swift/MenuManager.swift
@@ -48,7 +48,7 @@ private extension MenuManager {
/// - Parameter manager: The SDL Manager
/// - Returns: A SDLMenuCell object
class func menuCellSpeakName(with manager: SDLManager) -> SDLMenuCell {
- return SDLMenuCell(title: ACSpeakAppNameMenuName, icon: SDLArtwork(image: UIImage(named: SpeakBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), voiceCommands: [ACSpeakAppNameMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { _ in
+ return SDLMenuCell(title: ACSpeakAppNameMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: SpeakBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, voiceCommands: [ACSpeakAppNameMenuName], handler: { _ in
manager.send(request: SDLSpeak(tts: ExampleAppNameTTS), responseHandler: { (_, response, error) in
guard response?.resultCode == .success else { return }
SDLLog.e("Error sending the Speak RPC: \(error?.localizedDescription ?? "no error message")")
@@ -62,12 +62,12 @@ private extension MenuManager {
/// - Returns: A SDLMenuCell object
class func menuCellGetAllVehicleData(with manager: SDLManager) -> SDLMenuCell {
let submenuItems = allVehicleDataTypes.map { submenuName in
- SDLMenuCell(title: submenuName, icon: SDLArtwork(staticIcon: .settings), voiceCommands: nil, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { triggerSource in
+ SDLMenuCell(title: submenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(staticIcon: .settings), secondaryArtwork: nil, voiceCommands: nil, handler: { triggerSource in
VehicleDataManager.getAllVehicleData(with: manager, triggerSource: triggerSource, vehicleDataType: submenuName)
})
}
- return SDLMenuCell(title: ACGetAllVehicleDataMenuName, icon: SDLArtwork(image: UIImage(named: CarBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), submenuLayout: .tiles, subCells: submenuItems, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil)
+ return SDLMenuCell(title: ACGetAllVehicleDataMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: CarBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, submenuLayout: .tiles, subCells: submenuItems)
}
/// A list of all possible vehicle data types
@@ -80,7 +80,7 @@ private extension MenuManager {
/// - Parameter manager: The SDL Manager
/// - Returns: A SDLMenuCell object
class func menuCellShowPerformInteraction(with manager: SDLManager, choiceSetManager: PerformInteractionManager) -> SDLMenuCell {
- return SDLMenuCell(title: ACShowChoiceSetMenuName, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), voiceCommands: [ACShowChoiceSetMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { triggerSource in
+ return SDLMenuCell(title: ACShowChoiceSetMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, voiceCommands: [ACShowChoiceSetMenuName], handler: { triggerSource in
choiceSetManager.show(from: triggerSource)
})
}
@@ -91,7 +91,7 @@ private extension MenuManager {
/// - Returns: A SDLMenuCell object
class func menuCellRecordInCarMicrophoneAudio(with manager: SDLManager) -> SDLMenuCell {
let audioManager = AudioManager(sdlManager: manager)
- return SDLMenuCell(title: ACRecordInCarMicrophoneAudioMenuName, icon: SDLArtwork(image: UIImage(named: MicrophoneBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), voiceCommands: [ACRecordInCarMicrophoneAudioMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { _ in
+ return SDLMenuCell(title: ACRecordInCarMicrophoneAudioMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: MicrophoneBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, voiceCommands: [ACRecordInCarMicrophoneAudioMenuName], handler: { _ in
audioManager.startRecording()
})
}
@@ -101,7 +101,7 @@ private extension MenuManager {
/// - Parameter manager: The SDL Manager
/// - Returns: A SDLMenuCell object
class func menuCellDialNumber(with manager: SDLManager) -> SDLMenuCell {
- return SDLMenuCell(title: ACDialPhoneNumberMenuName, icon: SDLArtwork(image: UIImage(named: PhoneBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), voiceCommands: [ACDialPhoneNumberMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { _ in
+ return SDLMenuCell(title: ACDialPhoneNumberMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: PhoneBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, voiceCommands: [ACDialPhoneNumberMenuName], handler: { _ in
guard RPCPermissionsManager.isDialNumberRPCAllowed(with: manager) else {
AlertManager.sendAlert(textField1: AlertDialNumberPermissionsWarningText, sdlManager: manager)
return
@@ -123,7 +123,7 @@ private extension MenuManager {
/// Non-Media
let submenuTitleNonMedia = "Non - Media (Default)"
- submenuItems.append(SDLMenuCell(title: submenuTitleNonMedia, icon: nil, voiceCommands: nil, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { (triggerSource) in
+ submenuItems.append(SDLMenuCell(title: submenuTitleNonMedia, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in
manager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .nonMedia)) { err in
if err != nil {
AlertManager.sendAlert(textField1: errorMessage, sdlManager: manager)
@@ -134,7 +134,7 @@ private extension MenuManager {
/// Graphic with Text
let submenuTitleGraphicText = "Graphic With Text"
- submenuItems.append(SDLMenuCell(title: submenuTitleGraphicText, icon: nil, voiceCommands: nil, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { (triggerSource) in
+ submenuItems.append(SDLMenuCell(title: submenuTitleGraphicText, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in
manager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .graphicWithText)) { err in
if err != nil {
AlertManager.sendAlert(textField1: errorMessage, sdlManager: manager)
@@ -143,7 +143,7 @@ private extension MenuManager {
}
}))
- return SDLMenuCell(title: ACSubmenuTemplateMenuName, icon: nil, submenuLayout: .list, subCells: submenuItems, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil)
+ return SDLMenuCell(title: ACSubmenuTemplateMenuName, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, submenuLayout: .list, subCells: submenuItems)
}
/// Menu item that opens a submenu when selected
@@ -154,7 +154,7 @@ private extension MenuManager {
var submenuItems = [SDLMenuCell]()
for i in 0 ..< 10 {
let submenuTitle = "Submenu Item \(i)"
- submenuItems.append(SDLMenuCell(title: submenuTitle, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), voiceCommands: nil, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { (triggerSource) in
+ submenuItems.append(SDLMenuCell(title: submenuTitle, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: UIImage(named: MenuBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in
let message = "\(submenuTitle) selected!"
switch triggerSource {
case .menu:
@@ -166,11 +166,11 @@ private extension MenuManager {
}))
}
- return SDLMenuCell(title: ACSubmenuMenuName, icon: SDLArtwork(image: #imageLiteral(resourceName: "choice_set").withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), submenuLayout: .list, subCells: submenuItems, secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil)
+ return SDLMenuCell(title: ACSubmenuMenuName, secondaryText: nil, tertiaryText: nil, icon: SDLArtwork(image: #imageLiteral(resourceName: "choice_set").withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), secondaryArtwork: nil, submenuLayout: .list, subCells: submenuItems)
}
private class func sliderMenuCell(with manager: SDLManager) -> SDLMenuCell {
- return SDLMenuCell(title: ACSliderMenuName, icon: nil, voiceCommands: [ACSliderMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { _ in
+ return SDLMenuCell(title: ACSliderMenuName, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: [ACSliderMenuName], handler: { _ in
let slider = SDLSlider(numTicks: 3, position: 1, sliderHeader: "Select a letter", sliderFooters: ["A", "B", "C"], timeout: 3000)
manager.send(request: slider, responseHandler: { (request, response, error) in
guard let response = response else { return }
@@ -189,7 +189,7 @@ private extension MenuManager {
}
private class func scrollableMessageMenuCell(with manager: SDLManager) -> SDLMenuCell {
- return SDLMenuCell(title: ACScrollableMessageMenuName, icon: nil, voiceCommands: [ACScrollableMessageMenuName], secondaryText: nil, tertiaryText: nil, secondaryArtwork: nil, handler: { _ in
+ return SDLMenuCell(title: ACScrollableMessageMenuName, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: [ACScrollableMessageMenuName], handler: { _ in
let scrollableMessage = SDLScrollableMessage(message: "This is a scrollable message\nIt can contain many lines")
manager.send(request: scrollableMessage, responseHandler: { (request, response, error) in
guard let response = response else { return }
diff --git a/Example Apps/Example Swift/ProxyManager.swift b/Example Apps/Example Swift/ProxyManager.swift
index 8a53e7c76..6c04e57fa 100644
--- a/Example Apps/Example Swift/ProxyManager.swift
+++ b/Example Apps/Example Swift/ProxyManager.swift
@@ -146,8 +146,8 @@ private extension ProxyManager {
// MARK: - SDLManagerDelegate
extension ProxyManager: SDLManagerDelegate {
- /// Called when the connection beween this app and the module has closed.
- func managerDidDisconnect() {
+ /// Called when the connection between this app and the module has closed.
+ func managerDidDisconnect() {
if delegate?.proxyState != .some(.stopped) {
delegate?.didChangeProxyState(ProxyState.searching)
}
@@ -234,6 +234,14 @@ extension ProxyManager: SDLManagerDelegate {
return update
}
+
+ /// Called when connected module information becomes available
+ /// - Parameter systemInfo: The connected module's information
+ /// - Returns: True to continue connecting, false to disconnect immediately
+ func didReceive(systemInfo: SDLSystemInfo) -> Bool {
+ SDLLog.d("Example app got system info: \(systemInfo)")
+ return true
+ }
}
// MARK: - SDL UI
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index ef875dcaa..54e0ef74e 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -284,6 +284,7 @@
2BF2F85220ED068200A26EF2 /* SDLAudioStreamingIndicatorSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BF2F85120ED068200A26EF2 /* SDLAudioStreamingIndicatorSpec.m */; };
4A1B036F24CF484E008C6B13 /* SDLDriverDistractionCapabilitySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A1B036E24CF484E008C6B13 /* SDLDriverDistractionCapabilitySpec.m */; };
4A1FA09B25114833006B7851 /* SDLErrorConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A1FA09A25114833006B7851 /* SDLErrorConstants.m */; };
+ 4A39C6FA25E84C87005C8943 /* SDLKeyboardCapabilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9D9DF25D2571000CDFD21 /* SDLKeyboardCapabilities.m */; };
4A40254124FFDA660080E159 /* SDLTextAndGraphicState.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A40253D24FFDA660080E159 /* SDLTextAndGraphicState.m */; };
4A40254224FFDA660080E159 /* SDLTextAndGraphicUpdateOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A40253E24FFDA660080E159 /* SDLTextAndGraphicUpdateOperation.h */; };
4A40254324FFDA660080E159 /* SDLTextAndGraphicUpdateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A40253F24FFDA660080E159 /* SDLTextAndGraphicUpdateOperation.m */; };
@@ -512,6 +513,9 @@
4A8BD3CD24F999BE000945E3 /* TestSubscribeButtonObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A8BD3CC24F999BE000945E3 /* TestSubscribeButtonObserver.m */; };
4A8BD3D024FE7CF1000945E3 /* SDLPermissionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8BD3CE24FE7CF1000945E3 /* SDLPermissionManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
4A8BD3D124FE7CF1000945E3 /* SDLPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A8BD3CF24FE7CF1000945E3 /* SDLPermissionManager.m */; };
+ 4AAB6A1225E57BEA0017A5A7 /* SDLSystemInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AAB6A1025E57BEA0017A5A7 /* SDLSystemInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4AAB6A1325E57BEA0017A5A7 /* SDLSystemInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AAB6A1125E57BEA0017A5A7 /* SDLSystemInfo.m */; };
+ 4AAB6A2325E69D010017A5A7 /* SDLSystemInfoSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AAB6A2225E69D010017A5A7 /* SDLSystemInfoSpec.m */; };
4ABB24BA24F592620061BF55 /* NSMutableArray+Safe.h in Headers */ = {isa = PBXBuildFile; fileRef = 4ABB24B224F592620061BF55 /* NSMutableArray+Safe.h */; };
4ABB24BB24F592620061BF55 /* NSMutableArray+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ABB24B324F592620061BF55 /* NSMutableArray+Safe.m */; };
4ABB24BC24F592620061BF55 /* NSBundle+SDLBundle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ABB24B424F592620061BF55 /* NSBundle+SDLBundle.m */; };
@@ -1565,6 +1569,11 @@
8815D0F022330765000F24E6 /* SDLRPCRequestNotificationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C23E8522297BD500EA171F /* SDLRPCRequestNotificationSpec.m */; };
8816772922208B82001FACFF /* SDLNavigationInstructionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8816772822208B82001FACFF /* SDLNavigationInstructionSpec.m */; };
8818ADDD2100FE0C007D6F19 /* SDLTurnSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8818ADDC2100FE0C007D6F19 /* SDLTurnSignalSpec.m */; };
+ 881BBF50255AC27000761B7E /* SDLAlertView.h in Headers */ = {isa = PBXBuildFile; fileRef = 881BBF4E255AC27000761B7E /* SDLAlertView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 881BBF51255AC27000761B7E /* SDLAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 881BBF4F255AC27000761B7E /* SDLAlertView.m */; };
+ 881BBF5B255ADB8300761B7E /* SDLAlertViewSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 881BBF5A255ADB8300761B7E /* SDLAlertViewSpec.m */; };
+ 881BBF60255B1C1E00761B7E /* SDLAlertManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 881BBF5E255B1C1E00761B7E /* SDLAlertManager.h */; };
+ 881BBF61255B1C1E00761B7E /* SDLAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 881BBF5F255B1C1E00761B7E /* SDLAlertManager.m */; };
881F388D22D904BE00DF6DCE /* SDLCancelInteractionResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 881F388C22D904BE00DF6DCE /* SDLCancelInteractionResponseSpec.m */; };
8829568B207CF68800EF056C /* SmartDeviceLink.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D61FA1C1A84237100846EE7 /* SmartDeviceLink.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
88295693207CF68800EF056C /* SmartDeviceLink.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5D61FA1C1A84237100846EE7 /* SmartDeviceLink.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -1587,6 +1596,8 @@
8855F9EC220CBFB700A5C897 /* SDLGetFileSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8855F9EB220CBFB700A5C897 /* SDLGetFileSpec.m */; };
8863747E22D650DE00D2671F /* SDLCloseApplicationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8863747D22D650DE00D2671F /* SDLCloseApplicationSpec.m */; };
88665B6C220B796A00D9DA77 /* SDLPerformAppServiceInteractionResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88665B6B220B796A00D9DA77 /* SDLPerformAppServiceInteractionResponseSpec.m */; };
+ 886E413D2565D0D200F073B8 /* SDLPresentAlertOperationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 886E413C2565D0D200F073B8 /* SDLPresentAlertOperationSpec.m */; };
+ 886E41412565D11200F073B8 /* SDLAlertManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 886E41402565D11200F073B8 /* SDLAlertManagerSpec.m */; };
8877F5EB1F34A3BE00DC128A /* SDLSendHapticDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */; };
8877F5F11F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */; };
887BE4D422272B2200B397C2 /* SDLControlFramePayloadConstantsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 887BE4D322272B2200B397C2 /* SDLControlFramePayloadConstantsSpec.m */; };
@@ -1602,6 +1613,12 @@
8881AFBB2225E7FA00EA870B /* SDLGetCloudAppPropertiesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8881AFBA2225E7FA00EA870B /* SDLGetCloudAppPropertiesSpec.m */; };
8881AFC12225EB9300EA870B /* SDLGetCloudAppPropertiesResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8881AFC02225EB9300EA870B /* SDLGetCloudAppPropertiesResponseSpec.m */; };
8886EB982111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8886EB972111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m */; };
+ 8889C2ED2559C7E2004F5966 /* SDLAudioDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8889C2EC2559C7E2004F5966 /* SDLAudioDataSpec.m */; };
+ 8889C2F42559CFAF004F5966 /* SDLAlertAudioData.h in Headers */ = {isa = PBXBuildFile; fileRef = 8889C2F22559CFAF004F5966 /* SDLAlertAudioData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8889C2F52559CFAF004F5966 /* SDLAlertAudioData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8889C2F32559CFAF004F5966 /* SDLAlertAudioData.m */; };
+ 8889C2FC2559CFE3004F5966 /* SDLAudioData.m in Sources */ = {isa = PBXBuildFile; fileRef = 8889C2FA2559CFE2004F5966 /* SDLAudioData.m */; };
+ 8889C2FD2559CFE3004F5966 /* SDLAudioData.h in Headers */ = {isa = PBXBuildFile; fileRef = 8889C2FB2559CFE3004F5966 /* SDLAudioData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8889C3052559E109004F5966 /* SDLAlertAudioDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8889C3042559E109004F5966 /* SDLAlertAudioDataSpec.m */; };
888F8700221DF4880052FE4C /* SDLAsynchronousRPCOperationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 888F86FF221DF4880052FE4C /* SDLAsynchronousRPCOperationSpec.m */; };
889D0B9624D065EE008AD494 /* SDLSubtleAlertResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 889D0B9524D065EE008AD494 /* SDLSubtleAlertResponseSpec.m */; };
889D0B9824D06E52008AD494 /* SDLSubtleAlertSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 889D0B9724D06E52008AD494 /* SDLSubtleAlertSpec.m */; };
@@ -1631,6 +1648,8 @@
88D0E5D624786580009469AB /* SDLSubscribeButtonManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D0E5D524786580009469AB /* SDLSubscribeButtonManagerSpec.m */; };
88D0E5D824786770009469AB /* SDLSubscribeButtonObserverSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D0E5D724786770009469AB /* SDLSubscribeButtonObserverSpec.m */; };
88D2AAE41F682BB20078D5B2 /* SDLLogConstantsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D2AAE31F682BB20078D5B2 /* SDLLogConstantsSpec.m */; };
+ 88D79EED255D8D5B005FACB1 /* SDLPresentAlertOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 88D79EEB255D8D5B005FACB1 /* SDLPresentAlertOperation.h */; };
+ 88D79EEE255D8D5B005FACB1 /* SDLPresentAlertOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D79EEC255D8D5B005FACB1 /* SDLPresentAlertOperation.m */; };
88DDD0F9229ECA57002F9623 /* SDLIAPConstantsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88DDD0F8229ECA57002F9623 /* SDLIAPConstantsSpec.m */; };
88DF998D22035CC600477AC1 /* EAAccessory+OCMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 88DF998C22035CC600477AC1 /* EAAccessory+OCMock.m */; };
88DF998F22035D1700477AC1 /* SDLIAPSessionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88DF998E22035D1700477AC1 /* SDLIAPSessionSpec.m */; };
@@ -1688,6 +1707,14 @@
B38D8E7E24A118BD00B977D0 /* SDLGearStatusSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B38D8E7D24A118BD00B977D0 /* SDLGearStatusSpec.m */; };
B38D8E8024A1E3D000B977D0 /* SDLTransmissionTypeSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B38D8E7F24A1E3D000B977D0 /* SDLTransmissionTypeSpec.m */; };
B38D8E8224A1F53500B977D0 /* SDLCapacityUnitSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B38D8E8124A1F53500B977D0 /* SDLCapacityUnitSpec.m */; };
+ B3A9D9E225D2571000CDFD21 /* SDLKeyboardCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A9D9E025D2571000CDFD21 /* SDLKeyboardCapabilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B3A9D9E725D2578F00CDFD21 /* SDLKeyboardLayoutCapability.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9D9E525D2578F00CDFD21 /* SDLKeyboardLayoutCapability.m */; };
+ B3A9D9E825D2578F00CDFD21 /* SDLKeyboardLayoutCapability.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A9D9E625D2578F00CDFD21 /* SDLKeyboardLayoutCapability.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B3A9D9ED25D2586C00CDFD21 /* SDLKeyboardInputMask.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A9D9EB25D2586C00CDFD21 /* SDLKeyboardInputMask.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B3A9D9EE25D2586C00CDFD21 /* SDLKeyboardInputMask.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9D9EC25D2586C00CDFD21 /* SDLKeyboardInputMask.m */; };
+ B3A9DA0425D26D8500CDFD21 /* SDLKeyboardInputMaskSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9DA0325D26D8500CDFD21 /* SDLKeyboardInputMaskSpec.m */; };
+ B3A9DA0A25D26E1800CDFD21 /* SDLKeyboardCapabilitiesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9DA0925D26E1800CDFD21 /* SDLKeyboardCapabilitiesSpec.m */; };
+ B3A9DA1225D270EA00CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9DA1125D270E900CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m */; };
B3EC9E6E2579AA010039F3AA /* SDLClimateDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3EC9E6D2579AA010039F3AA /* SDLClimateDataSpec.m */; };
B3F7918324E062C200DB5CAF /* SDLGetVehicleDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 162E824C1A9BDE8A00906325 /* SDLGetVehicleDataSpec.m */; };
C9707D1825DEE786009D00F2 /* NSArray+Extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = C9707D1625DEE786009D00F2 /* NSArray+Extensions.h */; };
@@ -2326,6 +2353,9 @@
4A8BD3CC24F999BE000945E3 /* TestSubscribeButtonObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestSubscribeButtonObserver.m; sourceTree = "<group>"; };
4A8BD3CE24FE7CF1000945E3 /* SDLPermissionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLPermissionManager.h; path = public/SDLPermissionManager.h; sourceTree = "<group>"; };
4A8BD3CF24FE7CF1000945E3 /* SDLPermissionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLPermissionManager.m; path = public/SDLPermissionManager.m; sourceTree = "<group>"; };
+ 4AAB6A1025E57BEA0017A5A7 /* SDLSystemInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLSystemInfo.h; path = public/SDLSystemInfo.h; sourceTree = "<group>"; };
+ 4AAB6A1125E57BEA0017A5A7 /* SDLSystemInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLSystemInfo.m; path = public/SDLSystemInfo.m; sourceTree = "<group>"; };
+ 4AAB6A2225E69D010017A5A7 /* SDLSystemInfoSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLSystemInfoSpec.m; path = DevAPISpecs/SDLSystemInfoSpec.m; sourceTree = "<group>"; };
4ABB24B224F592620061BF55 /* NSMutableArray+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableArray+Safe.h"; path = "private/NSMutableArray+Safe.h"; sourceTree = "<group>"; };
4ABB24B324F592620061BF55 /* NSMutableArray+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSMutableArray+Safe.m"; path = "private/NSMutableArray+Safe.m"; sourceTree = "<group>"; };
4ABB24B424F592620061BF55 /* NSBundle+SDLBundle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSBundle+SDLBundle.m"; path = "private/NSBundle+SDLBundle.m"; sourceTree = "<group>"; };
@@ -3425,6 +3455,11 @@
880E35B72088F78E00181259 /* SDLSystemCapabilityManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityManagerSpec.m; sourceTree = "<group>"; };
8816772822208B82001FACFF /* SDLNavigationInstructionSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLNavigationInstructionSpec.m; sourceTree = "<group>"; };
8818ADDC2100FE0C007D6F19 /* SDLTurnSignalSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLTurnSignalSpec.m; sourceTree = "<group>"; };
+ 881BBF4E255AC27000761B7E /* SDLAlertView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLAlertView.h; path = public/SDLAlertView.h; sourceTree = "<group>"; };
+ 881BBF4F255AC27000761B7E /* SDLAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLAlertView.m; path = public/SDLAlertView.m; sourceTree = "<group>"; };
+ 881BBF5A255ADB8300761B7E /* SDLAlertViewSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAlertViewSpec.m; sourceTree = "<group>"; };
+ 881BBF5E255B1C1E00761B7E /* SDLAlertManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLAlertManager.h; path = private/SDLAlertManager.h; sourceTree = "<group>"; };
+ 881BBF5F255B1C1E00761B7E /* SDLAlertManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLAlertManager.m; path = private/SDLAlertManager.m; sourceTree = "<group>"; };
881F388C22D904BE00DF6DCE /* SDLCancelInteractionResponseSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLCancelInteractionResponseSpec.m; sourceTree = "<group>"; };
88295697207CF68800EF056C /* SDL Example Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDL Example Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; };
882FAC4C2209D7EF0062385D /* SDLAppServiceDataSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAppServiceDataSpec.m; sourceTree = "<group>"; };
@@ -3447,6 +3482,8 @@
8855F9EB220CBFB700A5C897 /* SDLGetFileSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLGetFileSpec.m; sourceTree = "<group>"; };
8863747D22D650DE00D2671F /* SDLCloseApplicationSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLCloseApplicationSpec.m; sourceTree = "<group>"; };
88665B6B220B796A00D9DA77 /* SDLPerformAppServiceInteractionResponseSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLPerformAppServiceInteractionResponseSpec.m; sourceTree = "<group>"; };
+ 886E413C2565D0D200F073B8 /* SDLPresentAlertOperationSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLPresentAlertOperationSpec.m; sourceTree = "<group>"; };
+ 886E41402565D11200F073B8 /* SDLAlertManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAlertManagerSpec.m; sourceTree = "<group>"; };
8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataSpec.m; sourceTree = "<group>"; };
8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataResponseSpec.m; sourceTree = "<group>"; };
887BE4D322272B2200B397C2 /* SDLControlFramePayloadConstantsSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLControlFramePayloadConstantsSpec.m; sourceTree = "<group>"; };
@@ -3456,6 +3493,12 @@
8881AFBA2225E7FA00EA870B /* SDLGetCloudAppPropertiesSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLGetCloudAppPropertiesSpec.m; sourceTree = "<group>"; };
8881AFC02225EB9300EA870B /* SDLGetCloudAppPropertiesResponseSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLGetCloudAppPropertiesResponseSpec.m; sourceTree = "<group>"; };
8886EB972111F4FA008294A5 /* SDLFileManagerConfigurationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLFileManagerConfigurationSpec.m; sourceTree = "<group>"; };
+ 8889C2EC2559C7E2004F5966 /* SDLAudioDataSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAudioDataSpec.m; sourceTree = "<group>"; };
+ 8889C2F22559CFAF004F5966 /* SDLAlertAudioData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLAlertAudioData.h; path = public/SDLAlertAudioData.h; sourceTree = "<group>"; };
+ 8889C2F32559CFAF004F5966 /* SDLAlertAudioData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLAlertAudioData.m; path = public/SDLAlertAudioData.m; sourceTree = "<group>"; };
+ 8889C2FA2559CFE2004F5966 /* SDLAudioData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLAudioData.m; path = public/SDLAudioData.m; sourceTree = "<group>"; };
+ 8889C2FB2559CFE3004F5966 /* SDLAudioData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLAudioData.h; path = public/SDLAudioData.h; sourceTree = "<group>"; };
+ 8889C3042559E109004F5966 /* SDLAlertAudioDataSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAlertAudioDataSpec.m; sourceTree = "<group>"; };
888F86FF221DF4880052FE4C /* SDLAsynchronousRPCOperationSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLAsynchronousRPCOperationSpec.m; sourceTree = "<group>"; };
889D0B9524D065EE008AD494 /* SDLSubtleAlertResponseSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSubtleAlertResponseSpec.m; sourceTree = "<group>"; };
889D0B9724D06E52008AD494 /* SDLSubtleAlertSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSubtleAlertSpec.m; sourceTree = "<group>"; };
@@ -3487,6 +3530,8 @@
88D0E5D524786580009469AB /* SDLSubscribeButtonManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSubscribeButtonManagerSpec.m; sourceTree = "<group>"; };
88D0E5D724786770009469AB /* SDLSubscribeButtonObserverSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSubscribeButtonObserverSpec.m; sourceTree = "<group>"; };
88D2AAE31F682BB20078D5B2 /* SDLLogConstantsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLLogConstantsSpec.m; sourceTree = "<group>"; };
+ 88D79EEB255D8D5B005FACB1 /* SDLPresentAlertOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLPresentAlertOperation.h; path = private/SDLPresentAlertOperation.h; sourceTree = "<group>"; };
+ 88D79EEC255D8D5B005FACB1 /* SDLPresentAlertOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLPresentAlertOperation.m; path = private/SDLPresentAlertOperation.m; sourceTree = "<group>"; };
88DDD0F8229ECA57002F9623 /* SDLIAPConstantsSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLIAPConstantsSpec.m; sourceTree = "<group>"; };
88DF998C22035CC600477AC1 /* EAAccessory+OCMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "EAAccessory+OCMock.m"; sourceTree = "<group>"; };
88DF998E22035D1700477AC1 /* SDLIAPSessionSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLIAPSessionSpec.m; sourceTree = "<group>"; };
@@ -3545,6 +3590,15 @@
B38D8E7D24A118BD00B977D0 /* SDLGearStatusSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLGearStatusSpec.m; sourceTree = "<group>"; };
B38D8E7F24A1E3D000B977D0 /* SDLTransmissionTypeSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLTransmissionTypeSpec.m; sourceTree = "<group>"; };
B38D8E8124A1F53500B977D0 /* SDLCapacityUnitSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLCapacityUnitSpec.m; sourceTree = "<group>"; };
+ B3A9D9DF25D2571000CDFD21 /* SDLKeyboardCapabilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLKeyboardCapabilities.m; path = public/SDLKeyboardCapabilities.m; sourceTree = "<group>"; };
+ B3A9D9E025D2571000CDFD21 /* SDLKeyboardCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLKeyboardCapabilities.h; path = public/SDLKeyboardCapabilities.h; sourceTree = "<group>"; };
+ B3A9D9E525D2578F00CDFD21 /* SDLKeyboardLayoutCapability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLKeyboardLayoutCapability.m; path = public/SDLKeyboardLayoutCapability.m; sourceTree = "<group>"; };
+ B3A9D9E625D2578F00CDFD21 /* SDLKeyboardLayoutCapability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLKeyboardLayoutCapability.h; path = public/SDLKeyboardLayoutCapability.h; sourceTree = "<group>"; };
+ B3A9D9EB25D2586C00CDFD21 /* SDLKeyboardInputMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLKeyboardInputMask.h; path = public/SDLKeyboardInputMask.h; sourceTree = "<group>"; };
+ B3A9D9EC25D2586C00CDFD21 /* SDLKeyboardInputMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLKeyboardInputMask.m; path = public/SDLKeyboardInputMask.m; sourceTree = "<group>"; };
+ B3A9DA0325D26D8500CDFD21 /* SDLKeyboardInputMaskSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLKeyboardInputMaskSpec.m; sourceTree = "<group>"; };
+ B3A9DA0925D26E1800CDFD21 /* SDLKeyboardCapabilitiesSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLKeyboardCapabilitiesSpec.m; sourceTree = "<group>"; };
+ B3A9DA1125D270E900CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLKeyboardLayoutCapabilitySpec.m; sourceTree = "<group>"; };
B3EC9E6D2579AA010039F3AA /* SDLClimateDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLClimateDataSpec.m; sourceTree = "<group>"; };
BB3C600D221AEF37007DD4CA /* NSMutableDictionary+StoreSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSMutableDictionary+StoreSpec.m"; path = "DevAPISpecs/NSMutableDictionary+StoreSpec.m"; sourceTree = "<group>"; };
C9707D1625DEE786009D00F2 /* NSArray+Extensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSArray+Extensions.h"; path = "private/NSArray+Extensions.h"; sourceTree = "<group>"; };
@@ -3765,6 +3819,7 @@
162E81FD1A9BDE8A00906325 /* SDLImageTypeSpec.m */,
162E81FE1A9BDE8A00906325 /* SDLInteractionModeSpec.m */,
162E81FF1A9BDE8A00906325 /* SDLKeyboardEventSpec.m */,
+ B3A9DA0325D26D8500CDFD21 /* SDLKeyboardInputMaskSpec.m */,
162E82001A9BDE8A00906325 /* SDLKeyboardLayoutSpec.m */,
162E82011A9BDE8A00906325 /* SDLKeypressModeSpec.m */,
162E82021A9BDE8A00906325 /* SDLLanguageSpec.m */,
@@ -4061,6 +4116,8 @@
162E829F1A9BDE8A00906325 /* SDLImageFieldSpec.m */,
5DB202261F5F2D030061D189 /* SDLImageResolutionSpec.m */,
162E82A01A9BDE8A00906325 /* SDLImageSpec.m */,
+ B3A9DA0925D26E1800CDFD21 /* SDLKeyboardCapabilitiesSpec.m */,
+ B3A9DA1125D270E900CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m */,
162E82A11A9BDE8A00906325 /* SDLKeyboardPropertiesSpec.m */,
1EAA476B2036A52F000FE74B /* SDLLightCapabilitiesSpec.m */,
1EAA476920369ECC000FE74B /* SDLLightControlCapabilitiesSpec.m */,
@@ -4326,6 +4383,15 @@
name = "Status Manager";
sourceTree = "<group>";
};
+ 4AAB6A0F25E57B2D0017A5A7 /* Utilities */ = {
+ isa = PBXGroup;
+ children = (
+ 4AAB6A1025E57BEA0017A5A7 /* SDLSystemInfo.h */,
+ 4AAB6A1125E57BEA0017A5A7 /* SDLSystemInfo.m */,
+ );
+ name = Utilities;
+ sourceTree = "<group>";
+ };
4AD1F16A2559952D00637FE1 /* Voice Command */ = {
isa = PBXGroup;
children = (
@@ -4376,6 +4442,7 @@
5D0A736F203F0C450001595D /* Screen */ = {
isa = PBXGroup;
children = (
+ 8889C2E12559AE6C004F5966 /* Alert */,
5D92935720B33D3C00FCC775 /* Choice Set */,
5D339CE5207C0651000CC364 /* Menu */,
5D0A737F203F23D10001595D /* Soft Button */,
@@ -4441,16 +4508,17 @@
5D1654541D3E753100554D93 /* Lifecycle */ = {
isa = PBXGroup;
children = (
- 5D1654551D3E754F00554D93 /* SDLLifecycleManagerSpec.m */,
888F86FF221DF4880052FE4C /* SDLAsynchronousRPCOperationSpec.m */,
5D60DF23202B7A80001EDA01 /* SDLAsynchronousRPCRequestOperationSpec.m */,
- 5D60DF25202B7A97001EDA01 /* SDLSequentialRPCRequestOperationSpec.m */,
88A1CF1D21669AC7001ACC75 /* SDLLifecycleConfigurationUpdateSpec.m */,
+ 5D1654551D3E754F00554D93 /* SDLLifecycleManagerSpec.m */,
+ 4A457DD424A3C16E00386CBA /* SDLLifecycleMobileHMIStateHandlerSpec.m */,
4A457DC224A2933E00386CBA /* SDLLifecycleRPCAdapterSpec.m */,
4A457DD224A3886700386CBA /* SDLLifecycleSyncPDataHandlerSpec.m */,
- 4A457DD424A3C16E00386CBA /* SDLLifecycleMobileHMIStateHandlerSpec.m */,
4A457DD624A3CCED00386CBA /* SDLLifecycleSystemRequestHandlerSpec.m */,
4A457DD824A5137100386CBA /* SDLLifecycleProtocolHandlerSpec.m */,
+ 5D60DF25202B7A97001EDA01 /* SDLSequentialRPCRequestOperationSpec.m */,
+ 4AAB6A2225E69D010017A5A7 /* SDLSystemInfoSpec.m */,
);
name = Lifecycle;
sourceTree = "<group>";
@@ -4463,6 +4531,7 @@
4A3BA4E324900962003E56B8 /* Custom RPC Handlers */,
4A3BA4E9249147E6003E56B8 /* Protocol Delegate Handler */,
5D07C0342044AD1900D1ECDC /* Request Operations */,
+ 4AAB6A0F25E57B2D0017A5A7 /* Utilities */,
4ABB253924F7E46A0061BF55 /* SDLLifecycleManager.h */,
4ABB253824F7E46A0061BF55 /* SDLLifecycleManager.m */,
);
@@ -4472,6 +4541,7 @@
5D1BF6AA2047429C00D36881 /* Utilities */ = {
isa = PBXGroup;
children = (
+ 8889C2E22559AE82004F5966 /* Audio */,
4ABB25D024F7E7630061BF55 /* SDLImageField+ScreenManagerExtensions.h */,
4ABB25D124F7E7630061BF55 /* SDLImageField+ScreenManagerExtensions.m */,
4ABB25D224F7E7630061BF55 /* SDLTextField+ScreenManagerExtensions.h */,
@@ -5135,6 +5205,12 @@
4ABB2B9824F850AD0061BF55 /* SDLImageField.m */,
4ABB2B9B24F850AD0061BF55 /* SDLImageResolution.h */,
4ABB2B9124F850AC0061BF55 /* SDLImageResolution.m */,
+ B3A9D9E025D2571000CDFD21 /* SDLKeyboardCapabilities.h */,
+ B3A9D9DF25D2571000CDFD21 /* SDLKeyboardCapabilities.m */,
+ B3A9D9EB25D2586C00CDFD21 /* SDLKeyboardInputMask.h */,
+ B3A9D9EC25D2586C00CDFD21 /* SDLKeyboardInputMask.m */,
+ B3A9D9E625D2578F00CDFD21 /* SDLKeyboardLayoutCapability.h */,
+ B3A9D9E525D2578F00CDFD21 /* SDLKeyboardLayoutCapability.m */,
4ABB2B9224F850AC0061BF55 /* SDLLightCapabilities.h */,
4ABB2B9624F850AD0061BF55 /* SDLLightCapabilities.m */,
4ABB2B8F24F850AB0061BF55 /* SDLLightControlCapabilities.h */,
@@ -6219,11 +6295,13 @@
5DAD5F8120507DE40025624C /* Screen */ = {
isa = PBXGroup;
children = (
+ 8889C2EB2559C7AA004F5966 /* Alert */,
5DE35E4320CAFBEA0034BE5A /* Choice Set */,
5DF40B24208FA7C500DD6FDA /* Menu */,
5DAD5F8220507DED0025624C /* Soft Button */,
88D0E5D42478656B009469AB /* Subscribe Button */,
5DAD5F8320507DF30025624C /* Text and Graphic */,
+ 8889C3082559E11F004F5966 /* Utilities */,
4AD1F16A2559952D00637FE1 /* Voice Command */,
5DAD5F8420507E1F0025624C /* SDLScreenManagerSpec.m */,
);
@@ -6734,6 +6812,48 @@
name = "Data Session";
sourceTree = "<group>";
};
+ 8889C2E12559AE6C004F5966 /* Alert */ = {
+ isa = PBXGroup;
+ children = (
+ 88D79EEA255D87F8005FACB1 /* Operations */,
+ 8889C2F22559CFAF004F5966 /* SDLAlertAudioData.h */,
+ 8889C2F32559CFAF004F5966 /* SDLAlertAudioData.m */,
+ 881BBF4E255AC27000761B7E /* SDLAlertView.h */,
+ 881BBF4F255AC27000761B7E /* SDLAlertView.m */,
+ 881BBF5E255B1C1E00761B7E /* SDLAlertManager.h */,
+ 881BBF5F255B1C1E00761B7E /* SDLAlertManager.m */,
+ );
+ name = Alert;
+ sourceTree = "<group>";
+ };
+ 8889C2E22559AE82004F5966 /* Audio */ = {
+ isa = PBXGroup;
+ children = (
+ 8889C2FB2559CFE3004F5966 /* SDLAudioData.h */,
+ 8889C2FA2559CFE2004F5966 /* SDLAudioData.m */,
+ );
+ name = Audio;
+ sourceTree = "<group>";
+ };
+ 8889C2EB2559C7AA004F5966 /* Alert */ = {
+ isa = PBXGroup;
+ children = (
+ 8889C3042559E109004F5966 /* SDLAlertAudioDataSpec.m */,
+ 881BBF5A255ADB8300761B7E /* SDLAlertViewSpec.m */,
+ 886E413C2565D0D200F073B8 /* SDLPresentAlertOperationSpec.m */,
+ 886E41402565D11200F073B8 /* SDLAlertManagerSpec.m */,
+ );
+ name = Alert;
+ sourceTree = "<group>";
+ };
+ 8889C3082559E11F004F5966 /* Utilities */ = {
+ isa = PBXGroup;
+ children = (
+ 8889C2EC2559C7E2004F5966 /* SDLAudioDataSpec.m */,
+ );
+ name = Utilities;
+ sourceTree = "<group>";
+ };
88A098AB2476F08F00A50005 /* Subscribe Button */ = {
isa = PBXGroup;
children = (
@@ -6807,6 +6927,15 @@
name = "Subscribe Button";
sourceTree = "<group>";
};
+ 88D79EEA255D87F8005FACB1 /* Operations */ = {
+ isa = PBXGroup;
+ children = (
+ 88D79EEB255D8D5B005FACB1 /* SDLPresentAlertOperation.h */,
+ 88D79EEC255D8D5B005FACB1 /* SDLPresentAlertOperation.m */,
+ );
+ name = Operations;
+ sourceTree = "<group>";
+ };
88DF998A22035CA400477AC1 /* TCP */ = {
isa = PBXGroup;
children = (
@@ -7063,6 +7192,7 @@
4ABB28FE24F82BE90061BF55 /* SDLAddSubMenu.h in Headers */,
4ABB299624F845440061BF55 /* SDLRegisterAppInterface.h in Headers */,
4ABB27DE24F800CA0061BF55 /* SDLPredefinedLayout.h in Headers */,
+ 88D79EED255D8D5B005FACB1 /* SDLPresentAlertOperation.h in Headers */,
4ABB27E424F800CA0061BF55 /* SDLPrerecordedSpeech.h in Headers */,
4ABB2A2E24F847980061BF55 /* SDLDeleteCommandResponse.h in Headers */,
4ABB277524F7FE910061BF55 /* SDLIgnitionStatus.h in Headers */,
@@ -7112,6 +7242,7 @@
5D9FDA991F2A7D3F00A495C8 /* emhashmap.h in Headers */,
4ABB255F24F7E59E0061BF55 /* SDLPermissionConstants.h in Headers */,
4ABB270324F7FB8F0061BF55 /* SDLButtonName.h in Headers */,
+ 881BBF50255AC27000761B7E /* SDLAlertView.h in Headers */,
4ABB25B324F7E6F60061BF55 /* SDLSoftButtonTransitionOperation.h in Headers */,
4ABB24C624F592900061BF55 /* SDLError.h in Headers */,
5D9FDA901F2A7D3400A495C8 /* bson_array.h in Headers */,
@@ -7164,6 +7295,7 @@
4ABB2AB024F847F40061BF55 /* SDLSetCloudAppPropertiesResponse.h in Headers */,
4ABB28C524F82A6A0061BF55 /* SDLOnEncodedSyncPData.h in Headers */,
4ABB2A5924F847B10061BF55 /* SDLGetCloudAppPropertiesResponse.h in Headers */,
+ 4AAB6A1225E57BEA0017A5A7 /* SDLSystemInfo.h in Headers */,
4ABB29BF24F845DB0061BF55 /* SDLSetMediaClockTimer.h in Headers */,
4A8BD39324F94731000945E3 /* SDLIAPTransport.h in Headers */,
4ABB2A2024F847980061BF55 /* SDLButtonPressResponse.h in Headers */,
@@ -7199,6 +7331,7 @@
4A8BD33824F945B4000945E3 /* SDLControlFramePayloadConstants.h in Headers */,
4ABB256724F7E5B80061BF55 /* SDLRPCPermissionStatus.h in Headers */,
4ABB286724F828E00061BF55 /* SDLVehicleDataStatus.h in Headers */,
+ 8889C2F42559CFAF004F5966 /* SDLAlertAudioData.h in Headers */,
4A8BD25024F93135000945E3 /* SDLMetadataTags.h in Headers */,
4ABB2A3424F847980061BF55 /* SDLCancelInteractionResponse.h in Headers */,
4ABB2AF424F849CF0061BF55 /* SDLGenericResponse.h in Headers */,
@@ -7258,6 +7391,7 @@
4ABB275224F7FD9C0061BF55 /* SDLFuelCutoffStatus.h in Headers */,
4ABB24BE24F592620061BF55 /* NSBundle+SDLBundle.h in Headers */,
4ABB286124F828E00061BF55 /* SDLVehicleDataResultCode.h in Headers */,
+ B3A9D9E825D2578F00CDFD21 /* SDLKeyboardLayoutCapability.h in Headers */,
4ABB2BA024F850AE0061BF55 /* SDLLightCapabilities.h in Headers */,
4ABB284124F828630061BF55 /* SDLTurnSignal.h in Headers */,
4ABB299D24F845440061BF55 /* SDLScrollableMessage.h in Headers */,
@@ -7308,6 +7442,7 @@
4ABB284224F828630061BF55 /* SDLTextFieldName.h in Headers */,
4ABB2A3D24F847980061BF55 /* SDLEncodedSyncPDataResponse.h in Headers */,
4ABB24C924F593090061BF55 /* SDLStreamingProtocolDelegate.h in Headers */,
+ 8889C2FD2559CFE3004F5966 /* SDLAudioData.h in Headers */,
4ABB275F24F7FE1F0061BF55 /* SDLFuelType.h in Headers */,
4A8BD3A024F9474B000945E3 /* SDLIAPDataSessionDelegate.h in Headers */,
B3838A28257C5CE600420C11 /* SDLDoorStatusType.h in Headers */,
@@ -7326,6 +7461,7 @@
4ABB26D724F7FAFD0061BF55 /* SDLRPCMessage.h in Headers */,
4A8BD24A24F93135000945E3 /* SDLMyKey.h in Headers */,
4ABB24F924F5959E0061BF55 /* SDLAsynchronousOperation.h in Headers */,
+ B3A9D9E225D2571000CDFD21 /* SDLKeyboardCapabilities.h in Headers */,
4ABB29B324F845DB0061BF55 /* SDLShow.h in Headers */,
4ABB25B424F7E6F60061BF55 /* SDLSoftButtonReplaceOperation.h in Headers */,
4ABB269C24F7F9710061BF55 /* SDLRPCParameterNames.h in Headers */,
@@ -7459,6 +7595,7 @@
4A8BD36E24F94636000945E3 /* SDLProtocolMessageAssembler.h in Headers */,
4ABB28C024F82A6A0061BF55 /* SDLOnCommand.h in Headers */,
4ABB26A824F7F9CF0061BF55 /* SDLLogTargetAppleSystemLog.h in Headers */,
+ B3A9D9ED25D2586C00CDFD21 /* SDLKeyboardInputMask.h in Headers */,
4ABB250524F596450061BF55 /* SDLListFilesOperation.h in Headers */,
4ABB268F24F7F8FC0061BF55 /* SDLHexUtility.h in Headers */,
4A8BD28124F9343F000945E3 /* SDLRemoteControlCapabilities.h in Headers */,
@@ -7558,6 +7695,7 @@
4ABB25BC24F7E70E0061BF55 /* SDLSoftButtonObject.h in Headers */,
4ABB256324F7E5AA0061BF55 /* SDLPermissionElement.h in Headers */,
4ABB2AE624F848270061BF55 /* SDLUnsubscribeVehicleDataResponse.h in Headers */,
+ 881BBF60255B1C1E00761B7E /* SDLAlertManager.h in Headers */,
4ABB258524F7E62D0061BF55 /* SDLChoiceSetDelegate.h in Headers */,
4ABB2B8D24F8504A0061BF55 /* SDLHMISettingsControlData.h in Headers */,
4ABB25F824F7E7EF0061BF55 /* SDLTouchManager.h in Headers */,
@@ -7680,7 +7818,7 @@
attributes = {
CLASSPREFIX = SDL;
LastSwiftUpdateCheck = 0710;
- LastUpgradeCheck = 1210;
+ LastUpgradeCheck = 1240;
ORGANIZATIONNAME = smartdevicelink;
TargetAttributes = {
5D4019AE1A76EC350006B0C2 = {
@@ -7845,6 +7983,7 @@
4ABB291624F842160061BF55 /* SDLCloseApplication.m in Sources */,
4ABB2B4F24F84EF50061BF55 /* SDLClimateControlData.m in Sources */,
4ABB2A2824F847980061BF55 /* SDLDeleteCommandResponse.m in Sources */,
+ 881BBF51255AC27000761B7E /* SDLAlertView.m in Sources */,
4ABB2AD224F848130061BF55 /* SDLSubscribeWayPointsResponse.m in Sources */,
4ABB286224F828E00061BF55 /* SDLVehicleDataResultCode.m in Sources */,
4ABB2B8A24F8504A0061BF55 /* SDLHMISettingsControlCapabilities.m in Sources */,
@@ -7882,6 +8021,7 @@
4ABB2AB724F847F40061BF55 /* SDLSetGlobalPropertiesResponse.m in Sources */,
C9DFFE79257ACE0000F7D57A /* SDLSeekStreamingIndicator.m in Sources */,
4ABB2B0B24F84D950061BF55 /* SDLAppServiceData.m in Sources */,
+ 88D79EEE255D8D5B005FACB1 /* SDLPresentAlertOperation.m in Sources */,
4ABB282C24F824E70061BF55 /* SDLTBTState.m in Sources */,
4ABB27DF24F800CA0061BF55 /* SDLPowerModeQualificationStatus.m in Sources */,
4ABB269D24F7F9710061BF55 /* SDLRPCParameterNames.m in Sources */,
@@ -7890,6 +8030,7 @@
4ABB28E224F82A6A0061BF55 /* SDLOnLanguageChange.m in Sources */,
4ABB29DD24F846880061BF55 /* SDLSubscribeButton.m in Sources */,
4ABB25F324F7E7EF0061BF55 /* SDLPinchGesture.m in Sources */,
+ 8889C2F52559CFAF004F5966 /* SDLAlertAudioData.m in Sources */,
4A8BD39524F94731000945E3 /* SDLIAPConstants.m in Sources */,
4ABB2B8C24F8504A0061BF55 /* SDLGrid.m in Sources */,
4ABB299024F845440061BF55 /* SDLRegisterAppInterface.m in Sources */,
@@ -8090,12 +8231,14 @@
4ABB269224F7F9060061BF55 /* SDLTimer.m in Sources */,
4ABB25C624F7E73C0061BF55 /* SDLSubscribeButtonManager.m in Sources */,
4ABB278E24F7FF0B0061BF55 /* SDLKeyboardEvent.m in Sources */,
+ B3A9D9E725D2578F00CDFD21 /* SDLKeyboardLayoutCapability.m in Sources */,
4ABB279024F7FF0B0061BF55 /* SDLImageType.m in Sources */,
4ABB28CB24F82A6A0061BF55 /* SDLOnTouchEvent.m in Sources */,
4ABB2B4E24F84EF50061BF55 /* SDLClusterModeStatus.m in Sources */,
4ABB2AA824F847F40061BF55 /* SDLSetDisplayLayoutResponse.m in Sources */,
4ABB273E24F7FD1D0061BF55 /* SDLDisplayMode.m in Sources */,
4A40254124FFDA660080E159 /* SDLTextAndGraphicState.m in Sources */,
+ 4AAB6A1325E57BEA0017A5A7 /* SDLSystemInfo.m in Sources */,
4ABB27AB24F7FFDA0061BF55 /* SDLMassageZone.m in Sources */,
4A8BD2DD24F93803000945E3 /* SDLTouchEvent.m in Sources */,
4ABB26BD24F7FA1C0061BF55 /* SDLLogConfiguration.m in Sources */,
@@ -8143,6 +8286,7 @@
4ABB254824F7E49D0061BF55 /* SDLLockScreenStatusManager.m in Sources */,
4A8BD2B724F935BC000945E3 /* SDLSoftButton.m in Sources */,
4ABB2AD824F8481D0061BF55 /* SDLSystemRequestResponse.m in Sources */,
+ 8889C2FC2559CFE3004F5966 /* SDLAudioData.m in Sources */,
4ABB28E924F82A6A0061BF55 /* SDLOnWayPointChange.m in Sources */,
4A8BD24324F93135000945E3 /* SDLMetadataTags.m in Sources */,
4ABB283124F824E70061BF55 /* SDLTemperatureUnit.m in Sources */,
@@ -8151,6 +8295,7 @@
4ABB2AB924F847F40061BF55 /* SDLSetInteriorVehicleDataResponse.m in Sources */,
4ABB295424F843440061BF55 /* SDLEndAudioPassThru.m in Sources */,
4ABB2A2924F847980061BF55 /* SDLDeleteFileResponse.m in Sources */,
+ B3A9D9EE25D2586C00CDFD21 /* SDLKeyboardInputMask.m in Sources */,
4ABB284524F828630061BF55 /* SDLTouchType.m in Sources */,
4ABB2B8024F8504A0061BF55 /* SDLHapticRect.m in Sources */,
4A8BD38A24F94712000945E3 /* SDLSecondaryTransportManager.m in Sources */,
@@ -8189,6 +8334,7 @@
4ABB2B9F24F850AE0061BF55 /* SDLImageResolution.m in Sources */,
4ABB29B424F845DB0061BF55 /* SDLSpeak.m in Sources */,
4A8BD3AF24F98ACE000945E3 /* SDLLogManager.m in Sources */,
+ 4A39C6FA25E84C87005C8943 /* SDLKeyboardCapabilities.m in Sources */,
4ABB257124F7E5E80061BF55 /* SDLPresentChoiceSetOperation.m in Sources */,
4ABB2A5624F847B10061BF55 /* SDLGetWayPointsResponse.m in Sources */,
4ABB24F524F595120061BF55 /* SDLArtwork.m in Sources */,
@@ -8281,6 +8427,7 @@
4A8BD27A24F9343F000945E3 /* SDLRemoteControlCapabilities.m in Sources */,
4ABB291824F842160061BF55 /* SDLChangeRegistration.m in Sources */,
4A8BD26224F933C7000945E3 /* SDLNavigationInstruction.m in Sources */,
+ 881BBF61255B1C1E00761B7E /* SDLAlertManager.m in Sources */,
4ABB29EB24F847360061BF55 /* SDLUnsubscribeWayPoints.m in Sources */,
4ABB25E124F7E7980061BF55 /* SDLStreamingMediaConfiguration.m in Sources */,
4ABB299424F845440061BF55 /* SDLSendLocation.m in Sources */,
@@ -8429,6 +8576,7 @@
162E837D1A9BDE8B00906325 /* SDLEmergencyEventSpec.m in Sources */,
162E82D31A9BDE8A00906325 /* SDLCarModeStatusSpec.m in Sources */,
8B7B31A91F2FB8BC00BDC38D /* SDLVideoStreamingProtocolSpec.m in Sources */,
+ B3A9DA0A25D26E1800CDFD21 /* SDLKeyboardCapabilitiesSpec.m in Sources */,
88EED83B1F33BECB00E6C42E /* SDLHapticRectSpec.m in Sources */,
162E82EA1A9BDE8B00906325 /* SDLLanguageSpec.m in Sources */,
5D76E3291D3D0A8800647CFA /* SDLFakeViewControllerPresenter.m in Sources */,
@@ -8504,6 +8652,7 @@
162E835B1A9BDE8B00906325 /* SDLPerformInteractionResponseSpec.m in Sources */,
880E35B82088F78E00181259 /* SDLSystemCapabilityManagerSpec.m in Sources */,
162E832D1A9BDE8B00906325 /* SDLEncodedSyncPDataSpec.m in Sources */,
+ B3A9DA0425D26D8500CDFD21 /* SDLKeyboardInputMaskSpec.m in Sources */,
1EE8C44C1F385C7100FDC2CF /* SDLRDSDataSpec.m in Sources */,
5DB92D241AC47B2C00C15BB0 /* SDLHexUtilitySpec.m in Sources */,
8815D0F022330765000F24E6 /* SDLRPCRequestNotificationSpec.m in Sources */,
@@ -8607,6 +8756,7 @@
5D92935620B2FD7300FCC775 /* SDLTemplateColorSchemeSpec.m in Sources */,
162E82DE1A9BDE8B00906325 /* SDLFuelCutoffStatusSpec.m in Sources */,
162E83271A9BDE8B00906325 /* SDLCreateInteractionChoiceSetSpec.m in Sources */,
+ 4AAB6A2325E69D010017A5A7 /* SDLSystemInfoSpec.m in Sources */,
4A404C68250BBE2B003AB65D /* SDLTextAndGraphicStateSpec.m in Sources */,
5DAD5F8920508F090025624C /* SDLSoftButtonStateSpec.m in Sources */,
1098F03824A39699004F53CC /* SDLPermissionElementSpec.m in Sources */,
@@ -8637,6 +8787,7 @@
162E83761A9BDE8B00906325 /* SDLChoiceSpec.m in Sources */,
162E83571A9BDE8B00906325 /* SDLGetDTCsResponseSpec.m in Sources */,
5D4346471E6F0BDA00B639C6 /* SDLLogFileModuleSpec.m in Sources */,
+ 8889C3052559E109004F5966 /* SDLAlertAudioDataSpec.m in Sources */,
889D0B9824D06E52008AD494 /* SDLSubtleAlertSpec.m in Sources */,
88A1CF1E21669AC7001ACC75 /* SDLLifecycleConfigurationUpdateSpec.m in Sources */,
1EE8C4581F387ABD00FDC2CF /* SDLButtonPressResponseSpec.m in Sources */,
@@ -8677,6 +8828,7 @@
8863747E22D650DE00D2671F /* SDLCloseApplicationSpec.m in Sources */,
162E834B1A9BDE8B00906325 /* SDLAlertManeuverResponseSpec.m in Sources */,
162E833E1A9BDE8B00906325 /* SDLShowSpec.m in Sources */,
+ 886E41412565D11200F073B8 /* SDLAlertManagerSpec.m in Sources */,
5D6035D8202CF5C900A429C9 /* TestRequestProgressResponse.m in Sources */,
162E83241A9BDE8B00906325 /* SDLAlertManeuverSpec.m in Sources */,
5D43466F1E6F55BD00B639C6 /* SDLLogManagerSpec.m in Sources */,
@@ -8752,10 +8904,12 @@
162E83821A9BDE8B00906325 /* SDLImageSpec.m in Sources */,
162E834A1A9BDE8B00906325 /* SDLAddSubMenuResponseSpec.m in Sources */,
162E830C1A9BDE8B00906325 /* SDLWarningLightStatusSpec.m in Sources */,
+ 881BBF5B255ADB8300761B7E /* SDLAlertViewSpec.m in Sources */,
1EE8C45F1F3884FF00FDC2CF /* SDLSetInteriorVehicleDataSpec.m in Sources */,
162E82E71A9BDE8B00906325 /* SDLKeyboardEventSpec.m in Sources */,
162E834E1A9BDE8B00906325 /* SDLCreateInteractionChoiceSetResponseSpec.m in Sources */,
DA9F7EB61DCC086A00ACAE48 /* SDLOasisAddressSpec.m in Sources */,
+ 8889C2ED2559C7E2004F5966 /* SDLAudioDataSpec.m in Sources */,
162E833F1A9BDE8B00906325 /* SDLSliderSpec.m in Sources */,
162E838C1A9BDE8B00906325 /* SDLSoftButtonSpec.m in Sources */,
5DA23FF81F2FAF2D009C0313 /* SDLControlFramePayloadRPCStartServiceAckSpec.m in Sources */,
@@ -8808,6 +8962,7 @@
162E830F1A9BDE8B00906325 /* SDLOnAppInterfaceUnregisteredSpec.m in Sources */,
162E83971A9BDE8B00906325 /* SDLVehicleTypeSpec.m in Sources */,
887BE4D422272B2200B397C2 /* SDLControlFramePayloadConstantsSpec.m in Sources */,
+ B3A9DA1225D270EA00CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m in Sources */,
885468382225CBA400994D8D /* SDLCloudAppPropertiesSpec.m in Sources */,
88A795D5210678E000056542 /* SDLStaticIconNameSpec.m in Sources */,
1680B1131A9CD7AD00DBD79E /* SDLProtocolHeaderSpec.m in Sources */,
@@ -8847,6 +9002,7 @@
1680B1171A9CD7AD00DBD79E /* SDLProtocolSpec.m in Sources */,
162E836D1A9BDE8B00906325 /* SDLUnregisterAppInterfaceResponseSpec.m in Sources */,
162E837C1A9BDE8B00906325 /* SDLECallInfoSpec.m in Sources */,
+ 886E413D2565D0D200F073B8 /* SDLPresentAlertOperationSpec.m in Sources */,
1EAA47782036BA74000FE74B /* SDLAudioControlCapabilitiesSpec.m in Sources */,
5DB1BCD51D243A8E002FFC37 /* SDLUploadFileOperationSpec.m in Sources */,
162E83401A9BDE8B00906325 /* SDLSpeakSpec.m in Sources */,
diff --git a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-ObjC.xcscheme b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-ObjC.xcscheme
index 144ab0c4b..bc2631407 100644
--- a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-ObjC.xcscheme
+++ b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink-Example-ObjC.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1210"
+ LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme
index a9b412148..33ef694da 100644
--- a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme
+++ b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1210"
+ LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLinkSwift.xcscheme b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLinkSwift.xcscheme
index 55446e4f2..de1c185e3 100644
--- a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLinkSwift.xcscheme
+++ b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLinkSwift.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1210"
+ LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/SmartDeviceLink/private/SDLAlertManager.h b/SmartDeviceLink/private/SDLAlertManager.h
new file mode 100644
index 000000000..c80645b20
--- /dev/null
+++ b/SmartDeviceLink/private/SDLAlertManager.h
@@ -0,0 +1,52 @@
+//
+// SDLAlertManager.h
+// SmartDeviceLink
+//
+// Created by Nicole on 11/10/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLAlertView;
+@class SDLFileManager;
+@class SDLPermissionManager;
+@class SDLSystemCapabilityManager;
+
+@protocol SDLConnectionManagerType;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Handler called when the alert either dismisses from the screen or it has failed to present
+typedef void(^SDLAlertCompletionHandler)(NSError *__nullable error);
+
+/// An alert manager that handles uploading images and audio needed by an alert, sending an alert and cancelling an alert.
+@interface SDLAlertManager : NSObject
+
+/// Initialize the manager with required dependencies
+/// @param connectionManager The connection manager object for sending RPCs
+/// @param fileManager The file manager object for uploading files
+/// @param systemCapabilityManager The system capability manager object for reading window capabilities
+/// @param permissionManager The permission manager object for checking permissions
+/// @return The alert manager
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager permissionManager:(SDLPermissionManager *)permissionManager;
+
+/// Starts the manager.
+- (void)start;
+
+/// Stops the manager.
+- (void)stop;
+
+/// Present the alert on the screen.
+///
+/// If the alert contains an audio indication with a file that needs to be uploaded, it will be uploaded before presenting the alert. If the alert contains soft buttons with images, they will be uploaded before presenting the alert. If the alert contains an icon, that will be uploaded before presenting the alert.
+///
+/// The handler will be called when the alert either dismisses from the screen or it has failed to present. If the error value in the handler is present, then the alert failed to appear or was aborted, if not, then the alert dismissed without error. The error will contain `userInfo` with information on how long to wait before retrying.
+///
+/// @param alert Alert to be presented
+/// @param handler The handler to be called when the alert either dismisses from the screen or it has failed to present
+- (void)presentAlert:(SDLAlertView *)alert withCompletionHandler:(nullable SDLAlertCompletionHandler)handler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/private/SDLAlertManager.m b/SmartDeviceLink/private/SDLAlertManager.m
new file mode 100644
index 000000000..2dc774869
--- /dev/null
+++ b/SmartDeviceLink/private/SDLAlertManager.m
@@ -0,0 +1,171 @@
+//
+// SDLAlertManager.m
+// SmartDeviceLink
+//
+// Created by Nicole on 11/10/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAlertManager.h"
+
+#import "SDLAlertView.h"
+#import "SDLDisplayCapability.h"
+#import "SDLGlobals.h"
+#import "SDLLogMacros.h"
+#import "SDLNotificationConstants.h"
+#import "SDLOnHMIStatus.h"
+#import "SDLPermissionManager.h"
+#import "SDLPredefinedWindows.h"
+#import "SDLPresentAlertOperation.h"
+#import "SDLRPCNotificationNotification.h"
+#import "SDLSystemCapability.h"
+#import "SDLSystemCapabilityManager.h"
+#import "SDLWindowCapability.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Assigns a set range of unique cancel ids in order to prevent overlap with other sub-screen managers that use cancel ids. If the max cancel id is reached, generation starts over from the cancel id min value.
+UInt16 const AlertCancelIdMin = 1;
+UInt16 const AlertCancelIdMax = 100;
+
+@interface SDLAlertManager()
+
+@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
+@property (weak, nonatomic) SDLFileManager *fileManager;
+@property (weak, nonatomic) SDLSystemCapabilityManager *systemCapabilityManager;
+@property (weak, nonatomic) SDLPermissionManager *permissionManager;
+
+@property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability;
+@property (strong, nonatomic) NSOperationQueue *transactionQueue;
+@property (copy, nonatomic) dispatch_queue_t readWriteQueue;
+
+@property (assign, nonatomic) UInt16 nextCancelId;
+@property (assign, nonatomic) BOOL isAlertRPCAllowed;
+
+@end
+
+@implementation SDLAlertManager
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager permissionManager:(SDLPermissionManager *)permissionManager {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _connectionManager = connectionManager;
+ _fileManager = fileManager;
+ _systemCapabilityManager = systemCapabilityManager;
+ _permissionManager = permissionManager;
+ _transactionQueue = [self sdl_newTransactionQueue];
+
+ _readWriteQueue = dispatch_queue_create_with_target("com.sdl.screenManager.alertManager.readWriteQueue", DISPATCH_QUEUE_SERIAL, [SDLGlobals sharedGlobals].sdlProcessingQueue);
+ _nextCancelId = AlertCancelIdMin;
+
+ _currentWindowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
+
+ return self;
+}
+
+- (void)start {
+ SDLLogD(@"Starting manager");
+
+ __weak typeof(self) weakself = self;
+ [self.permissionManager subscribeToRPCPermissions:@[[[SDLPermissionElement alloc] initWithRPCName:SDLRPCFunctionNameAlert parameterPermissions:nil]] groupType:SDLPermissionGroupTypeAny withHandler:^(NSDictionary<SDLRPCFunctionName,SDLRPCPermissionStatus *> * _Nonnull updatedPermissionStatuses, SDLPermissionGroupStatus status) {
+ weakself.isAlertRPCAllowed = (status == SDLPermissionGroupStatusAllowed);
+
+ [weakself sdl_updateTransactionQueueSuspended];
+ }];
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate)];
+}
+
+- (void)stop {
+ SDLLogD(@"Stopping manager");
+
+ _currentWindowCapability = nil;
+ _nextCancelId = AlertCancelIdMin;
+
+ [_transactionQueue cancelAllOperations];
+ self.transactionQueue = [self sdl_newTransactionQueue];
+
+ [self.permissionManager removeAllObservers];
+ [self.systemCapabilityManager unsubscribeFromCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self];
+}
+
+- (void)presentAlert:(SDLAlertView *)alert withCompletionHandler:(nullable SDLAlertCompletionHandler)handler {
+ SDLPresentAlertOperation *op = [[SDLPresentAlertOperation alloc] initWithConnectionManager:self.connectionManager fileManager:self.fileManager systemCapabilityManager:self.systemCapabilityManager currentWindowCapability:self.currentWindowCapability alertView:alert cancelID:self.nextCancelId];
+
+ __weak typeof(op) weakPreloadOp = op;
+ op.completionBlock = ^{
+ SDLLogD(@"Alert finished presenting: %@", alert);
+
+ if (handler != nil) {
+ handler(weakPreloadOp.error);
+ }
+ };
+
+ [self.transactionQueue addOperation:op];
+}
+
+/// Creates a new serial queue. If an alert is already being presented when a new alert is added to the queue, the newest alert will not be sent until module dismisses the previous alert.
+/// The queue is initially suspended until the manager knows it can send the `Alert` RPCS without getting a disallowed response.
+/// @return A concurrent operation queue
+- (NSOperationQueue *)sdl_newTransactionQueue {
+ NSOperationQueue *queue = [[NSOperationQueue alloc] init];
+ queue.name = @"com.sdl.screenManager.alertManager.transactionQueue";
+ queue.maxConcurrentOperationCount = 1;
+ queue.qualityOfService = NSQualityOfServiceUserInteractive;
+ queue.underlyingQueue = [SDLGlobals sharedGlobals].sdlConcurrentQueue;
+ queue.suspended = YES;
+
+ return queue;
+}
+
+/// Suspend the queue if the window capabilities are nil (we assume that text and graphics are not supported yet)
+- (void)sdl_updateTransactionQueueSuspended {
+ if (self.currentWindowCapability == nil || !self.isAlertRPCAllowed) {
+ SDLLogD(@"Suspending the transaction queue. Window capabilities is nil: %@, alert has permission be sent at the current HMI level: %@", (self.currentWindowCapability == nil ? @"YES" : @"NO"), self.isAlertRPCAllowed ? @"YES" : @"NO");
+ self.transactionQueue.suspended = YES;
+ } else {
+ SDLLogD(@"Starting the transaction queue");
+ self.transactionQueue.suspended = NO;
+ }
+}
+
+/// Updates pending operations in the queue with the new window capability (i.e. the window capability will change when the template changes)
+- (void)sdl_updatePendingOperationsWithNewWindowCapability {
+ for (NSOperation *operation in self.transactionQueue.operations) {
+ if (operation.isExecuting) { continue; }
+
+ ((SDLPresentAlertOperation *)operation).currentWindowCapability = self.currentWindowCapability;
+ }
+}
+
+#pragma mark - Observers
+
+/// Called when the current window capabilities have updated.
+- (void)sdl_displayCapabilityDidUpdate {
+ self.currentWindowCapability = [self.systemCapabilityManager defaultMainWindowCapability];
+ [self sdl_updateTransactionQueueSuspended];
+ [self sdl_updatePendingOperationsWithNewWindowCapability];
+}
+
+#pragma mark - Getters
+
+/// Generates a `cancelID` for an Alert `CancelInteraction` request. `cancelID`s do not need to be unique for different RPC functions, however, we will set a max value for `cancelID`s so if a developer, for some reason, is using both the alert manager and the `Alert` RPC they can use any value above the max `cancelID` without worrying about conflicts. Once an alert with the associated `cancelID` has been dismissed, the `cancelID` can be reused so it is very unlikely there will be conflicts with an already existing generated `cancelID`.
+- (UInt16)nextCancelId {
+ __block UInt16 cancelId = 0;
+ [SDLGlobals runSyncOnSerialSubQueue:self.readWriteQueue block:^{
+ cancelId = self->_nextCancelId;
+ if (cancelId >= AlertCancelIdMax) {
+ self->_nextCancelId = AlertCancelIdMin;
+ } else {
+ self->_nextCancelId = cancelId + 1;
+ }
+ }];
+
+ return cancelId;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/private/SDLChoiceSetManager.m b/SmartDeviceLink/private/SDLChoiceSetManager.m
index 7bed1782b..1a44ef5de 100644
--- a/SmartDeviceLink/private/SDLChoiceSetManager.m
+++ b/SmartDeviceLink/private/SDLChoiceSetManager.m
@@ -84,7 +84,10 @@ typedef NSNumber * SDLChoiceId;
@end
UInt16 const ChoiceCellIdMin = 1;
-UInt16 const ChoiceCellCancelIdMin = 1;
+
+// Assigns a set range of unique cancel ids in order to prevent overlap with other sub-screen managers that use cancel ids. If the max cancel id is reached, generation starts over from the cancel id min value.
+UInt16 const ChoiceCellCancelIdMin = 101;
+UInt16 const ChoiceCellCancelIdMax = 200;
@implementation SDLChoiceSetManager
@@ -119,7 +122,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
- (void)start {
SDLLogD(@"Starting manager");
- [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate:)];
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate)];
if ([self.currentState isEqualToString:SDLChoiceManagerStateShutdown]) {
[self.stateMachine transitionToState:SDLChoiceManagerStateCheckingVoiceOptional];
@@ -382,10 +385,10 @@ UInt16 const ChoiceCellCancelIdMin = 1;
SDLPresentChoiceSetOperation *presentOp = nil;
if (delegate == nil) {
// Non-searchable choice set
- presentOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:self.connectionManager choiceSet:self.pendingPresentationSet mode:mode keyboardProperties:nil keyboardDelegate:nil cancelID:self.nextCancelId];
+ presentOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:self.connectionManager choiceSet:self.pendingPresentationSet mode:mode keyboardProperties:nil keyboardDelegate:nil cancelID:self.nextCancelId windowCapability:self.currentWindowCapability];
} else {
// Searchable choice set
- presentOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:self.connectionManager choiceSet:self.pendingPresentationSet mode:mode keyboardProperties:self.keyboardConfiguration keyboardDelegate:delegate cancelID:self.nextCancelId];
+ presentOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:self.connectionManager choiceSet:self.pendingPresentationSet mode:mode keyboardProperties:self.keyboardConfiguration keyboardDelegate:delegate cancelID:self.nextCancelId windowCapability:self.currentWindowCapability];
}
self.pendingPresentOperation = presentOp;
@@ -424,7 +427,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
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];
+ self.pendingPresentOperation = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:self.connectionManager keyboardProperties:self.keyboardConfiguration initialText:initialText keyboardDelegate:delegate cancelID:keyboardCancelId windowCapability:self.currentWindowCapability];
[self.transactionQueue addOperation:self.pendingPresentOperation];
return @(keyboardCancelId);
}
@@ -545,7 +548,7 @@ UInt16 const ChoiceCellCancelIdMin = 1;
}
- (SDLKeyboardProperties *)sdl_defaultKeyboardConfiguration {
- return [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageEnUs keyboardLayout:SDLKeyboardLayoutQWERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil];
+ return [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageEnUs keyboardLayout:SDLKeyboardLayoutQWERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil];
}
#pragma mark - Getters
@@ -582,7 +585,11 @@ UInt16 const ChoiceCellCancelIdMin = 1;
__block UInt16 cancelId = 0;
[SDLGlobals runSyncOnSerialSubQueue:self.readWriteQueue block:^{
cancelId = self->_nextCancelId;
- self->_nextCancelId = cancelId + 1;
+ if (cancelId >= ChoiceCellCancelIdMax) {
+ self->_nextCancelId = ChoiceCellCancelIdMin;
+ } else {
+ self->_nextCancelId = cancelId + 1;
+ }
}];
return cancelId;
@@ -594,21 +601,8 @@ UInt16 const ChoiceCellCancelIdMin = 1;
#pragma mark - RPC Responses / Notifications
-- (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; }
-
- self.currentWindowCapability = windowCapability;
- break;
- }
- }
-
+- (void)sdl_displayCapabilityDidUpdate {
+ self.currentWindowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
[self sdl_updateTransactionQueueSuspended];
}
diff --git a/SmartDeviceLink/private/SDLConnectionManagerType.h b/SmartDeviceLink/private/SDLConnectionManagerType.h
index 2602a7315..21cd8d3ab 100644
--- a/SmartDeviceLink/private/SDLConnectionManagerType.h
+++ b/SmartDeviceLink/private/SDLConnectionManagerType.h
@@ -12,12 +12,15 @@
@class SDLRPCRequest;
@class SDLRPCMessage;
@class SDLRegisterAppInterfaceResponse;
-
+@class SDLSystemInfo;
NS_ASSUME_NONNULL_BEGIN
@protocol SDLConnectionManagerType <NSObject>
+/// An object describing the properties of the connected module
+@property (strong, nonatomic, nullable) SDLSystemInfo *systemInfo;
+
/**
* A special method on the connection manager which is used by managers that must bypass the default block on RPC sends before managers complete setup.
*
diff --git a/SmartDeviceLink/private/SDLControlFramePayloadConstants.h b/SmartDeviceLink/private/SDLControlFramePayloadConstants.h
index e0bd1d5e8..ecdd4c954 100644
--- a/SmartDeviceLink/private/SDLControlFramePayloadConstants.h
+++ b/SmartDeviceLink/private/SDLControlFramePayloadConstants.h
@@ -11,18 +11,24 @@
extern int32_t const SDLControlFrameInt32NotFound;
extern int64_t const SDLControlFrameInt64NotFound;
-extern char *const SDLControlFrameProtocolVersionKey;
+extern char *const SDLControlFrameAudioServiceTransportsKey;
+extern char *const SDLControlFrameAuthTokenKey;
extern char *const SDLControlFrameHashIdKey;
+extern char *const SDLControlFrameHeightKey;
extern char *const SDLControlFrameMTUKey;
+extern char *const SDLControlFrameProtocolVersionKey;
extern char *const SDLControlFrameReasonKey;
extern char *const SDLControlFrameRejectedParams;
-extern char *const SDLControlFrameVideoProtocolKey;
-extern char *const SDLControlFrameVideoCodecKey;
-extern char *const SDLControlFrameHeightKey;
-extern char *const SDLControlFrameWidthKey;
extern char *const SDLControlFrameSecondaryTransportsKey;
-extern char *const SDLControlFrameAudioServiceTransportsKey;
-extern char *const SDLControlFrameVideoServiceTransportsKey;
extern char *const SDLControlFrameTCPIPAddressKey;
extern char *const SDLControlFrameTCPPortKey;
-extern char *const SDLControlFrameAuthTokenKey;
+extern char *const SDLControlFrameVehicleMakeKey;
+extern char *const SDLControlFrameVehicleModelKey;
+extern char *const SDLControlFrameVehicleModelYearKey;
+extern char *const SDLControlFrameVehicleHardwareVersionKey;
+extern char *const SDLControlFrameVehicleSoftwareVersionKey;
+extern char *const SDLControlFrameVehicleTrimKey;
+extern char *const SDLControlFrameVideoCodecKey;
+extern char *const SDLControlFrameVideoProtocolKey;
+extern char *const SDLControlFrameVideoServiceTransportsKey;
+extern char *const SDLControlFrameWidthKey;
diff --git a/SmartDeviceLink/private/SDLControlFramePayloadConstants.m b/SmartDeviceLink/private/SDLControlFramePayloadConstants.m
index c365c78a8..1d3e19b98 100644
--- a/SmartDeviceLink/private/SDLControlFramePayloadConstants.m
+++ b/SmartDeviceLink/private/SDLControlFramePayloadConstants.m
@@ -11,18 +11,24 @@
int32_t const SDLControlFrameInt32NotFound = -1;
int64_t const SDLControlFrameInt64NotFound = -1;
-char *const SDLControlFrameProtocolVersionKey = "protocolVersion";
-char *const SDLControlFrameHashIdKey = "hashId";
-char *const SDLControlFrameMTUKey = "mtu";
-char *const SDLControlFrameSecondaryTransportsKey = "secondaryTransports";
char *const SDLControlFrameAudioServiceTransportsKey = "audioServiceTransports";
-char *const SDLControlFrameVideoServiceTransportsKey = "videoServiceTransports";
char *const SDLControlFrameAuthTokenKey = "authToken";
+char *const SDLControlFrameHashIdKey = "hashId";
+char *const SDLControlFrameHeightKey = "height";
+char *const SDLControlFrameMTUKey = "mtu";
+char *const SDLControlFrameProtocolVersionKey = "protocolVersion";
char *const SDLControlFrameRejectedParams = "rejectedParams";
char *const SDLControlFrameReasonKey = "reason";
+char *const SDLControlFrameSecondaryTransportsKey = "secondaryTransports";
+char *const SDLControlFrameTCPIPAddressKey = "tcpIpAddress";
+char *const SDLControlFrameTCPPortKey = "tcpPort";
+char *const SDLControlFrameVehicleHardwareVersionKey = "systemHardwareVersion";
+char *const SDLControlFrameVehicleMakeKey = "make";
+char *const SDLControlFrameVehicleModelKey = "model";
+char *const SDLControlFrameVehicleModelYearKey = "modelYear";
+char *const SDLControlFrameVehicleSoftwareVersionKey = "systemSoftwareVersion";
+char *const SDLControlFrameVehicleTrimKey = "trim";
char *const SDLControlFrameVideoProtocolKey = "videoProtocol";
char *const SDLControlFrameVideoCodecKey = "videoCodec";
-char *const SDLControlFrameHeightKey = "height";
char *const SDLControlFrameWidthKey = "width";
-char *const SDLControlFrameTCPIPAddressKey = "tcpIpAddress";
-char *const SDLControlFrameTCPPortKey = "tcpPort";
+char *const SDLControlFrameVideoServiceTransportsKey = "videoServiceTransports";
diff --git a/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.h b/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.h
index 295204aac..27e860b64 100644
--- a/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.h
+++ b/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.h
@@ -35,7 +35,51 @@ NS_ASSUME_NONNULL_BEGIN
/** List of transports that are allowed to carry video service. The values can be either 1 (primary transport) or 2 (secondary transport) and are listed in preferred order. */
@property (copy, nonatomic, readonly, nullable) NSArray<NSNumber *> *videoServiceTransports;
-- (instancetype)initWithHashId:(int32_t)hashId mtu:(int64_t)mtu authToken:(nullable NSString *)authToken protocolVersion:(nullable NSString *)protocolVersion secondaryTransports:(nullable NSArray<NSString *> *)secondaryTransports audioServiceTransports:(nullable NSArray<NSNumber *> *)audioServiceTransports videoServiceTransports:(nullable NSArray<NSNumber *> *)videoServiceTransports;
+/// The connected vehicle make, e.g. "Ford", "Toyota", or "Subaru"
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *make;
+
+/// The connected vehicle model, e.g. "Bronco", "Tundra", "Outback"
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *model;
+
+/// The connected vehicle trim, e.g. "ST"
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *trim;
+
+/// The connected vehicle model year, e.g. "2021"
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *modelYear;
+
+/// The connected vehicle module software version
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *systemSoftwareVersion;
+
+/// The connected vehicle module hardware version
+///
+/// Added in Protocol Spec 5.4
+@property (copy, nonatomic, readonly, nullable) NSString *systemHardwareVersion;
+
+/// Initialize a StartServiceACK Control Frame Payload
+/// @param hashId A hash identifying the connection
+/// @param mtu The size of a packet that can be sent over this connection without dividing it into separate packets
+/// @param authToken A cloud app authorization token
+/// @param protocolVersion The version of the protocol this connection runs over
+/// @param secondaryTransports Array of available secondary transports
+/// @param audioServiceTransports Array of transports the audio service may travel on
+/// @param videoServiceTransports Array of transports the video service may travel on
+/// @param make The connected vehicle make, e.g. "Ford", "Toyota", or "Subaru"
+/// @param model The connected vehicle model, e.g. "Bronco", "Tundra", "Outback"
+/// @param trim The connected vehicle trim, e.g. "ST"
+/// @param modelYear The connected vehicle model year, e.g. "2021"
+/// @param systemSoftwareVersion The connected vehicle module software version
+/// @param systemHardwareVersion The connected vehicle module hardware version
+- (instancetype)initWithHashId:(int32_t)hashId mtu:(int64_t)mtu authToken:(nullable NSString *)authToken protocolVersion:(nullable NSString *)protocolVersion secondaryTransports:(nullable NSArray<NSString *> *)secondaryTransports audioServiceTransports:(nullable NSArray<NSNumber *> *)audioServiceTransports videoServiceTransports:(nullable NSArray<NSNumber *> *)videoServiceTransports make:(nullable NSString *)make model:(nullable NSString *)model trim:(nullable NSString *)trim modelYear:(nullable NSString *)modelYear systemSoftwareVersion:(nullable NSString *)systemSoftwareVersion systemHardwareVersion:(nullable NSString *)systemHardwareVersion;
@end
diff --git a/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.m b/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.m
index e6afae672..afa5ace28 100644
--- a/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.m
+++ b/SmartDeviceLink/private/SDLControlFramePayloadRPCStartServiceAck.m
@@ -23,19 +23,19 @@ NS_ASSUME_NONNULL_BEGIN
@property (copy, nonatomic, readwrite, nullable) NSArray<NSString *> *secondaryTransports;
@property (copy, nonatomic, readwrite, nullable) NSArray<NSNumber *> *audioServiceTransports;
@property (copy, nonatomic, readwrite, nullable) NSArray<NSNumber *> *videoServiceTransports;
+@property (copy, nonatomic, readwrite, nullable) NSString *make;
+@property (copy, nonatomic, readwrite, nullable) NSString *model;
+@property (copy, nonatomic, readwrite, nullable) NSString *trim;
+@property (copy, nonatomic, readwrite, nullable) NSString *modelYear;
+@property (copy, nonatomic, readwrite, nullable) NSString *systemSoftwareVersion;
+@property (copy, nonatomic, readwrite, nullable) NSString *systemHardwareVersion;
@end
@implementation SDLControlFramePayloadRPCStartServiceAck
-- (instancetype)initWithHashId:(int32_t)hashId
- mtu:(int64_t)mtu
- authToken:(nullable NSString *)authToken
- protocolVersion:(nullable NSString *)protocolVersion
- secondaryTransports:(nullable NSArray<NSString *> *)secondaryTransports
- audioServiceTransports:(nullable NSArray<NSNumber *> *)audioServiceTransports
- videoServiceTransports:(nullable NSArray<NSNumber *> *)videoServiceTransports {
+- (instancetype)initWithHashId:(int32_t)hashId mtu:(int64_t)mtu authToken:(nullable NSString *)authToken protocolVersion:(nullable NSString *)protocolVersion secondaryTransports:(nullable NSArray<NSString *> *)secondaryTransports audioServiceTransports:(nullable NSArray<NSNumber *> *)audioServiceTransports videoServiceTransports:(nullable NSArray<NSNumber *> *)videoServiceTransports make:(nullable NSString *)make model:(nullable NSString *)model trim:(nullable NSString *)trim modelYear:(nullable NSString *)modelYear systemSoftwareVersion:(nullable NSString *)systemSoftwareVersion systemHardwareVersion:(nullable NSString *)systemHardwareVersion {
self = [super init];
if (!self) return nil;
@@ -46,6 +46,12 @@ NS_ASSUME_NONNULL_BEGIN
_secondaryTransports = secondaryTransports;
_audioServiceTransports = audioServiceTransports;
_videoServiceTransports = videoServiceTransports;
+ _make = make;
+ _model = model;
+ _trim = trim;
+ _modelYear = modelYear;
+ _systemSoftwareVersion = systemSoftwareVersion;
+ _systemHardwareVersion = systemHardwareVersion;
return self;
}
@@ -105,6 +111,30 @@ NS_ASSUME_NONNULL_BEGIN
[self sdl_addServiceTransports:&payloadObject fromArray:self.audioServiceTransports forKey:SDLControlFrameAudioServiceTransportsKey];
[self sdl_addServiceTransports:&payloadObject fromArray:self.videoServiceTransports forKey:SDLControlFrameVideoServiceTransportsKey];
+ if (self.make != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleMakeKey, (char *)self.make.UTF8String);
+ }
+
+ if (self.model != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleModelKey, (char *)self.model.UTF8String);
+ }
+
+ if (self.trim != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleTrimKey, (char *)self.trim.UTF8String);
+ }
+
+ if (self.modelYear != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleModelYearKey, (char *)self.modelYear.UTF8String);
+ }
+
+ if (self.systemSoftwareVersion != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleSoftwareVersionKey, (char *)self.systemSoftwareVersion.UTF8String);
+ }
+
+ if (self.systemHardwareVersion != nil) {
+ bson_object_put_string(&payloadObject, SDLControlFrameVehicleHardwareVersionKey, (char *)self.systemHardwareVersion.UTF8String);
+ }
+
BytePtr bsonData = bson_object_to_bytes(&payloadObject);
NSUInteger length = bson_object_size(&payloadObject);
@@ -148,6 +178,36 @@ NS_ASSUME_NONNULL_BEGIN
self.audioServiceTransports = [self sdl_getServiceTransports:&payloadObject forKey:SDLControlFrameAudioServiceTransportsKey];
self.videoServiceTransports = [self sdl_getServiceTransports:&payloadObject forKey:SDLControlFrameVideoServiceTransportsKey];
+ char *makeString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleMakeKey);
+ if (makeString != NULL) {
+ self.make = [NSString stringWithUTF8String:makeString];
+ }
+
+ char *modelString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleModelKey);
+ if (modelString != NULL) {
+ self.model = [NSString stringWithUTF8String:modelString];
+ }
+
+ char *trimString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleTrimKey);
+ if (trimString != NULL) {
+ self.trim = [NSString stringWithUTF8String:trimString];
+ }
+
+ char *modelYearString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleModelYearKey);
+ if (modelYearString != NULL) {
+ self.modelYear = [NSString stringWithUTF8String:modelYearString];
+ }
+
+ char *softwareVersionString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleSoftwareVersionKey);
+ if (softwareVersionString != NULL) {
+ self.systemSoftwareVersion = [NSString stringWithUTF8String:softwareVersionString];
+ }
+
+ char *hardwareVersionString = bson_object_get_string(&payloadObject, SDLControlFrameVehicleHardwareVersionKey);
+ if (hardwareVersionString != NULL) {
+ self.systemHardwareVersion = [NSString stringWithUTF8String:hardwareVersionString];
+ }
+
bson_object_deinitialize(&payloadObject);
}
diff --git a/SmartDeviceLink/private/SDLEncryptionLifecycleManager.m b/SmartDeviceLink/private/SDLEncryptionLifecycleManager.m
index 8206a021f..a8f7b488d 100644
--- a/SmartDeviceLink/private/SDLEncryptionLifecycleManager.m
+++ b/SmartDeviceLink/private/SDLEncryptionLifecycleManager.m
@@ -25,6 +25,7 @@
#import "SDLRPCResponseNotification.h"
#import "SDLServiceEncryptionDelegate.h"
#import "SDLStateMachine.h"
+#import "SDLSystemInfo.h"
#import "SDLVehicleType.h"
NS_ASSUME_NONNULL_BEGIN
@@ -80,7 +81,6 @@ typedef NSString SDLVehicleMake;
}
}
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_registerAppInterfaceResponseReceived:) name:SDLDidReceiveRegisterAppInterfaceResponse object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_permissionsDidChange:) name:SDLDidChangePermissionsNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_hmiLevelDidChange:) name:SDLDidChangeHMIStatusNotification object:nil];
@@ -92,7 +92,13 @@ typedef NSString SDLVehicleMake;
- (void)startWithProtocol:(SDLProtocol *)protocol {
SDLLogD(@"Starting encryption manager");
_protocol = protocol;
-
+
+ // Set the security manager based on the known system info
+ self.protocol.securityManager = [self sdl_securityManagerForMake:self.connectionManager.systemInfo.vehicleType.make];
+ if ((self.protocol.securityManager != nil) && [self.protocol.securityManager respondsToSelector:@selector(setAppId:)]) {
+ self.protocol.securityManager.appId = self.configuration.lifecycleConfig.fullAppId ? self.configuration.lifecycleConfig.fullAppId : self.configuration.lifecycleConfig.appId;
+ }
+
@synchronized(self.protocol.protocolDelegateTable) {
if (![self.protocol.protocolDelegateTable containsObject:self]) {
[self.protocol.protocolDelegateTable addObject:self];
@@ -238,16 +244,6 @@ typedef NSString SDLVehicleMake;
#pragma mark - Notifications
-- (void)sdl_registerAppInterfaceResponseReceived:(SDLRPCResponseNotification *)notification {
- if (![notification isResponseMemberOfClass:[SDLRegisterAppInterfaceResponse class]]) { return; }
-
- SDLRegisterAppInterfaceResponse *registerResponse = notification.response;
- self.protocol.securityManager = [self sdl_securityManagerForMake:registerResponse.vehicleType.make];
- if (self.protocol.securityManager && [self.protocol.securityManager respondsToSelector:@selector(setAppId:)]) {
- self.protocol.securityManager.appId = self.configuration.lifecycleConfig.fullAppId ? self.configuration.lifecycleConfig.fullAppId : self.configuration.lifecycleConfig.appId;
- }
-}
-
- (void)sdl_hmiLevelDidChange:(SDLRPCNotificationNotification *)notification {
if (![notification isNotificationMemberOfClass:[SDLOnHMIStatus class]]) { return; }
diff --git a/SmartDeviceLink/private/SDLError.h b/SmartDeviceLink/private/SDLError.h
index 4b3099a84..1621d8f1b 100644
--- a/SmartDeviceLink/private/SDLError.h
+++ b/SmartDeviceLink/private/SDLError.h
@@ -65,6 +65,11 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSError *)sdl_choiceSetManager_failedToCreateMenuItems;
+ (NSError *)sdl_choiceSetManager_incorrectState:(NSString *)state;
+#pragma mark Alert Manager
+
++ (NSError *)sdl_alertManager_presentationFailedWithError:(NSError *)error tryAgainTime:(int)tryAgainTime;
++ (NSError *)sdl_alertManager_alertDataInvalid;
++ (NSError *)sdl_alertManager_alertAudioFileNotSupported;
#pragma mark System Capability Manager
@@ -99,6 +104,8 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSException *)sdl_missingHandlerException;
+ (NSException *)sdl_missingIdException;
+ (NSException *)sdl_missingFilesException;
++ (NSException *)sdl_invalidTTSSpeechCapabilitiesException;
++ (NSException *)sdl_invalidAlertSoftButtonStatesException;
+ (NSException *)sdl_invalidSoftButtonStateException;
+ (NSException *)sdl_carWindowOrientationException;
+ (NSException *)sdl_invalidLockscreenSetupException;
diff --git a/SmartDeviceLink/private/SDLError.m b/SmartDeviceLink/private/SDLError.m
index 0874e0674..35818d361 100644
--- a/SmartDeviceLink/private/SDLError.m
+++ b/SmartDeviceLink/private/SDLError.m
@@ -302,6 +302,37 @@ NS_ASSUME_NONNULL_BEGIN
return [NSError errorWithDomain:SDLErrorDomainChoiceSetManager code:SDLChoiceSetManagerErrorInvalidState userInfo:userInfo];
}
+#pragma mark Alert Manager
+
++ (NSError *)sdl_alertManager_presentationFailedWithError:(NSError *)error tryAgainTime:(int)tryAgainTime {
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: @"The alert presentation failed",
+ NSLocalizedFailureReasonErrorKey: @"Either the alert failed to present on the module or it was dismissed early after being shown",
+ NSLocalizedRecoverySuggestionErrorKey: @"Please check the \"error\" key and the \"tryAgainTime\" keys for more information",
+ @"tryAgainTime": @(tryAgainTime),
+ @"error": error
+ };
+ return [NSError errorWithDomain:SDLErrorDomainAlertManager code:SDLAlertManagerPresentationError userInfo:userInfo];
+}
+
++ (NSError *)sdl_alertManager_alertDataInvalid {
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: @"The alert data is invalid",
+ NSLocalizedFailureReasonErrorKey: @"At least either text, secondaryText or audio needs to be provided",
+ NSLocalizedRecoverySuggestionErrorKey: @"Make sure to set at least the text, secondaryText or audio properties on the SDLAlertView"
+ };
+ return [NSError errorWithDomain:SDLErrorDomainAlertManager code:SDLAlertManagerInvalidDataError userInfo:userInfo];
+}
+
++ (NSError *)sdl_alertManager_alertAudioFileNotSupported {
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: @"The module does not support the use of only audio file data in an alert",
+ NSLocalizedFailureReasonErrorKey: @"The alert has no data and can not be sent to the module",
+ NSLocalizedRecoverySuggestionErrorKey: @"The use of audio file data in an alert is only supported on modules supporting RPC Spec v5.0 or newer"
+ };
+ return [NSError errorWithDomain:SDLErrorDomainAlertManager code:SDLAlertManagerInvalidDataError userInfo:userInfo];
+}
+
#pragma mark System Capability Manager
+ (NSError *)sdl_systemCapabilityManager_moduleDoesNotSupportSystemCapabilities {
@@ -432,6 +463,14 @@ NS_ASSUME_NONNULL_BEGIN
userInfo:nil];
}
++ (NSException *)sdl_invalidTTSSpeechCapabilitiesException {
+ return [NSException exceptionWithName:@"InvalidTTSSpeechCapabilities" reason:@"Attempting to create a text-to-speech string with an invalid phonetic type. The phoneticType must be of type `SAPI_PHONEMES`, `LHPLUS_PHONEMES`, `TEXT`, or `PRE_RECORDED`." userInfo:nil];
+}
+
++ (NSException *)sdl_invalidAlertSoftButtonStatesException {
+ return [NSException exceptionWithName:@"InvalidSoftButtonStates" reason:@"Attempting to create a soft button for an Alert with more than one state. Alerts only support soft buttons with one state" userInfo:nil];
+}
+
+ (NSException *)sdl_invalidSoftButtonStateException {
return [NSException exceptionWithName:@"InvalidSoftButtonState" reason:@"Attempting to transition to a state that does not exist" userInfo:nil];
}
diff --git a/SmartDeviceLink/private/SDLGlobals.m b/SmartDeviceLink/private/SDLGlobals.m
index 5bfa5796a..c9a36c6c2 100644
--- a/SmartDeviceLink/private/SDLGlobals.m
+++ b/SmartDeviceLink/private/SDLGlobals.m
@@ -15,7 +15,7 @@
NS_ASSUME_NONNULL_BEGIN
// VERSION DEPENDENT CODE
-NSString *const SDLMaxProxyProtocolVersion = @"5.3.0";
+NSString *const SDLMaxProxyProtocolVersion = @"5.4.0";
NSString *const SDLMaxProxyRPCVersion = @"7.1.0";
NSUInteger const SDLDefaultMTUSize = UINT32_MAX;
diff --git a/SmartDeviceLink/private/SDLLifecycleManager.h b/SmartDeviceLink/private/SDLLifecycleManager.h
index 1911c4877..fdda17f40 100644
--- a/SmartDeviceLink/private/SDLLifecycleManager.h
+++ b/SmartDeviceLink/private/SDLLifecycleManager.h
@@ -35,6 +35,7 @@
@class SDLStateMachine;
@class SDLStreamingMediaManager;
@class SDLSystemCapabilityManager;
+@class SDLSystemInfo;
@protocol SDLManagerDelegate;
@@ -83,6 +84,7 @@ typedef void (^SDLManagerReadyBlock)(BOOL success, NSError *_Nullable error);
@property (copy, nonatomic, nullable) SDLVideoStreamingState videoStreamingState;
@property (copy, nonatomic, nullable) SDLSystemContext systemContext;
@property (strong, nonatomic, nullable) SDLRegisterAppInterfaceResponse *registerResponse;
+@property (strong, nonatomic, nullable) SDLSystemInfo *systemInfo;
@property (strong, nonatomic) NSOperationQueue *rpcOperationQueue;
diff --git a/SmartDeviceLink/private/SDLLifecycleManager.m b/SmartDeviceLink/private/SDLLifecycleManager.m
index c81dc6dd0..45e84e531 100644
--- a/SmartDeviceLink/private/SDLLifecycleManager.m
+++ b/SmartDeviceLink/private/SDLLifecycleManager.m
@@ -60,6 +60,7 @@
#import "SDLStreamingMediaConfiguration.h"
#import "SDLStreamingMediaManager.h"
#import "SDLSystemCapabilityManager.h"
+#import "SDLSystemInfo.h"
#import "SDLTCPTransport.h"
#import "SDLUnregisterAppInterface.h"
#import "SDLVersion.h"
@@ -168,7 +169,7 @@ NSString *const BackgroundTaskTransportName = @"com.sdl.transport.backgroundTask
_permissionManager = [[SDLPermissionManager alloc] init];
_lockScreenManager = [[SDLLockScreenManager alloc] initWithConfiguration:_configuration.lockScreenConfig notificationDispatcher:_notificationDispatcher presenter:[[SDLLockScreenPresenter alloc] init]];
_systemCapabilityManager = [[SDLSystemCapabilityManager alloc] initWithConnectionManager:self];
- _screenManager = [[SDLScreenManager alloc] initWithConnectionManager:self fileManager:_fileManager systemCapabilityManager:_systemCapabilityManager];
+ _screenManager = [[SDLScreenManager alloc] initWithConnectionManager:self fileManager:_fileManager systemCapabilityManager:_systemCapabilityManager permissionManager:_permissionManager];
if ([self.class sdl_isStreamingConfiguration:self.configuration]) {
_streamManager = [[SDLStreamingMediaManager alloc] initWithConnectionManager:self configuration:configuration systemCapabilityManager:self.systemCapabilityManager];
@@ -374,6 +375,21 @@ NSString *const BackgroundTaskTransportName = @"com.sdl.transport.backgroundTask
return;
}
+ // If we received vehicle details in the protocol layer, we need to check if the developer wants to disconnect
+ self.systemInfo = self.protocolHandler.protocol.systemInfo;
+ if (self.systemInfo != nil) {
+ SDLLogD(@"System info received via protocol layer: %@", self.systemInfo);
+ if ([self.delegate respondsToSelector:@selector(didReceiveSystemInfo:)]) {
+ BOOL shouldConnect = [self.delegate didReceiveSystemInfo:self.systemInfo];
+ if (!shouldConnect) {
+ SDLLogW(@"Developer chose to disconnect from the head unit; disconnecting now");
+ [self.protocolHandler.protocol endServiceWithType:SDLServiceTypeRPC];
+ [self sdl_transitionToState:SDLLifecycleStateStopped];
+ return;
+ }
+ }
+ }
+
// Build a register app interface request with the configuration data
SDLRegisterAppInterface *regRequest = [[SDLRegisterAppInterface alloc] initWithLifecycleConfiguration:self.configuration.lifecycleConfig];
@@ -396,7 +412,7 @@ NSString *const BackgroundTaskTransportName = @"com.sdl.transport.backgroundTask
weakSelf.registerResponse = (SDLRegisterAppInterfaceResponse *)response;
[SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithSDLMsgVersion:weakSelf.registerResponse.sdlMsgVersion];
- SDLLogD(@"Did register app; RPC version: %@, SDL version: %@, starting languages: (VR) %@, (HMI) %@, vehicle type: %@", weakSelf.registerResponse.sdlMsgVersion, (weakSelf.registerResponse.sdlVersion ?: @"unavailable"), weakSelf.registerResponse.language, weakSelf.registerResponse.hmiDisplayLanguage, weakSelf.registerResponse.vehicleType);
+ SDLLogD(@"Did register app; RPC version: %@, starting languages: (VR) %@, (HMI) %@", weakSelf.registerResponse.sdlMsgVersion, weakSelf.registerResponse.language, weakSelf.registerResponse.hmiDisplayLanguage);
[weakSelf sdl_transitionToState:SDLLifecycleStateRegistered];
}];
@@ -410,6 +426,29 @@ NSString *const BackgroundTaskTransportName = @"com.sdl.transport.backgroundTask
return;
}
+ // If we did not receive vehicle details in the protocol layer, we need to check if the developer wants to disconnect based on vehicle details from the RAIR
+ if (self.systemInfo == nil) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+ SDLVehicleType *vehicleType = self.registerResponse.vehicleType;
+ NSString *softwareVersion = self.registerResponse.systemSoftwareVersion;
+#pragma clang diagnostic pop
+ if ((vehicleType != nil) || (softwareVersion != nil)) {
+ self.systemInfo = [[SDLSystemInfo alloc] initWithVehicleType:vehicleType softwareVersion:softwareVersion hardwareVersion:nil];
+ SDLLogD(@"System info received by RPC layer, using RAIR system info: %@", self.systemInfo);
+
+ if ([self.delegate respondsToSelector:@selector(didReceiveSystemInfo:)]) {
+ BOOL shouldConnect = [self.delegate didReceiveSystemInfo:self.systemInfo];
+ if (!shouldConnect) {
+ SDLLogW(@"Developer chose to disconnect from the head unit; disconnecting now");
+ [self.protocolHandler.protocol endServiceWithType:SDLServiceTypeRPC];
+ [self sdl_transitionToState:SDLLifecycleStateStopped];
+ return;
+ }
+ }
+ }
+ }
+
NSArray<SDLLanguage> *supportedLanguages = self.configuration.lifecycleConfig.languagesSupported;
SDLLanguage desiredHMILanguage = self.configuration.lifecycleConfig.language;
SDLLanguage desiredVRLanguage = self.currentVRLanguage;
diff --git a/SmartDeviceLink/private/SDLLogFileModuleMap.m b/SmartDeviceLink/private/SDLLogFileModuleMap.m
index 29834a1d0..44b6b47dd 100644
--- a/SmartDeviceLink/private/SDLLogFileModuleMap.m
+++ b/SmartDeviceLink/private/SDLLogFileModuleMap.m
@@ -36,6 +36,7 @@
[self sdl_screenManagerSubscribeButtonModule],
[self sdl_screenManagerMenuModule],
[self sdl_screenManagerChoiceSetModule],
+ [self sdl_screenManagerAlertModule],
[self sdl_utilitiesModule]]];
}
@@ -129,6 +130,10 @@
return [SDLLogFileModule moduleWithName:@"Screen/SubscribeButton" files:[NSSet setWithArray:@[@"SDLSubscribeButtonManager", @"SDLSubscribeButtonObserver"]]];
}
++ (SDLLogFileModule *)sdl_screenManagerAlertModule {
+ return [SDLLogFileModule moduleWithName:@"Screen/Alert" files:[NSSet setWithArray:@[@"SDLAlertManager", @"SDLAlertView", @"SDLAlertAudioData", @"SDLPresentAlertOperation"]]];
+}
+
+ (SDLLogFileModule *)sdl_screenManagerMenuModule {
return [SDLLogFileModule moduleWithName:@"Screen/Menu" files:[NSSet setWithArray:@[@"SDLMenuManager", @"SDLVoiceCommandManager", @"SDLVoiceCommandUpdateOperation"]]];
}
diff --git a/SmartDeviceLink/private/SDLMenuManager.m b/SmartDeviceLink/private/SDLMenuManager.m
index 603ef9c73..383b3f220 100644
--- a/SmartDeviceLink/private/SDLMenuManager.m
+++ b/SmartDeviceLink/private/SDLMenuManager.m
@@ -41,7 +41,6 @@
#import "SDLWindowCapability+ScreenManagerExtensions.h"
#import "SDLVersion.h"
#import "SDLVoiceCommand.h"
-#import "SDLError.h"
NS_ASSUME_NONNULL_BEGIN
@@ -107,7 +106,7 @@ UInt32 const MenuCellIdMin = 1;
}
- (void)start {
- [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate:)];
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate)];
}
- (void)stop {
@@ -725,8 +724,8 @@ UInt32 const MenuCellIdMin = 1;
params.menuName = cell.uniqueTitle;
params.parentID = cell.parentCellId != UINT32_MAX ? @(cell.parentCellId) : nil;
params.position = @(position);
- params.tertiaryText = cell.tertiaryText;
- params.secondaryText = cell.secondaryText;
+ params.secondaryText = (cell.secondaryText.length == 0) ? nil : cell.secondaryText;
+ params.tertiaryText = (cell.tertiaryText.length == 0) ? nil : cell.tertiaryText;
command.menuParams = params;
command.vrCommands = (cell.voiceCommands.count == 0) ? nil : cell.voiceCommands;
@@ -747,7 +746,10 @@ UInt32 const MenuCellIdMin = 1;
} else {
submenuLayout = self.menuConfiguration.defaultSubmenuLayout;
}
- return [[SDLAddSubMenu alloc] initWithMenuID:cell.cellId menuName:cell.uniqueTitle position:@(position) menuIcon:icon menuLayout:submenuLayout parentID:nil secondaryText:cell.secondaryText tertiaryText:cell.tertiaryText secondaryImage:secondaryImage];
+
+ NSString *secondaryText = (cell.secondaryText.length == 0) ? nil : cell.secondaryText;
+ NSString *tertiaryText = (cell.tertiaryText.length == 0) ? nil : cell.tertiaryText;
+ return [[SDLAddSubMenu alloc] initWithMenuID:cell.cellId menuName:cell.uniqueTitle position:@(position) menuIcon:icon menuLayout:submenuLayout parentID:nil secondaryText:secondaryText tertiaryText:tertiaryText secondaryImage:secondaryImage];
}
#pragma mark - Calling handlers
@@ -776,8 +778,7 @@ UInt32 const MenuCellIdMin = 1;
[self sdl_callHandlerForCells:self.menuCells command:onCommand];
}
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability {
- // We won't use the object in the parameter but the convenience method of the system capability manager
+- (void)sdl_displayCapabilityDidUpdate {
self.windowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
}
diff --git a/SmartDeviceLink/private/SDLPresentAlertOperation.h b/SmartDeviceLink/private/SDLPresentAlertOperation.h
new file mode 100644
index 000000000..22cd56fb3
--- /dev/null
+++ b/SmartDeviceLink/private/SDLPresentAlertOperation.h
@@ -0,0 +1,38 @@
+//
+// SDLPresentAlertOperation.h
+// SmartDeviceLink
+//
+// Created by Nicole on 11/12/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAsynchronousOperation.h"
+
+@class SDLAlertView;
+@class SDLFileManager;
+@class SDLSystemCapabilityManager;
+@class SDLWindowCapability;
+
+@protocol SDLConnectionManagerType;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Operation that handles uploading images and audio data needed by the alert and, once the data uploads are complete, sending the alert.
+@interface SDLPresentAlertOperation : SDLAsynchronousOperation
+
+/// The current window capabilities
+@property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability;
+
+/// An operation to present an alert.
+/// @param connectionManager The connection manager
+/// @param fileManager The file manager
+/// @param systemCapabilityManager The system capability manager
+/// @param currentWindowCapability The current window capability
+/// @param alertView The alert to be displayed
+/// @param cancelID A unique ID for this specific choice set that allows cancellation through the `CancelInteraction` RPC
+/// @return A SDLPresentAlertOperation object
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager currentWindowCapability:(nullable SDLWindowCapability *)currentWindowCapability alertView:(SDLAlertView *)alertView cancelID:(UInt16)cancelID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/private/SDLPresentAlertOperation.m b/SmartDeviceLink/private/SDLPresentAlertOperation.m
new file mode 100644
index 000000000..6999bf55d
--- /dev/null
+++ b/SmartDeviceLink/private/SDLPresentAlertOperation.m
@@ -0,0 +1,451 @@
+//
+// SDLPresentAlertOperation.m
+// SmartDeviceLink
+//
+// Created by Nicole on 11/12/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLPresentAlertOperation.h"
+
+#import "SDLAlert.h"
+#import "SDLAlertAudioData.h"
+#import "SDLAlertResponse.h"
+#import "SDLAlertView.h"
+#import "SDLArtwork.h"
+#import "SDLCancelInteraction.h"
+#import "SDLConnectionManagerType.h"
+#import "SDLError.h"
+#import "SDLFile.h"
+#import "SDLFileManager.h"
+#import "SDLGlobals.h"
+#import "SDLLogMacros.h"
+#import "SDLSoftButton.h"
+#import "SDLSoftButtonCapabilities.h"
+#import "SDLSoftButtonObject.h"
+#import "SDLSoftButtonState.h"
+#import "SDLSystemCapabilityManager.h"
+#import "SDLTextField.h"
+#import "SDLTTSChunk.h"
+#import "SDLVersion.h"
+#import "SDLWindowCapability.h"
+#import "SDLWindowCapability+ScreenManagerExtensions.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+static const int SDLAlertSoftButtonIDMin = 10;
+static const int SDLAlertSoftButtonCount = 4;
+
+@interface SDLAlertAudioData()
+
+@property (nullable, copy, nonatomic, readonly) NSDictionary<SDLFileName *, SDLFile *> *audioFileData;
+
+@end
+
+@interface SDLAlertView()
+
+/// Handler called when the alert should be dismissed.
+@property (copy, nonatomic) SDLAlertCanceledHandler canceledHandler;
+
+@end
+
+@interface SDLSoftButtonObject()
+
+/// Unique id assigned to the soft button.
+@property (assign, nonatomic) NSUInteger buttonId;
+
+@end
+
+@interface SDLPresentAlertOperation()
+
+@property (strong, nonatomic) NSUUID *operationId;
+@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
+@property (weak, nonatomic) SDLFileManager *fileManager;
+@property (weak, nonatomic) SDLSystemCapabilityManager *systemCapabilityManager;
+@property (strong, nonatomic, readwrite) SDLAlertView *alertView;
+@property (assign, nonatomic) UInt16 cancelId;
+@property (copy, nonatomic, nullable) NSError *internalError;
+@property (assign, atomic) BOOL isAlertPresented;
+
+@end
+
+@implementation SDLPresentAlertOperation
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager currentWindowCapability:(nullable SDLWindowCapability *)currentWindowCapability alertView:(SDLAlertView *)alertView cancelID:(UInt16)cancelID {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _connectionManager = connectionManager;
+ _fileManager = fileManager;
+ _systemCapabilityManager = systemCapabilityManager;
+
+ __weak typeof(self) weakSelf = self;
+ alertView.canceledHandler = ^{
+ [weakSelf sdl_cancelInteraction];
+ };
+ _alertView = [alertView copy];
+
+ _cancelId = cancelID;
+ _operationId = [NSUUID UUID];
+ _currentWindowCapability = currentWindowCapability;
+
+ return self;
+}
+
+- (void)start {
+ [super start];
+ if (self.isCancelled) { return; }
+
+ NSError *alertViewValidatedError = [self sdl_isValidAlertViewData:self.alertView];
+ if (alertViewValidatedError != nil) {
+ [self finishOperation];
+ self.internalError = alertViewValidatedError;
+ return;
+ }
+
+ dispatch_group_t uploadFilesTask = dispatch_group_create();
+ dispatch_group_enter(uploadFilesTask);
+
+ dispatch_group_enter(uploadFilesTask);
+ [self sdl_uploadImagesWithCompletionHandler:^{
+ dispatch_group_leave(uploadFilesTask);
+ }];
+
+ dispatch_group_enter(uploadFilesTask);
+ [self sdl_uploadAudioFilesWithCompletionHandler:^{
+ dispatch_group_leave(uploadFilesTask);
+ }];
+
+ dispatch_group_leave(uploadFilesTask);
+ // This will always run after all `leave`s
+ __weak typeof(self) weakSelf = self;
+ dispatch_group_notify(uploadFilesTask, [SDLGlobals sharedGlobals].sdlConcurrentQueue, ^{
+ __strong typeof(weakSelf) strongSelf = weakSelf;
+ [strongSelf sdl_presentAlert];
+ });
+}
+
+/// Checks the `AlertView` data to make sure it conforms to the RPC Spec, which says that at least either `alertText1`, `alertText2` or `TTSChunks` need to be provided.
+/// @return The error if the alert view does not have valid data; nil if the alert view data is valid
+- (nullable NSError *)sdl_isValidAlertViewData:(SDLAlertView *)alertView {
+ BOOL isValidData = NO;
+ if ((alertView.text.length > 0)
+ || (alertView.secondaryText.length > 0)
+ || ([self sdl_ttsChunksForAlertView:alertView].count > 0)) {
+ isValidData = YES;
+ }
+
+ if (isValidData) {
+ return nil;
+ } else if (alertView.audio.audioData.count > 0) {
+ return [NSError sdl_alertManager_alertAudioFileNotSupported];
+ } else {
+ return [NSError sdl_alertManager_alertDataInvalid];
+ }
+}
+
+#pragma mark Uploads
+
+/// Upload the alert audio files.
+/// @param handler Called when all audio files have been uploaded
+- (void)sdl_uploadAudioFilesWithCompletionHandler:(void (^)(void))handler {
+ if (![self sdl_supportsAlertAudioFile]) {
+ SDLLogD(@"Module does not support audio files for alerts, skipping upload of audio files");
+ return handler();
+ }
+
+ NSMutableArray<SDLFile *> *filesToBeUploaded = [NSMutableArray array];
+ for (SDLTTSChunk *ttsChunk in self.alertView.audio.audioData) {
+ if (ttsChunk.type != SDLSpeechCapabilitiesFile) { continue; }
+
+ SDLFile *audioFile = self.alertView.audio.audioFileData[ttsChunk.text];
+ if (![self.fileManager fileNeedsUpload:audioFile]) { continue; }
+ [filesToBeUploaded addObject:audioFile];
+ }
+
+ if (filesToBeUploaded.count == 0) {
+ SDLLogV(@"No audio files need to be uploaded for alert");
+ return handler();
+ }
+
+ SDLLogD(@"Uploading audio files for alert");
+ __weak typeof(self) weakself = self;
+ [self.fileManager uploadFiles:filesToBeUploaded progressHandler:^BOOL(SDLFileName * _Nonnull fileName, float uploadPercentage, NSError * _Nullable error) {
+ __strong typeof(weakself) strongself = weakself;
+ SDLLogD(@"Uploaded alert audio file: %@, error: %@, percent complete: %f.2%%", fileName, error, uploadPercentage * 100);
+ if (strongself.isCancelled) { return NO; }
+
+ return YES;
+ } completionHandler:^(NSError * _Nullable error) {
+ if (error != nil) {
+ SDLLogE(@"Error uploading alert audio files: %@", error);
+ } else {
+ SDLLogD(@"All alert audio files uploaded");
+ }
+
+ handler();
+ }];
+}
+
+/// Upload the alert icon and soft button images.
+/// @param handler Called when all images have been uploaded.
+- (void)sdl_uploadImagesWithCompletionHandler:(void (^)(void))handler {
+ NSMutableArray<SDLArtwork *> *artworksToBeUploaded = [NSMutableArray array];
+ if ([self sdl_supportsAlertIcon] && [self.fileManager fileNeedsUpload:self.alertView.icon]) {
+ [artworksToBeUploaded addObject:self.alertView.icon];
+ }
+
+ // Don't upload artworks for buttons that will not be shown.
+ for (NSUInteger i = 0; i < [self sdl_softButtonCount]; i++) {
+ SDLSoftButtonObject *object = self.alertView.softButtons[i];
+ if ([self sdl_supportsSoftButtonImages] && [self.fileManager fileNeedsUpload:object.currentState.artwork]) {
+ [artworksToBeUploaded addObject:object.currentState.artwork];
+ }
+ }
+
+ if (artworksToBeUploaded.count == 0) {
+ SDLLogV(@"No images to upload for alert");
+ return handler();
+ }
+
+ SDLLogD(@"Uploading images for alert");
+ __weak typeof(self) weakself = self;
+ [self.fileManager uploadArtworks:[artworksToBeUploaded copy] progressHandler:^BOOL(NSString * _Nonnull artworkName, float uploadPercentage, NSError * _Nullable error) {
+ __strong typeof(weakself) strongself = weakself;
+ SDLLogD(@"Uploaded alert images: %@, error: %@, percent complete: %f.2%%", artworkName, error, uploadPercentage * 100);
+ if (strongself.isCancelled) { return NO; }
+
+ return YES;
+ } completionHandler:^(NSArray<NSString *> * _Nonnull artworkNames, NSError * _Nullable error) {
+ if (error != nil) {
+ SDLLogE(@"Error uploading alert images: %@", error);
+ } else {
+ SDLLogD(@"All alert images uploaded");
+ }
+
+ return handler();
+ }];
+}
+
+/// Sends the alert RPC to the module. The operation is finished once a response has been received from the module.
+- (void)sdl_presentAlert {
+ if (self.isCancelled) { return [self finishOperation]; }
+
+ self.isAlertPresented = YES;
+
+ __weak typeof(self) weakSelf = self;
+ [self.connectionManager sendConnectionRequest:self.alertRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ __strong typeof(weakSelf) strongSelf = weakSelf;
+ if (error != nil) {
+ SDLAlertResponse *alertResponse = (SDLAlertResponse *)response;
+ strongSelf.internalError = [NSError sdl_alertManager_presentationFailedWithError:error tryAgainTime:alertResponse.tryAgainTime.intValue];
+ }
+
+ [strongSelf finishOperation];
+ }];
+}
+
+#pragma mark - Cancel
+
+/// Cancels the alert. If the alert has not yet been sent to the module, it will not be sent. If the alert is already presented on the module, the alert will be immediately dismissed. Canceling an already presented alert will only work if connected to modules supporting RPC spec versions 6.0+. On older versions alert will not be dismissed.
+- (void)sdl_cancelInteraction {
+ if (self.isFinished) {
+ SDLLogW(@"This operation has already finished so it can not be canceled.");
+ return;
+ } else if (self.isCancelled) {
+ SDLLogW(@"This operation has already been canceled. It will be finished at some point during the operation.");
+ return;
+ } else if (self.isExecuting) {
+ if ([SDLGlobals.sharedGlobals.rpcVersion isLessThanVersion:[[SDLVersion alloc] initWithMajor:6 minor:0 patch:0]]) {
+ SDLLogD(@"Attempting to cancel this operation in-progress; if the alert is already presented on the module, it cannot be dismissed.");
+ [self cancel];
+ return;
+ } else if (self.isAlertPresented == NO) {
+ SDLLogD(@"Alert has not yet been sent to the module. Alert will not be shown.");
+ [self cancel];
+ return;
+ }
+
+ SDLLogD(@"Canceling the presented alert");
+ __weak typeof(self) weakSelf = self;
+ SDLCancelInteraction *cancelInteraction = [[SDLCancelInteraction alloc] initWithAlertCancelID:self.cancelId];
+ [self.connectionManager sendConnectionRequest:cancelInteraction withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ if (error != nil) {
+ weakSelf.internalError = error;
+ SDLLogE(@"Error canceling the presented alert: %@, with error: %@", request, error);
+ return;
+ }
+ SDLLogD(@"The presented alert was canceled successfully");
+ }];
+ } else {
+ SDLLogD(@"Canceling an alert that has not started: %@", self);
+ [self cancel];
+ }
+}
+
+#pragma mark - Private Getters / Setters
+
+/// Assembles an `Alert` RPC from the `SDLAlertView` information.
+/// @return The `Alert` RPC to be sent to the module.
+- (SDLAlert *)alertRPC {
+ SDLAlert *alert = [[SDLAlert alloc] init];
+ [self sdl_assembleAlertText:alert];
+ alert.duration = @((NSUInteger)(self.alertView.timeout * 1000));
+ alert.alertIcon = ([self sdl_supportsAlertIcon] && ![self.fileManager fileNeedsUpload:self.alertView.icon]) ? self.alertView.icon.imageRPC : nil;
+ alert.progressIndicator = @(self.alertView.showWaitIndicator);
+ alert.cancelID = @(self.cancelId);
+
+ // The number of alert soft buttons sent must be capped so there are no clashes with soft button ids assigned by other managers (And thus leading to clashes saving/retreiving the button handlers in the `SDLResponseDispatcher` class)
+ NSMutableArray<SDLSoftButton *> *softButtons = [NSMutableArray arrayWithCapacity:[self sdl_softButtonCount]];
+ for (NSUInteger i = 0; i < [self sdl_softButtonCount]; i += 1) {
+ SDLSoftButtonObject *button = self.alertView.softButtons[i];
+ button.buttonId = SDLAlertSoftButtonIDMin + i;
+ [softButtons addObject:button.currentStateSoftButton.copy];
+ }
+ alert.softButtons = softButtons;
+
+ alert.playTone = @(self.alertView.audio.playTone);
+ alert.ttsChunks = [self sdl_ttsChunksForAlertView:self.alertView];
+
+ return alert;
+}
+
+/// Checks the number of soft buttons added to the alert view against the max number of soft buttons allowed by the RPC Spec and returns the smaller of the two values.
+/// @return The maximum number of soft buttons that can be sent to the module
+- (unsigned long)sdl_softButtonCount {
+ return MIN(self.alertView.softButtons.count, SDLAlertSoftButtonCount);
+}
+
+/// Creates an array of text-to-speech chunks for the `Alert` RPC from the text strings and the audio data files.
+/// @param alertView The alert view
+/// @return An array of TTS chunks or nil if there are no TTS chunks
+- (nullable NSArray<SDLTTSChunk *> *)sdl_ttsChunksForAlertView:(SDLAlertView *)alertView {
+ SDLAlertAudioData *alertAudio = alertView.audio;
+ NSMutableArray<SDLTTSChunk *> *ttsChunks = [NSMutableArray array];
+
+ for (SDLTTSChunk *audioData in alertAudio.audioData) {
+ // If the audio data is a file and the connected system doesn't support files, skip that audio data
+ if (audioData.type == SDLSpeechCapabilitiesFile && ![self sdl_supportsAlertAudioFile]) { continue; }
+ [ttsChunks addObject:audioData];
+ }
+
+ return ttsChunks.count > 0 ? [ttsChunks copy] : nil;
+}
+
+/// Checks if the connected module or current template supports soft button images.
+/// @return True if soft button images are currently supported; false if not.
+- (BOOL)sdl_supportsSoftButtonImages {
+ return self.currentWindowCapability.softButtonCapabilities.firstObject.imageSupported.boolValue;
+}
+
+/// Checks if the connected module supports audio files. Using an audio file in an alert will only work if connected to modules supporting RPC spec versions 5.0+. If the module does not return a speechCapabilities, assume that the module supports playing an audio file.
+/// @return True if the module supports playing audio files in an alert; false if not.
+- (BOOL)sdl_supportsAlertAudioFile {
+ NSUInteger majorVersion = [SDLGlobals sharedGlobals].rpcVersion.major;
+ BOOL supportSpeechCapabilities = (self.systemCapabilityManager.speechCapabilities != nil) ? [self.systemCapabilityManager.speechCapabilities containsObject:SDLSpeechCapabilitiesFile] : YES;
+ return (majorVersion >= 5 && supportSpeechCapabilities);
+}
+
+/// Checks if the connected module or current template supports alert icons.
+/// @return True if alert icons are currently supported; false if not.
+- (BOOL)sdl_supportsAlertIcon {
+ return [self.currentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon];
+}
+
+#pragma mark - Text Helpers
+
+/// Populates the alert RPC text-fields based on the number of text-fields the current template supports. If more text-fields are set in the SDLAlertView than the template supports, the text is concancated so all text fits in the currently available text-fields.
+/// @param alert The alert RPC with no text-fields set
+/// @return An alert RPC with the text-fields set
+- (SDLAlert *)sdl_assembleAlertText:(SDLAlert *)alert {
+ NSArray *nonNilFields = [self sdl_findNonNilTextFields];
+ if (nonNilFields.count == 0) { return alert; }
+
+ NSUInteger maxNumberOfLines = (self.currentWindowCapability != nil) ? self.currentWindowCapability.maxNumberOfAlertFieldLines : MaxAlertTextFieldLineCount;
+ if (maxNumberOfLines == 1) {
+ alert = [self sdl_assembleOneLineAlertText:alert withAlertFields:nonNilFields];
+ } else if (maxNumberOfLines == 2) {
+ alert = [self sdl_assembleTwoLineAlertText:alert withAlertFields:nonNilFields];
+ } else if (maxNumberOfLines == 3) {
+ alert = [self sdl_assembleThreeLineAlertText:alert withAlertFields:nonNilFields];
+ }
+
+ return alert;
+}
+
+/// Generates a list of all non-empty text-fields set in the SDLAlertView in order from first, second to third.
+/// @return An array of all the text-fields set in the SDLAlertView
+- (NSArray<NSString *> *)sdl_findNonNilTextFields {
+ NSMutableArray *array = [NSMutableArray array];
+ (self.alertView.text.length > 0) ? [array addObject:self.alertView.text] : nil;
+ (self.alertView.secondaryText.length > 0) ? [array addObject:self.alertView.secondaryText] : nil;
+ (self.alertView.tertiaryText.length > 0) ? [array addObject:self.alertView.tertiaryText] : nil;
+
+ return [array copy];
+}
+
+/// Called if the alert template only supports one line of text. A single string is created from all the text and is used to set the first text-field in the alert RPC.
+/// @param alert The alert RPC
+/// @param fields A list all the text set in the SDLAlertView
+/// @return An alert RPC with the text-fields set
+- (SDLAlert *)sdl_assembleOneLineAlertText:(SDLAlert *)alert withAlertFields:(NSArray<NSString *> *)fields {
+ NSMutableString *alertString = [NSMutableString stringWithString:[fields objectAtIndex:0]];
+ for (NSUInteger i = 1; i < fields.count; i+= 1) {
+ [alertString appendFormat:@" - %@", fields[i]];
+ }
+ alert.alertText1 = alertString.copy;
+
+ return alert;
+}
+
+/// Called if the alert template only supports two lines of text. The first text-field in the alert RPC is set with the first available text and the second text-field is set with a single string created from all remaining text.
+/// @param alert The alert RPC
+/// @param fields A list all the text set in the SDLAlertView
+/// @return An alert RPC with the text-fields set
+- (SDLAlert *)sdl_assembleTwoLineAlertText:(SDLAlert *)alert withAlertFields:(NSArray<NSString *> *)fields {
+ if (fields.count <= 2) {
+ alert.alertText1 = fields.count > 0 ? fields[0] : nil;
+ alert.alertText2 = fields.count > 1 ? [fields objectAtIndex:1] : nil;
+ } else {
+ alert.alertText1 = fields.count > 0 ? [fields objectAtIndex:0] : nil;
+ alert.alertText2 = [NSString stringWithFormat:@"%@ - %@", [fields objectAtIndex:1], [fields objectAtIndex:2]];
+ }
+
+ return alert;
+}
+
+/// Called if the alert template supports all three lines of text. Each text-field in the alert RPC is set with its corresponding text.
+/// @param alert The alert RPC
+/// @param fields A list all the text set in the SDLAlertView
+/// @return An alert RPC with the text-fields set
+- (SDLAlert *)sdl_assembleThreeLineAlertText:(SDLAlert *)alert withAlertFields:(NSArray<NSString *> *)fields {
+ alert.alertText1 = fields.count > 0 ? fields[0] : nil;
+ alert.alertText2 = fields.count > 1 ? [fields objectAtIndex:1] : nil;
+ alert.alertText3 = fields.count > 2 ? [fields objectAtIndex:2] : nil;
+ return alert;
+}
+
+#pragma mark - Property Overrides
+
+- (void)finishOperation {
+ SDLLogV(@"Finishing present alert operation");
+ [super finishOperation];
+}
+
+- (nullable NSString *)name {
+ return @"com.sdl.alertManager.present";
+}
+
+- (NSOperationQueuePriority)queuePriority {
+ return NSOperationQueuePriorityNormal;
+}
+
+- (nullable NSError *)error {
+ return self.internalError;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/private/SDLPresentChoiceSetOperation.h b/SmartDeviceLink/private/SDLPresentChoiceSetOperation.h
index df82bfa22..b2589a280 100644
--- a/SmartDeviceLink/private/SDLPresentChoiceSetOperation.h
+++ b/SmartDeviceLink/private/SDLPresentChoiceSetOperation.h
@@ -15,6 +15,7 @@
@class SDLChoiceCell;
@class SDLChoiceSet;
@class SDLKeyboardProperties;
+@class SDLWindowCapability;
@protocol SDLConnectionManagerType;
@protocol SDLKeyboardDelegate;
@@ -54,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
@param cancelID A unique ID for this specific choice set that allows cancellation through the `CancelInteraction` RPC.
@return A SDLPresentChoiceSetOperation object
*/
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager choiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode keyboardProperties:(nullable SDLKeyboardProperties *)originalKeyboardProperties keyboardDelegate:(nullable id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager choiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode keyboardProperties:(nullable SDLKeyboardProperties *)originalKeyboardProperties keyboardDelegate:(nullable id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID windowCapability:(SDLWindowCapability *)windowCapability;
@end
diff --git a/SmartDeviceLink/private/SDLPresentChoiceSetOperation.m b/SmartDeviceLink/private/SDLPresentChoiceSetOperation.m
index f0fbbf28a..121383ce7 100644
--- a/SmartDeviceLink/private/SDLPresentChoiceSetOperation.m
+++ b/SmartDeviceLink/private/SDLPresentChoiceSetOperation.m
@@ -24,6 +24,7 @@
#import "SDLRPCNotificationNotification.h"
#import "SDLSetGlobalProperties.h"
#import "SDLVersion.h"
+#import "SDLWindowCapability+ScreenManagerExtensions.h"
NS_ASSUME_NONNULL_BEGIN
@@ -60,12 +61,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic, readwrite, nullable) SDLChoiceCell *selectedCell;
@property (strong, nonatomic, readwrite, nullable) SDLTriggerSource selectedTriggerSource;
@property (assign, nonatomic, readwrite) NSUInteger selectedCellRow;
+@property (strong, nonatomic) SDLWindowCapability *windowCapability;
@end
@implementation SDLPresentChoiceSetOperation
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager choiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode keyboardProperties:(nullable SDLKeyboardProperties *)originalKeyboardProperties keyboardDelegate:(nullable id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID {
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager choiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode keyboardProperties:(nullable SDLKeyboardProperties *)originalKeyboardProperties keyboardDelegate:(nullable id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID windowCapability:(SDLWindowCapability *)windowCapability {
self = [super init];
if (!self) { return self; }
@@ -86,6 +88,7 @@ NS_ASSUME_NONNULL_BEGIN
_cancelId = cancelID;
_selectedCellRow = NSNotFound;
+ _windowCapability = windowCapability;
return self;
}
@@ -121,15 +124,16 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Sending Requests
- (void)sdl_updateKeyboardPropertiesWithCompletionHandler:(nullable void(^)(void))completionHandler {
- if (self.keyboardProperties == nil) {
+ // Create the keyboard configuration based on the window capability's keyboard capabilities
+ SDLKeyboardProperties *modifiedKeyboardConfig = [self.windowCapability createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:self.keyboardProperties];
+ if (modifiedKeyboardConfig == nil) {
if (completionHandler != nil) {
completionHandler();
}
return;
}
-
SDLSetGlobalProperties *setProperties = [[SDLSetGlobalProperties alloc] init];
- setProperties.keyboardProperties = self.keyboardProperties;
+ setProperties.keyboardProperties = modifiedKeyboardConfig;
__weak typeof(self) weakself = self;
[self.connectionManager sendConnectionRequest:setProperties withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
@@ -295,6 +299,12 @@ NS_ASSUME_NONNULL_BEGIN
} else if ([onKeyboard.event isEqualToEnum:SDLKeyboardEventAborted] || [onKeyboard.event isEqualToEnum:SDLKeyboardEventCancelled]) {
// Notify of abort / cancellation
[self.keyboardDelegate keyboardDidAbortWithReason:onKeyboard.event];
+ } else if ([onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled] || [onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskDisabled]) {
+ // Notify of key mask change
+ if ([self.keyboardDelegate respondsToSelector:@selector(keyboardDidUpdateInputMask:)]) {
+ BOOL isEnabled = [onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ [self.keyboardDelegate keyboardDidUpdateInputMask:isEnabled];
+ }
}
}
diff --git a/SmartDeviceLink/private/SDLPresentKeyboardOperation.h b/SmartDeviceLink/private/SDLPresentKeyboardOperation.h
index 9a5a6cfb5..508c948b4 100644
--- a/SmartDeviceLink/private/SDLPresentKeyboardOperation.h
+++ b/SmartDeviceLink/private/SDLPresentKeyboardOperation.h
@@ -10,6 +10,8 @@
#import "NSNumber+NumberType.h"
@class SDLKeyboardProperties;
+@class SDLWindowCapability;
+
@protocol SDLConnectionManagerType;
@protocol SDLKeyboardDelegate;
@@ -33,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
@param cancelID An ID for this specific keyboard to allow cancellation through the `CancelInteraction` RPC.
@return A SDLPresentKeyboardOperation object
*/
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager keyboardProperties:(SDLKeyboardProperties *)originalKeyboardProperties initialText:(NSString *)initialText keyboardDelegate:(id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager keyboardProperties:(SDLKeyboardProperties *)originalKeyboardProperties initialText:(NSString *)initialText keyboardDelegate:(id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID windowCapability:(SDLWindowCapability *)windowCapability;
/**
Cancels the keyboard-only interface if it is currently showing. If the keyboard has not yet been sent to Core, it will not be sent.
diff --git a/SmartDeviceLink/private/SDLPresentKeyboardOperation.m b/SmartDeviceLink/private/SDLPresentKeyboardOperation.m
index 798e046af..939869680 100644
--- a/SmartDeviceLink/private/SDLPresentKeyboardOperation.m
+++ b/SmartDeviceLink/private/SDLPresentKeyboardOperation.m
@@ -21,6 +21,7 @@
#import "SDLRPCNotificationNotification.h"
#import "SDLSetGlobalProperties.h"
#import "SDLVersion.h"
+#import "SDLWindowCapability+ScreenManagerExtensions.h"
NS_ASSUME_NONNULL_BEGIN
@@ -37,12 +38,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic, readonly) SDLPerformInteraction *performInteraction;
@property (copy, nonatomic, nullable) NSError *internalError;
+@property (strong, nonatomic) SDLWindowCapability *windowCapability;
@end
@implementation SDLPresentKeyboardOperation
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager keyboardProperties:(SDLKeyboardProperties *)originalKeyboardProperties initialText:(NSString *)initialText keyboardDelegate:(id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID {
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager keyboardProperties:(SDLKeyboardProperties *)originalKeyboardProperties initialText:(NSString *)initialText keyboardDelegate:(id<SDLKeyboardDelegate>)keyboardDelegate cancelID:(UInt16)cancelID windowCapability:(SDLWindowCapability *)windowCapability {
self = [super init];
if (!self) { return self; }
@@ -53,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
_keyboardProperties = originalKeyboardProperties;
_cancelId = cancelID;
_operationId = [NSUUID UUID];
+ _windowCapability = windowCapability;
return self;
}
@@ -87,8 +90,16 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Sending Requests
- (void)sdl_updateKeyboardPropertiesWithCompletionHandler:(nullable void(^)(void))completionHandler {
+ // Create the keyboard configuration based on the window capability's keyboard capabilities
+ SDLKeyboardProperties *keyboardConfiguration = [self.windowCapability createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:self.keyboardProperties];
+ if (keyboardConfiguration == nil) {
+ if (completionHandler != nil) {
+ completionHandler();
+ }
+ return;
+ }
SDLSetGlobalProperties *setProperties = [[SDLSetGlobalProperties alloc] init];
- setProperties.keyboardProperties = self.keyboardProperties;
+ setProperties.keyboardProperties = keyboardConfiguration;
[self.connectionManager sendConnectionRequest:setProperties withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
@@ -209,6 +220,12 @@ NS_ASSUME_NONNULL_BEGIN
} else if ([onKeyboard.event isEqualToEnum:SDLKeyboardEventAborted] || [onKeyboard.event isEqualToEnum:SDLKeyboardEventCancelled]) {
// Notify of abort / cancellation
[self.keyboardDelegate keyboardDidAbortWithReason:onKeyboard.event];
+ } else if ([onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled] || [onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskDisabled]) {
+ // Notify of key mask change
+ if ([self.keyboardDelegate respondsToSelector:@selector(keyboardDidUpdateInputMask:)]) {
+ BOOL isEnabled = [onKeyboard.event isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ [self.keyboardDelegate keyboardDidUpdateInputMask:isEnabled];
+ }
}
}
diff --git a/SmartDeviceLink/private/SDLProtocol.h b/SmartDeviceLink/private/SDLProtocol.h
index a9a21f66d..9fdc25192 100644
--- a/SmartDeviceLink/private/SDLProtocol.h
+++ b/SmartDeviceLink/private/SDLProtocol.h
@@ -13,6 +13,7 @@
@class SDLProtocolHeader;
@class SDLProtocolRecievedMessageRouter;
@class SDLRPCMessage;
+@class SDLSystemInfo;
NS_ASSUME_NONNULL_BEGIN
@@ -65,6 +66,9 @@ extern NSString *const SDLProtocolSecurityErrorDomain;
*/
@property (strong, nonatomic, readonly, nullable) NSString *authToken;
+/// The connected module's information if it's available
+@property (strong, nonatomic, readonly, nullable) SDLSystemInfo *systemInfo;
+
#pragma mark - Init
- (instancetype)init NS_UNAVAILABLE;
diff --git a/SmartDeviceLink/private/SDLProtocol.m b/SmartDeviceLink/private/SDLProtocol.m
index a76e6a24d..348543801 100644
--- a/SmartDeviceLink/private/SDLProtocol.m
+++ b/SmartDeviceLink/private/SDLProtocol.m
@@ -9,8 +9,10 @@
#import "SDLControlFramePayloadEndService.h"
#import "SDLControlFramePayloadNak.h"
#import "SDLControlFramePayloadRegisterSecondaryTransportNak.h"
+#import "SDLControlFramePayloadAudioStartServiceAck.h"
#import "SDLControlFramePayloadRPCStartService.h"
#import "SDLControlFramePayloadRPCStartServiceAck.h"
+#import "SDLControlFramePayloadVideoStartServiceAck.h"
#import "SDLEncryptionLifecycleManager.h"
#import "SDLLogMacros.h"
#import "SDLGlobals.h"
@@ -25,6 +27,7 @@
#import "SDLRPCRequest.h"
#import "SDLRPCResponse.h"
#import "SDLSecurityType.h"
+#import "SDLSystemInfo.h"
#import "SDLTimer.h"
#import "SDLVersion.h"
#import "SDLV2ProtocolHeader.h"
@@ -50,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
// Readonly public properties
@property (strong, nonatomic, readwrite, nullable) NSString *authToken;
+@property (strong, nonatomic, readwrite, nullable) SDLSystemInfo *systemInfo;
@end
@@ -513,7 +517,6 @@ NS_ASSUME_NONNULL_BEGIN
switch (startServiceACK.header.serviceType) {
case SDLServiceTypeRPC: {
SDLControlFramePayloadRPCStartServiceAck *startServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:startServiceACK.payload];
-
if (startServiceACKPayload.mtu != SDLControlFrameInt64NotFound) {
[[SDLGlobals sharedGlobals] setDynamicMTUSize:(NSUInteger)startServiceACKPayload.mtu forServiceType:startServiceACK.header.serviceType];
}
@@ -523,20 +526,20 @@ NS_ASSUME_NONNULL_BEGIN
[SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion = (startServiceACKPayload.protocolVersion != nil) ? [SDLVersion versionWithString:startServiceACKPayload.protocolVersion] : [SDLVersion versionWithMajor:startServiceACK.header.version minor:0 patch:0];
- self.authToken = [SDLGlobals.sharedGlobals.maxHeadUnitProtocolVersion isGreaterThanOrEqualToVersion:[[SDLVersion alloc] initWithMajor:5 minor:2 patch:0]] ? startServiceACKPayload.authToken : nil;
+ self.authToken = startServiceACKPayload.authToken;
- // TODO: Hash id?
+ if ((startServiceACKPayload.make != nil) || (startServiceACKPayload.systemHardwareVersion != nil) || (startServiceACKPayload.systemSoftwareVersion != nil)) {
+ self.systemInfo = [[SDLSystemInfo alloc] initWithMake:startServiceACKPayload.make model:startServiceACKPayload.model trim:startServiceACKPayload.trim modelYear:startServiceACKPayload.modelYear softwareVersion:startServiceACKPayload.systemSoftwareVersion hardwareVersion:startServiceACKPayload.systemHardwareVersion];
+ }
} break;
case SDLServiceTypeAudio: {
- SDLControlFramePayloadRPCStartServiceAck *startServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:startServiceACK.payload];
-
+ SDLControlFramePayloadAudioStartServiceAck *startServiceACKPayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithData:startServiceACK.payload];
if (startServiceACKPayload.mtu != SDLControlFrameInt64NotFound) {
[[SDLGlobals sharedGlobals] setDynamicMTUSize:(NSUInteger)startServiceACKPayload.mtu forServiceType:SDLServiceTypeAudio];
}
} break;
case SDLServiceTypeVideo: {
- SDLControlFramePayloadRPCStartServiceAck *startServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:startServiceACK.payload];
-
+ SDLControlFramePayloadVideoStartServiceAck *startServiceACKPayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithData:startServiceACK.payload];
if (startServiceACKPayload.mtu != SDLControlFrameInt64NotFound) {
[[SDLGlobals sharedGlobals] setDynamicMTUSize:(NSUInteger)startServiceACKPayload.mtu forServiceType:SDLServiceTypeVideo];
}
diff --git a/SmartDeviceLink/private/SDLRPCParameterNames.h b/SmartDeviceLink/private/SDLRPCParameterNames.h
index cd34d66e9..d792b9b1a 100644
--- a/SmartDeviceLink/private/SDLRPCParameterNames.h
+++ b/SmartDeviceLink/private/SDLRPCParameterNames.h
@@ -166,6 +166,7 @@ extern SDLRPCParameterName const SDLRPCParameterNameCurrentForecastSupported;
extern SDLRPCParameterName const SDLRPCParameterNameCurrentTemperature;
extern SDLRPCParameterName const SDLRPCParameterNameCushion;
extern SDLRPCParameterName const SDLRPCParameterNameCustomButtonId;
+extern SDLRPCParameterName const SDLRPCParameterNameCustomKeys;
extern SDLRPCParameterName const SDLRPCParameterNameCustomPresets;
extern SDLRPCParameterName const SDLRPCParameterNameOEMCustomDataType;
extern SDLRPCParameterName const SDLRPCParameterNameData;
@@ -354,6 +355,7 @@ extern SDLRPCParameterName const SDLRPCParameterNameIsSubscribed;
extern SDLRPCParameterName const SDLRPCParameterNameJunctionType;
extern SDLRPCParameterName const SDLRPCParameterNameKeepContext;
extern SDLRPCParameterName const SDLRPCParameterNameKeepContextAvailable;
+extern SDLRPCParameterName const SDLRPCParameterNameKeyboardCapabilities;
extern SDLRPCParameterName const SDLRPCParameterNameKeyboardLayout;
extern SDLRPCParameterName const SDLRPCParameterNameKeyboardProperties;
extern SDLRPCParameterName const SDLRPCParameterNameKeypressMode;
@@ -400,6 +402,8 @@ extern SDLRPCParameterName const SDLRPCParameterNameMajorVersion;
extern SDLRPCParameterName const SDLRPCParameterNameMake;
extern SDLRPCParameterName const SDLRPCParameterNameManeuverComplete;
extern SDLRPCParameterName const SDLRPCParameterNameManualTextEntry;
+extern SDLRPCParameterName const SDLRPCParameterNameMaskInputCharacters;
+extern SDLRPCParameterName const SDLRPCParameterNameMaskInputCharactersSupported;
extern SDLRPCParameterName const SDLRPCParameterNameMassageCushionFirmness;
extern SDLRPCParameterName const SDLRPCParameterNameMassageCushionFirmnessAvailable;
extern SDLRPCParameterName const SDLRPCParameterNameMassageEnabled;
@@ -485,6 +489,7 @@ extern SDLRPCParameterName const SDLRPCParameterNameNotification;
extern SDLRPCParameterName const SDLRPCParameterNameNumber;
extern SDLRPCParameterName const SDLRPCParameterNameNumberCustomPresetsAvailable;
extern SDLRPCParameterName const SDLRPCParameterNameNumberTicks;
+extern SDLRPCParameterName const SDLRPCParameterNameNumConfigurableKeys;
extern SDLRPCParameterName const SDLRPCParameterNameOdometer;
extern SDLRPCParameterName const SDLRPCParameterNameOffset;
extern SDLRPCParameterName const SDLRPCParameterNameOnLockScreenStatus;
@@ -675,6 +680,7 @@ extern SDLRPCParameterName const SDLRPCParameterNameSupportedDiagnosticModes;
extern SDLRPCParameterName const SDLRPCParameterNameSupportedDynamicImageFieldNames;
extern SDLRPCParameterName const SDLRPCParameterNameSupportsDynamicSubMenus;
extern SDLRPCParameterName const SDLRPCParameterNameSupportedFormats;
+extern SDLRPCParameterName const SDLRPCParameterNameSupportedKeyboards;
extern SDLRPCParameterName const SDLRPCParameterNameSupportedLights;
extern SDLRPCParameterName const SDLRPCParameterNameSyncFileName;
extern SDLRPCParameterName const SDLRPCParameterNameSyncMessageVersion;
diff --git a/SmartDeviceLink/private/SDLRPCParameterNames.m b/SmartDeviceLink/private/SDLRPCParameterNames.m
index d95d6af05..04c9e66b8 100644
--- a/SmartDeviceLink/private/SDLRPCParameterNames.m
+++ b/SmartDeviceLink/private/SDLRPCParameterNames.m
@@ -165,6 +165,7 @@ SDLRPCParameterName const SDLRPCParameterNameCurrentForecastSupported = @"curren
SDLRPCParameterName const SDLRPCParameterNameCurrentTemperature = @"currentTemperature";
SDLRPCParameterName const SDLRPCParameterNameCushion = @"cushion";
SDLRPCParameterName const SDLRPCParameterNameCustomButtonId = @"customButtonID";
+SDLRPCParameterName const SDLRPCParameterNameCustomKeys = @"customKeys";
SDLRPCParameterName const SDLRPCParameterNameCustomPresets = @"customPresets";
SDLRPCParameterName const SDLRPCParameterNameData = @"data";
SDLRPCParameterName const SDLRPCParameterNameDataResult = @"dataResult";
@@ -353,6 +354,7 @@ SDLRPCParameterName const SDLRPCParameterNameIsSubscribed = @"isSubscribed";
SDLRPCParameterName const SDLRPCParameterNameJunctionType = @"junctionType";
SDLRPCParameterName const SDLRPCParameterNameKeepContext = @"keepContext";
SDLRPCParameterName const SDLRPCParameterNameKeepContextAvailable = @"keepContextAvailable";
+SDLRPCParameterName const SDLRPCParameterNameKeyboardCapabilities = @"keyboardCapabilities";
SDLRPCParameterName const SDLRPCParameterNameKeyboardLayout = @"keyboardLayout";
SDLRPCParameterName const SDLRPCParameterNameKeyboardProperties = @"keyboardProperties";
SDLRPCParameterName const SDLRPCParameterNameKeypressMode = @"keypressMode";
@@ -395,6 +397,8 @@ SDLRPCParameterName const SDLRPCParameterNameMajorVersion = @"majorVersion";
SDLRPCParameterName const SDLRPCParameterNameMake = @"make";
SDLRPCParameterName const SDLRPCParameterNameManeuverComplete = @"maneuverComplete";
SDLRPCParameterName const SDLRPCParameterNameManualTextEntry = @"manualTextEntry";
+SDLRPCParameterName const SDLRPCParameterNameMaskInputCharacters = @"maskInputCharacters";
+SDLRPCParameterName const SDLRPCParameterNameMaskInputCharactersSupported = @"maskInputCharactersSupported";
SDLRPCParameterName const SDLRPCParameterNameMassageCushionFirmness = @"massageCushionFirmness";
SDLRPCParameterName const SDLRPCParameterNameMassageCushionFirmnessAvailable = @"massageCushionFirmnessAvailable";
SDLRPCParameterName const SDLRPCParameterNameMassageEnabled = @"massageEnabled";
@@ -480,6 +484,7 @@ SDLRPCParameterName const SDLRPCParameterNameNotification = @"notification";
SDLRPCParameterName const SDLRPCParameterNameNumber = @"number";
SDLRPCParameterName const SDLRPCParameterNameNumberCustomPresetsAvailable = @"numCustomPresetsAvailable";
SDLRPCParameterName const SDLRPCParameterNameNumberTicks = @"numTicks";
+SDLRPCParameterName const SDLRPCParameterNameNumConfigurableKeys = @"numConfigurableKeys";
SDLRPCParameterName const SDLRPCParameterNameOdometer = @"odometer";
SDLRPCParameterName const SDLRPCParameterNameOEMCustomDataType = @"oemCustomDataType";
SDLRPCParameterName const SDLRPCParameterNameOffset = @"offset";
@@ -671,6 +676,7 @@ SDLRPCParameterName const SDLRPCParameterNameSupportedDiagnosticModes = @"suppor
SDLRPCParameterName const SDLRPCParameterNameSupportedDynamicImageFieldNames = @"supportedDynamicImageFieldNames";
SDLRPCParameterName const SDLRPCParameterNameSupportsDynamicSubMenus = @"supportsDynamicSubMenus";
SDLRPCParameterName const SDLRPCParameterNameSupportedFormats = @"supportedFormats";
+SDLRPCParameterName const SDLRPCParameterNameSupportedKeyboards = @"supportedKeyboards";
SDLRPCParameterName const SDLRPCParameterNameSupportedLights = @"supportedLights";
SDLRPCParameterName const SDLRPCParameterNameSyncFileName = @"syncFileName";
SDLRPCParameterName const SDLRPCParameterNameSyncMessageVersion = @"syncMsgVersion";
diff --git a/SmartDeviceLink/private/SDLSoftButtonManager.m b/SmartDeviceLink/private/SDLSoftButtonManager.m
index 2a637f831..7a2725c7c 100644
--- a/SmartDeviceLink/private/SDLSoftButtonManager.m
+++ b/SmartDeviceLink/private/SDLSoftButtonManager.m
@@ -33,6 +33,9 @@
NS_ASSUME_NONNULL_BEGIN
+static const int SDLShowSoftButtonIDMin = 1;
+static const int SDLShowSoftButtonIDCount = 8;
+
@interface SDLSoftButtonObject()
@property (assign, nonatomic) NSUInteger buttonId;
@@ -76,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)start {
- [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate:)];
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate)];
}
- (void)stop {
@@ -124,12 +127,15 @@ NS_ASSUME_NONNULL_BEGIN
return;
}
- // Set the soft button ids. Check to make sure no two soft buttons have the same name, there aren't many soft buttons, so n^2 isn't going to be bad
- for (NSUInteger i = 0; i < softButtonObjects.count; i++) {
+ // Set the soft button ids. The number of soft buttons is maxed at 8 according to the RPC spec. We will only send the first 8 soft buttons if more are set into the array.
+ // Check to make sure no two soft buttons have the same name, there aren't many soft buttons, so n^2 isn't going to be bad
+ NSUInteger softButtonCount = MIN(softButtonObjects.count, SDLShowSoftButtonIDCount);
+ for (NSUInteger i = 0; i < softButtonCount; i++) {
NSString *buttonName = softButtonObjects[i].name;
// HAX: Due to a SYNC 3.0 bug (https://github.com/smartdevicelink/sdl_ios/issues/1793#issue-708356008), a `buttonId` can not be zero. As a workaround we will start the `buttonId`s from 1.
- softButtonObjects[i].buttonId = i + 1;
- for (NSUInteger j = (i + 1); j < softButtonObjects.count; j++) {
+ // Offset the soft buttons based on the minimum ID number to prevent clashes with other managers.
+ softButtonObjects[i].buttonId = i + SDLShowSoftButtonIDMin;
+ for (NSUInteger j = (i + 1); j < softButtonCount; j++) {
if ([softButtonObjects[j].name isEqualToString:buttonName]) {
_softButtonObjects = @[];
SDLLogE(@"Attempted to set soft button objects, but two buttons had the same name: %@", softButtonObjects);
@@ -213,23 +219,12 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Observers
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability {
+- (void)sdl_displayCapabilityDidUpdate {
SDLSoftButtonCapabilities *oldCapabilities = self.softButtonCapabilities;
// 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;
- }
- }
+ SDLWindowCapability *currentWindowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
+ self.softButtonCapabilities = currentWindowCapability.softButtonCapabilities.firstObject;
// Update the queue's suspend state
[self sdl_updateTransactionQueueSuspended];
diff --git a/SmartDeviceLink/private/SDLStreamingAudioLifecycleManager.m b/SmartDeviceLink/private/SDLStreamingAudioLifecycleManager.m
index 5e77bb305..4a3195613 100644
--- a/SmartDeviceLink/private/SDLStreamingAudioLifecycleManager.m
+++ b/SmartDeviceLink/private/SDLStreamingAudioLifecycleManager.m
@@ -15,6 +15,7 @@
#import "SDLControlFramePayloadConstants.h"
#import "SDLControlFramePayloadNak.h"
#import "SDLDisplayCapabilities.h"
+#import "SDLEncryptionConfiguration.h"
#import "SDLGlobals.h"
#import "SDLHMICapabilities.h"
#import "SDLLogMacros.h"
@@ -28,7 +29,7 @@
#import "SDLStateMachine.h"
#import "SDLStreamingMediaConfiguration.h"
#import "SDLSystemCapabilityManager.h"
-#import "SDLEncryptionConfiguration.h"
+#import "SDLSystemInfo.h"
#import "SDLVehicleType.h"
NS_ASSUME_NONNULL_BEGIN
@@ -44,7 +45,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (weak, nonatomic) SDLProtocol *protocol;
@property (copy, nonatomic) NSArray<NSString *> *secureMakes;
-@property (copy, nonatomic, nullable) NSString *connectedVehicleMake;
@property (assign, nonatomic, readwrite, getter=isAudioEncrypted) BOOL audioEncrypted;
@property (nonatomic, copy, nullable) void (^audioServiceEndedCompletionHandler)(void);
@@ -72,7 +72,6 @@ NS_ASSUME_NONNULL_BEGIN
_audioStreamStateMachine = [[SDLStateMachine alloc] initWithTarget:self initialState:SDLAudioStreamManagerStateStopped states:[self.class sdl_audioStreamingStateTransitionDictionary]];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_didReceiveRegisterAppInterfaceResponse:) name:SDLDidReceiveRegisterAppInterfaceResponse object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_hmiLevelDidChange:) name:SDLDidChangeHMIStatusNotification object:nil];
return self;
@@ -96,7 +95,6 @@ NS_ASSUME_NONNULL_BEGIN
SDLLogD(@"Stopping manager");
_protocol = nil;
_hmiLevel = SDLHMILevelNone;
- _connectedVehicleMake = nil;
[self.audioTranscodingManager stop];
[self.audioStreamStateMachine transitionToState:SDLAudioStreamManagerStateStopped];
@@ -162,7 +160,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)didEnterStateAudioStreamStarting {
SDLLogD(@"Audio stream starting");
- if ((self.requestedEncryptionType != SDLStreamingEncryptionFlagNone) && ([self.secureMakes containsObject:self.connectedVehicleMake])) {
+
+ NSString *connectedVehicleMake = self.connectionManager.systemInfo.vehicleType.make;
+ if ((self.requestedEncryptionType != SDLStreamingEncryptionFlagNone) && ([self.secureMakes containsObject:connectedVehicleMake])) {
[self.protocol startSecureServiceWithType:SDLServiceTypeAudio payload:nil tlsInitializationHandler:^(BOOL success, NSError * _Nonnull error) {
if (error) {
SDLLogE(@"TLS setup error: %@", error);
@@ -227,18 +227,6 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - SDL RPC Notification callbacks
-- (void)sdl_didReceiveRegisterAppInterfaceResponse:(SDLRPCResponseNotification *)notification {
- NSAssert([notification.response isKindOfClass:[SDLRegisterAppInterfaceResponse class]], @"A notification was sent with an unanticipated object");
- if (![notification.response isKindOfClass:[SDLRegisterAppInterfaceResponse class]]) {
- return;
- }
-
- SDLLogV(@"Received Register App Interface response");
- SDLRegisterAppInterfaceResponse *registerResponse = (SDLRegisterAppInterfaceResponse*)notification.response;
-
- self.connectedVehicleMake = registerResponse.vehicleType.make;
-}
-
- (void)sdl_hmiLevelDidChange:(SDLRPCNotificationNotification *)notification {
NSAssert([notification.notification isKindOfClass:[SDLOnHMIStatus class]], @"A notification was sent with an unanticipated object");
if (![notification.notification isKindOfClass:[SDLOnHMIStatus class]]) {
diff --git a/SmartDeviceLink/private/SDLStreamingVideoLifecycleManager.m b/SmartDeviceLink/private/SDLStreamingVideoLifecycleManager.m
index d2b5490ee..16236e6b7 100644
--- a/SmartDeviceLink/private/SDLStreamingVideoLifecycleManager.m
+++ b/SmartDeviceLink/private/SDLStreamingVideoLifecycleManager.m
@@ -42,6 +42,7 @@
#import "SDLStreamingVideoScaleManager.h"
#import "SDLSystemCapability.h"
#import "SDLSystemCapabilityManager.h"
+#import "SDLSystemInfo.h"
#import "SDLTouchManager.h"
#import "SDLVehicleType.h"
#import "SDLVideoEncoderDelegate.h"
@@ -71,7 +72,6 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
@property (strong, nonatomic) NSMutableDictionary *videoEncoderSettings;
@property (copy, nonatomic) NSDictionary<NSString *, id> *customEncoderSettings;
@property (copy, nonatomic) NSArray<NSString *> *secureMakes;
-@property (copy, nonatomic, nullable) NSString *connectedVehicleMake;
@property (copy, nonatomic, readonly) NSString *appName;
@property (assign, nonatomic) CV_NULLABLE CVPixelBufferRef backgroundingPixelBuffer;
@@ -199,7 +199,6 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
_protocol = nil;
[self.videoScaleManager stop];
[self.focusableItemManager stop];
- _connectedVehicleMake = nil;
[self.videoStreamStateMachine transitionToState:SDLVideoStreamManagerStateStopped];
}
@@ -597,7 +596,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
return;
}
- SDLLogD(@"Received Register App Interface");
+ SDLLogV(@"Received Register App Interface");
SDLRegisterAppInterfaceResponse *registerResponse = (SDLRegisterAppInterfaceResponse *)notification.response;
#pragma clang diagnostic push
@@ -608,15 +607,16 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
self.videoScaleManager.displayViewportResolution = CGSizeMake(resolution.resolutionWidth.floatValue,
resolution.resolutionHeight.floatValue);
// HAX: Workaround for Legacy Ford and Lincoln displays with > 800 resolution width or height. They don't support scaling and if we don't do this workaround, they will not correctly scale the view.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
NSString *make = registerResponse.vehicleType.make;
+#pragma clang diagnostic pop
CGSize resolution = self.videoScaleManager.displayViewportResolution;
if (([make containsString:@"Ford"] || [make containsString:@"Lincoln"]) && (resolution.width > 800 || resolution.height > 800)) {
self.videoScaleManager.scale = 1.0f / 0.75f; // Scale by 1.333333
}
}
- self.connectedVehicleMake = registerResponse.vehicleType.make;
-
SDLLogD(@"Determined base screen size on display capabilities: %@", NSStringFromCGSize(self.videoScaleManager.displayViewportResolution));
}
@@ -798,7 +798,8 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N
SDLControlFramePayloadVideoStartService *startVideoPayload = [[SDLControlFramePayloadVideoStartService alloc] initWithVideoHeight:preferredResolution.resolutionHeight.intValue width:preferredResolution.resolutionWidth.intValue protocol:preferredFormat.protocol codec:preferredFormat.codec];
// Decide if we need to start a secure service or not
- if ((self.requestedEncryptionType != SDLStreamingEncryptionFlagNone) && ([self.secureMakes containsObject:self.connectedVehicleMake])) {
+ NSString *connectedVehicleMake = self.connectionManager.systemInfo.vehicleType.make;
+ if ((self.requestedEncryptionType != SDLStreamingEncryptionFlagNone) && ([self.secureMakes containsObject:connectedVehicleMake])) {
SDLLogD(@"Sending secure video start service with payload: %@", startVideoPayload);
[self.protocol startSecureServiceWithType:SDLServiceTypeVideo payload:startVideoPayload.data tlsInitializationHandler:^(BOOL success, NSError *error) {
if (error) {
diff --git a/SmartDeviceLink/private/SDLTextAndGraphicManager.m b/SmartDeviceLink/private/SDLTextAndGraphicManager.m
index 6f416b2f1..37b9f95fa 100644
--- a/SmartDeviceLink/private/SDLTextAndGraphicManager.m
+++ b/SmartDeviceLink/private/SDLTextAndGraphicManager.m
@@ -90,7 +90,7 @@ NS_ASSUME_NONNULL_BEGIN
// Make sure none of the properties were set after the manager was shut down
[self sdl_reset];
- [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate:)];
+ [self.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:self selector:@selector(sdl_displayCapabilityDidUpdate)];
}
- (void)stop {
@@ -375,23 +375,12 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Subscribed notifications
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability {
- // Extract and update the capabilities
- NSArray<SDLDisplayCapability *> *capabilities = systemCapability.displayCapabilities;
- if (capabilities == nil || capabilities.count == 0) {
- self.windowCapability = 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; }
-
- // Check if the window capability is equal to the one we already have. If it is, abort.
- if ([windowCapability isEqual:self.windowCapability]) { return; }
- self.windowCapability = windowCapability;
- break;
- }
- }
+- (void)sdl_displayCapabilityDidUpdate {
+ SDLWindowCapability *currentWindowCapability = self.systemCapabilityManager.defaultMainWindowCapability;
+
+ // Check if the window capability is equal to the one we already have. If it is, abort.
+ if ([currentWindowCapability isEqual:self.windowCapability]) { return; }
+ self.windowCapability = currentWindowCapability;
[self sdl_updateTransactionQueueSuspended];
diff --git a/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.h b/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.h
index 9321c98cd..71e541666 100644
--- a/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.h
+++ b/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.h
@@ -1,5 +1,5 @@
//
-// SDLWindowCapability+ShowManagerExtensions.h
+// SDLWindowCapability+ScreenManagerExtensions.h
// SmartDeviceLink
//
// Created by Joel Fischer on 2/28/18.
@@ -12,15 +12,28 @@
#import "SDLTextFieldName.h"
#import "SDLWindowCapability.h"
+@class SDLKeyboardProperties;
+
NS_ASSUME_NONNULL_BEGIN
+static const int MaxMainFieldLineCount = 4;
+static const int MaxAlertTextFieldLineCount = 3;
+
@interface SDLWindowCapability (ScreenManagerExtensions)
@property (assign, nonatomic, readonly) NSUInteger maxNumberOfMainFieldLines;
+@property (assign, nonatomic, readonly) NSUInteger maxNumberOfAlertFieldLines;
- (BOOL)hasTextFieldOfName:(SDLTextFieldName)name;
- (BOOL)hasImageFieldOfName:(SDLImageFieldName)name;
+/// Takes a keyboard configuration (SDLKeyboardProperties) and creates a valid version of it, if possible, based on this object's internal keyboardCapabilities (SDLKeyboardCapabilities).
+/// If there is no internal keyboardCapabilities, it will just return the passed configuration as-is.
+/// If no valid configuration can be determined based on the internal keyboard capabilities, it will return nil.
+/// @param keyboardConfiguration The configuration to use to determine a valid configuration
+/// @return The passed keyboardConfiguration if there are no changes needed or possible, a modified keyboardConfiguration if a valid version of the configuration could be determined, or nil if a valid configuration could not be created
+- (nullable SDLKeyboardProperties *)createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:(nullable SDLKeyboardProperties *)keyboardConfiguration;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.m b/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.m
index 441356a83..e83063545 100644
--- a/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.m
+++ b/SmartDeviceLink/private/SDLWindowCapability+ScreenManagerExtensions.m
@@ -1,5 +1,5 @@
//
-// SDLWindowCapability+ShowManagerExtensions.m
+// SDLWindowCapability+ScreenManagerExtensions.m
// SmartDeviceLink
//
// Created by Joel Fischer on 2/28/18.
@@ -10,6 +10,10 @@
#import "SDLWindowCapability+ScreenManagerExtensions.h"
#import "SDLImageField.h"
+#import "SDLKeyboardCapabilities.h"
+#import "SDLKeyboardLayoutCapability.h"
+#import "SDLKeyboardProperties.h"
+#import "SDLLogMacros.h"
#import "SDLTextField.h"
@implementation SDLWindowCapability (ScreenManagerExtensions)
@@ -35,7 +39,24 @@
NSInteger fieldNumber = [[textField.name substringFromIndex:(textField.name.length - 1)] integerValue];
highestFound = (highestFound < fieldNumber) ? fieldNumber : highestFound;
- if (highestFound == 4) { break; }
+ if (highestFound == MaxMainFieldLineCount) { break; }
+ }
+ }
+
+ return (NSUInteger)highestFound;
+}
+
+- (NSUInteger)maxNumberOfAlertFieldLines {
+ NSInteger highestFound = 0;
+ for (SDLTextField *textField in self.textFields) {
+ if (![textField.name isKindOfClass:[NSString class]]) { continue; }
+ if ([textField.name isEqualToString:SDLTextFieldNameAlertText1]
+ || [textField.name isEqualToString:SDLTextFieldNameAlertText2]
+ || [textField.name isEqualToString:SDLTextFieldNameAlertText3]) {
+ NSInteger fieldNumber = [[textField.name substringFromIndex:(textField.name.length - 1)] integerValue];
+ highestFound = (highestFound < fieldNumber) ? fieldNumber : highestFound;
+
+ if (highestFound == MaxAlertTextFieldLineCount) { break; }
}
}
@@ -52,4 +73,44 @@
return NO;
}
+- (nullable SDLKeyboardProperties *)createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:(nullable SDLKeyboardProperties *)keyboardConfiguration {
+ // If there are no keyboard capabilities, if there is no passed keyboard configuration, or if there is no layout to the passed keyboard configuration, just pass back the passed in configuration
+ if ((self.keyboardCapabilities == nil) || (keyboardConfiguration == nil) || (keyboardConfiguration.keyboardLayout == nil)) {
+ return keyboardConfiguration;
+ }
+
+ // Find the capability for the keyboard configuration's layout
+ SDLKeyboardLayoutCapability *selectedLayoutCapability = nil;
+ for (SDLKeyboardLayoutCapability *layoutCapability in self.keyboardCapabilities.supportedKeyboards) {
+ if ([layoutCapability.keyboardLayout isEqualToEnum:keyboardConfiguration.keyboardLayout]) {
+ selectedLayoutCapability = layoutCapability;
+ break;
+ }
+ }
+ if (selectedLayoutCapability == nil) {
+ SDLLogE(@"Configured keyboard layout is not supported: %@", keyboardConfiguration.keyboardLayout);
+ return nil;
+ }
+
+ // Modify the keyboard configuration if there are fewer customKeys allowed than were set, or if an empty array was set.
+ SDLKeyboardProperties *modifiedKeyboardConfiguration = [keyboardConfiguration copy];
+ if (keyboardConfiguration.customKeys.count == 0) {
+ modifiedKeyboardConfiguration.customKeys = nil;
+ } else {
+ NSUInteger numConfigurableKeys = selectedLayoutCapability.numConfigurableKeys.unsignedIntegerValue;
+ if (modifiedKeyboardConfiguration.customKeys.count > numConfigurableKeys) {
+ SDLLogW(@"%lu custom keys set, but the selected layout: %@ only supports %lu. Dropping the rest.", (unsigned long)modifiedKeyboardConfiguration.customKeys.count, modifiedKeyboardConfiguration.keyboardLayout, (unsigned long)numConfigurableKeys);
+ // If there are more custom keys than are allowed for the selected keyboard layout, we need to trim the number of keys to only use the first n number of custom keys, where n is the number of allowed custom keys for that layout.
+ modifiedKeyboardConfiguration.customKeys = [modifiedKeyboardConfiguration.customKeys subarrayWithRange:NSMakeRange(0, numConfigurableKeys)];
+ }
+ }
+
+ // If the keyboard does not support masking input characters, we will remove it from the keyboard configuration
+ if (!self.keyboardCapabilities.maskInputCharactersSupported.boolValue) {
+ modifiedKeyboardConfiguration.maskInputCharacters = nil;
+ }
+
+ return modifiedKeyboardConfiguration;
+}
+
@end
diff --git a/SmartDeviceLink/public/SDLAlertAudioData.h b/SmartDeviceLink/public/SDLAlertAudioData.h
new file mode 100644
index 000000000..93b5462aa
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAlertAudioData.h
@@ -0,0 +1,22 @@
+//
+// SDLAlertAudioData.h
+// SmartDeviceLink
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAudioData.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLAlertAudioData : SDLAudioData
+
+/// Whether the alert tone should be played before the prompt (if any) is spoken. Defaults to NO.
+@property (assign, nonatomic) BOOL playTone;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLAlertAudioData.m b/SmartDeviceLink/public/SDLAlertAudioData.m
new file mode 100644
index 000000000..3e6f2a8bd
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAlertAudioData.m
@@ -0,0 +1,25 @@
+//
+// SDLAlertAudioData.m
+// SmartDeviceLink
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAlertAudioData.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLAlertAudioData
+
+#pragma mark - NSCopying
+
+- (id)copyWithZone:(nullable NSZone *)zone {
+ SDLAlertAudioData *new = [super copyWithZone:zone];
+ new->_playTone = _playTone;
+ return new;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLAlertView.h b/SmartDeviceLink/public/SDLAlertView.h
new file mode 100644
index 000000000..c2524b17a
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAlertView.h
@@ -0,0 +1,76 @@
+//
+// SDLAlertView.h
+// SmartDeviceLink
+//
+// Created by Nicole on 11/10/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import "NSNumber+NumberType.h"
+
+@class SDLAlertAudioData;
+@class SDLArtwork;
+@class SDLSoftButtonObject;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Notifies the subscriber that the alert should be cancelled.
+typedef void (^SDLAlertCanceledHandler)(void);
+
+@interface SDLAlertView : NSObject <NSCopying>
+
+/// Set this to change the default timeout for all alerts. If a timeout is not set on an individual alert object (or if it is set to 0.0), then it will use this timeout instead. See `timeout` for more details. If this is not set by you, it will default to 5 seconds. The minimum is 3 seconds, the maximum is 10 seconds. If this is set below the minimum, it will be capped at 3 seconds. If this is set above the maximum, it will be capped at 10 seconds.
+/// Please note that if a button is added to the alert, the defaultTimeout and timeout values will be ignored.
+@property (class, assign, nonatomic) NSTimeInterval defaultTimeout;
+
+/// The primary line of text for display on the alert. If fewer than three alert lines are available on the head unit, the screen manager will automatically concatenate some of the lines together.
+@property (nullable, strong, nonatomic) NSString *text;
+
+/// The secondary line of text for display on the alert. If fewer than three alert lines are available on the head unit, the screen manager will automatically concatenate some of the lines together.
+@property (nullable, strong, nonatomic) NSString *secondaryText;
+
+/// The tertiary line of text for display on the alert. If fewer than three alert lines are available on the head unit, the screen manager will automatically concatenate some of the lines together.
+@property (nullable, strong, nonatomic) NSString *tertiaryText;
+
+/// Timeout in seconds. Defaults to 0, which will use `defaultTimeout`. If this is set below the minimum, it will be capped at 3 seconds. Minimum 3 seconds, maximum 10 seconds. If this is set above the maximum, it will be capped at 10 seconds. Defaults to 0.
+/// Please note that if a button is added to the alert, the defaultTimeout and timeout values will be ignored.
+@property (assign, nonatomic) NSTimeInterval timeout;
+
+/// Text spoken, file(s) played, and/or tone played when the alert appears
+@property (nullable, copy, nonatomic) SDLAlertAudioData *audio;
+
+/// If supported, the alert GUI will display some sort of indefinite waiting / refresh / loading indicator animation. Defaults to NO.
+@property (assign, nonatomic) BOOL showWaitIndicator;
+
+/// Soft buttons the user may select to perform actions. Only one `SDLSoftButtonState` per object is supported; if any soft button object contains multiple states, an exception will be thrown.
+@property (nullable, copy, nonatomic) NSArray<SDLSoftButtonObject *> *softButtons;
+
+/// An artwork that will be displayed when the icon appears. This will be uploaded prior to the appearance of the alert if necessary. This will not be uploaded if the head unit does not declare support for alertIcon.
+@property (nullable, copy, nonatomic) SDLArtwork *icon;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+/// Initialize a basic alert with a message and buttons
+/// @param text The primary line of text for display on the alert
+/// @param softButtons Soft buttons the user may select to perform actions
+- (instancetype)initWithText:(NSString *)text buttons:(NSArray<SDLSoftButtonObject *> *)softButtons;
+
+/// Initialize a alert with a text, image, buttons and sound
+/// @param text The primary line of text for display on the alert
+/// @param secondaryText The secondary line of text for display on the alert
+/// @param tertiaryText The tertiary line of text for display on the alert
+/// @param timeout Timeout in seconds
+/// @param showWaitIndicator If supported, the alert GUI will display some sort of indefinite waiting / refresh / loading indicator animation
+/// @param audio Text spoken and/or tone played when the alert appears
+/// @param softButtons Soft buttons the user may select to perform actions
+/// @param icon An artwork that will be displayed when the icon appears
+- (instancetype)initWithText:(nullable NSString *)text secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText timeout:(nullable NSNumber<SDLFloat> *)timeout showWaitIndicator:(nullable NSNumber<SDLBool> *)showWaitIndicator audioIndication:(nullable SDLAlertAudioData *)audio buttons:(nullable NSArray<SDLSoftButtonObject *> *)softButtons icon:(nullable SDLArtwork *)icon;
+
+/// Cancels the alert. If the alert has not yet been sent to the module, it will not be sent. If the alert is already presented on the module, the alert will be immediately dismissed. Canceling an already presented alert will only work if connected to modules supporting RPC Spec v.6.0+. On older versions the alert will not be dismissed.
+- (void)cancel;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLAlertView.m b/SmartDeviceLink/public/SDLAlertView.m
new file mode 100644
index 000000000..f8f824f1b
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAlertView.m
@@ -0,0 +1,146 @@
+//
+// SDLAlertView.m
+// SmartDeviceLink
+//
+// Created by Nicole on 11/10/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAlertView.h"
+
+#import "SDLAlertAudioData.h"
+#import "SDLArtwork.h"
+#import "SDLError.h"
+#import "SDLSoftButtonObject.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLAlertView()
+
+@property (copy, nonatomic, nullable) SDLAlertCanceledHandler canceledHandler;
+
+@end
+
+@implementation SDLAlertView
+
+static const float TimeoutDefault = 0.0;
+static const float TimeoutMinCap = 3.0;
+static const float TimeoutMaxCap = 10.0;
+static NSTimeInterval _defaultTimeout = 5.0;
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _timeout = TimeoutDefault;
+
+ return self;
+}
+
+- (instancetype)initWithText:(NSString *)text buttons:(NSArray<SDLSoftButtonObject *> *)softButtons {
+ self = [self init];
+ if (!self) { return nil; }
+
+ _text = text;
+ self.softButtons = softButtons;
+
+ return self;
+}
+
+- (instancetype)initWithText:(nullable NSString *)text secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText timeout:(nullable NSNumber<SDLFloat> *)timeout showWaitIndicator:(nullable NSNumber<SDLBool> *)showWaitIndicator audioIndication:(nullable SDLAlertAudioData *)audio buttons:(nullable NSArray<SDLSoftButtonObject *> *)softButtons icon:(nullable SDLArtwork *)icon {
+ self = [self initWithText:text buttons:softButtons];
+ if (!self) { return nil; }
+
+ _secondaryText = secondaryText;
+ _tertiaryText = tertiaryText;
+ self.timeout = timeout.doubleValue;
+ _showWaitIndicator = showWaitIndicator.boolValue;
+ self.audio = audio;
+ self.icon = icon;
+
+ return self;
+}
+
+#pragma mark - Cancel
+
+- (void)cancel {
+ if (self.canceledHandler == nil) { return; }
+ self.canceledHandler();
+}
+
+#pragma mark - Getters / Setters
+
+- (void)setSoftButtons:(nullable NSArray<SDLSoftButtonObject *> *)softButtons {
+ for (SDLSoftButtonObject *softButton in softButtons) {
+ if (softButton.states.count == 1) { continue; }
+ @throw [NSException sdl_invalidAlertSoftButtonStatesException];
+ }
+
+ _softButtons = softButtons;
+}
+
++ (void)setDefaultTimeout:(NSTimeInterval)defaultTimeout {
+ _defaultTimeout = defaultTimeout;
+}
+
++ (NSTimeInterval)defaultTimeout {
+ if (_defaultTimeout < TimeoutMinCap) {
+ return TimeoutMinCap;
+ } else if (_defaultTimeout > TimeoutMaxCap) {
+ return TimeoutMaxCap;
+ }
+
+ return _defaultTimeout;
+}
+
+- (NSTimeInterval)timeout {
+ if (_timeout == TimeoutDefault) {
+ return SDLAlertView.defaultTimeout;
+ } else if (_timeout < TimeoutMinCap) {
+ return TimeoutMinCap;
+ } else if (_timeout > TimeoutMaxCap) {
+ return TimeoutMaxCap;
+ }
+
+ return _timeout;
+}
+
+#pragma mark - NSCopying
+
+- (id)copyWithZone:(nullable NSZone *)zone {
+ SDLAlertView *newAlertView = [[SDLAlertView allocWithZone:zone] initWithText:[_text copyWithZone:zone] secondaryText:[_secondaryText copyWithZone:zone] tertiaryText:[_tertiaryText copyWithZone:zone] timeout:@(_timeout) showWaitIndicator:@(_showWaitIndicator) audioIndication:[_audio copyWithZone:zone] buttons:[_softButtons copyWithZone:zone] icon:[_icon copyWithZone:zone]];
+ newAlertView->_canceledHandler = [_canceledHandler copyWithZone:zone];
+ return newAlertView;
+}
+
+#pragma mark - Debug Description
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"SDLAlertView: \"%@\", text: \"%@\"", [self sdl_alertType], _text];
+}
+
+- (NSString *)debugDescription {
+ return [NSString stringWithFormat:@"SDLAlertView: \"%@\", text: \"%@\", secondaryText: \"%@\", tertiaryText: \"%@\", timeout: %.1f, showWaitIndicator: %d, audio: \"%@\", softButtons: \"%@\", icon: \"%@\"", [self sdl_alertType], _text, _secondaryText, _tertiaryText, _timeout, _showWaitIndicator, _audio, _softButtons, _icon];
+}
+
+- (NSString *)sdl_alertType {
+ BOOL alertHasText = (_text || _secondaryText || _tertiaryText);
+ BOOL alertHasAudio = _audio.audioData.count > 0;
+
+ NSString *alertType;
+ if (alertHasText && alertHasAudio) {
+ alertType = @"Text-and-audio";
+ } else if (alertHasText) {
+ alertType = @"Text-only";
+ } else if (alertHasAudio) {
+ alertType = @"Audio-only";
+ } else {
+ alertType = @"Invalid";
+ }
+
+ return alertType;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLAudioData.h b/SmartDeviceLink/public/SDLAudioData.h
new file mode 100644
index 000000000..a4c0a3667
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAudioData.h
@@ -0,0 +1,55 @@
+//
+// SDLAudioData.h
+// SmartDeviceLink
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import "SDLSpeechCapabilities.h"
+
+@class SDLFile;
+@class SDLTTSChunk;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLAudioData : NSObject <NSCopying>
+
+/// The text-to-speech prompts that will used and/or audio files that will be played. The audio prompts and files will be played in the same order they are added.
+@property (nullable, copy, nonatomic, readonly) NSArray<SDLTTSChunk *> *audioData;
+
+/// Initialize with an SDLFile holding data or pointing to a file on the file system. When this object is passed to an `Alert` or `Speak`, the file will be uploaded if it is not already, then played if the system supports that feature.
+/// @discussion Only available on systems supporting RPC Spec v5.0+
+///
+/// @param audioFile The audio file to be played by the system
+- (instancetype)initWithAudioFile:(SDLFile *)audioFile;
+
+/// Initialize with a string to be spoken by the system speech synthesizer.
+/// @param spokenString The string to be spoken by the system speech synthesizer
+- (instancetype)initWithSpeechSynthesizerString:(NSString *)spokenString;
+
+/// Initialize with a string to be spoken by the system speech synthesizer using a phonetic string.
+/// @param phoneticString The string to be spoken by the system speech synthesizer
+/// @param phoneticType Must be one of `SAPI_PHONEMES`, `LHPLUS_PHONEMES`, `TEXT`, or `PRE_RECORDED` or no object will be created
+- (instancetype)initWithPhoneticSpeechSynthesizerString:(NSString *)phoneticString phoneticType:(SDLSpeechCapabilities)phoneticType;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Add additional SDLFiles holding data or pointing to a file on the file system. When this object is passed to an `Alert` or `Speak`, the file will be uploaded if it is not already, then played if the system supports that feature.
+/// @param audioFiles An array of audio file to be played by the system
+- (void)addAudioFiles:(NSArray<SDLFile *> *)audioFiles;
+
+/// Create additional strings to be spoken by the system speech synthesizer.
+/// @param spokenStrings The strings to be spoken by the system speech synthesizer
+- (void)addSpeechSynthesizerStrings:(NSArray<NSString *> *)spokenStrings;
+
+/// Create additional strings to be spoken by the system speech synthesizer using a phonetic string.
+/// @param phoneticStrings The strings to be spoken by the system speech synthesizer
+/// @param phoneticType Must be one of `SAPI_PHONEMES`, `LHPLUS_PHONEMES`, `TEXT`, or `PRE_RECORDED` or no object will be created
+- (void)addPhoneticSpeechSynthesizerStrings:(NSArray<NSString *> *)phoneticStrings phoneticType:(SDLSpeechCapabilities)phoneticType;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLAudioData.m b/SmartDeviceLink/public/SDLAudioData.m
new file mode 100644
index 000000000..e0ddb3501
--- /dev/null
+++ b/SmartDeviceLink/public/SDLAudioData.m
@@ -0,0 +1,135 @@
+//
+// SDLAudioData.m
+// SmartDeviceLink
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import "SDLAudioData.h"
+
+#import "SDLError.h"
+#import "SDLFile.h"
+#import "SDLSpeak.h"
+#import "SDLTTSChunk.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLAudioData()
+
+/// The audio file data that will be uploaded.
+@property (nullable, copy, nonatomic, readonly) NSMutableDictionary<NSString *, SDLFile *> *audioFileData;
+@property (nullable, copy, nonatomic, readonly) NSMutableArray<SDLTTSChunk *> *mutableAudioData;
+
+@end
+
+@implementation SDLAudioData
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _mutableAudioData = [NSMutableArray array];
+ _audioFileData = [NSMutableDictionary dictionary];
+
+ return self;
+}
+
+- (instancetype)initWithAudioFile:(SDLFile *)audioFile {
+ self = [self init];
+ if (!self) { return nil; }
+
+ [_mutableAudioData addObjectsFromArray:[SDLTTSChunk fileChunksWithName:audioFile.name]];
+ _audioFileData[audioFile.name] = audioFile;
+
+ return self;
+}
+
+- (instancetype)initWithSpeechSynthesizerString:(NSString *)spokenString {
+ self = [self init];
+ if (!self) { return nil; }
+
+ [_mutableAudioData addObjectsFromArray:[SDLTTSChunk textChunksFromString:spokenString]];
+
+ return self;
+}
+
+- (instancetype)initWithPhoneticSpeechSynthesizerString:(NSString *)phoneticString phoneticType:(SDLSpeechCapabilities)phoneticType {
+ self = [self init];
+ if (!self) { return nil; }
+
+ if (![self.class sdl_isValidPhoneticType:phoneticType]) {
+ @throw [NSException sdl_invalidTTSSpeechCapabilitiesException];
+ }
+
+ [_mutableAudioData addObjectsFromArray:@[[[SDLTTSChunk alloc] initWithText:phoneticString type:phoneticType]]];
+
+ return self;
+}
+
+#pragma mark - Adding additional audio data
+- (void)addAudioFiles:(NSArray<SDLFile *> *)audioFiles {
+ if (audioFiles.count == 0) { return; }
+
+ for (SDLFile *audioFile in audioFiles) {
+ self.audioFileData[audioFile.name] = audioFile;
+ [self.mutableAudioData addObjectsFromArray:[SDLTTSChunk fileChunksWithName:audioFile.name]];
+ }
+}
+
+- (void)addSpeechSynthesizerStrings:(NSArray<NSString *> *)spokenStrings {
+ if (spokenStrings.count == 0) { return; }
+
+ for (NSString *spokenString in spokenStrings) {
+ if (spokenString.length == 0) { continue; }
+ [self.mutableAudioData addObjectsFromArray:[SDLTTSChunk textChunksFromString:spokenString]];
+ }
+}
+
+- (void)addPhoneticSpeechSynthesizerStrings:(NSArray<NSString *> *)phoneticStrings phoneticType:(SDLSpeechCapabilities)phoneticType {
+ if (![self.class sdl_isValidPhoneticType:phoneticType]) {
+ @throw [NSException sdl_invalidTTSSpeechCapabilitiesException];
+ } else if (phoneticStrings.count == 0) {
+ return;
+ }
+
+ for (NSString *phoneticString in phoneticStrings) {
+ if (phoneticString.length == 0) { continue; }
+ [self.mutableAudioData addObject:[[SDLTTSChunk alloc] initWithText:phoneticString type:phoneticType]];
+ }
+}
+
+#pragma mark - Private Utilities
+
+/// Checks if the phonetic type can be used to create a text-to-speech string.
+/// @param phoneticType The phonetic type of the text-to-speech string
+/// @return True if the phoneticType is of type `SAPI_PHONEMES`, `LHPLUS_PHONEMES`, `TEXT`, or `PRE_RECORDED`; false if not.
++ (BOOL)sdl_isValidPhoneticType:(SDLSpeechCapabilities)phoneticType {
+ if (!([phoneticType isEqualToEnum:SDLSpeechCapabilitiesSAPIPhonemes]
+ || [phoneticType isEqualToEnum:SDLSpeechCapabilitiesLHPlusPhonemes]
+ || [phoneticType isEqualToEnum:SDLSpeechCapabilitiesText]
+ || [phoneticType isEqualToEnum:SDLSpeechCapabilitiesPrerecorded])) {
+ return NO;
+ }
+
+ return YES;
+}
+
+#pragma mark - Getters
+
+- (nullable NSArray<SDLTTSChunk *> *)audioData {
+ return [_mutableAudioData copy];
+}
+
+#pragma mark - NSCopying
+
+- (id)copyWithZone:(nullable NSZone *)zone {
+ SDLAudioData *newAudioData = [[self class] allocWithZone:zone];
+ newAudioData->_mutableAudioData = [_mutableAudioData copyWithZone:zone];
+ newAudioData->_audioFileData = [_audioFileData copyWithZone:zone];
+ return newAudioData;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLErrorConstants.h b/SmartDeviceLink/public/SDLErrorConstants.h
index 12bb1c235..14f92a3ba 100644
--- a/SmartDeviceLink/public/SDLErrorConstants.h
+++ b/SmartDeviceLink/public/SDLErrorConstants.h
@@ -22,6 +22,9 @@ extern SDLErrorDomain *const SDLErrorDomainCacheFileManager;
/// An error in the SDLChoiceSetManager subset of SDLScreenManager
extern SDLErrorDomain *const SDLErrorDomainChoiceSetManager;
+/// An error in the SDLAlertManager subset of SDLScreenManager
+extern SDLErrorDomain *const SDLErrorDomainAlertManager;
+
/// An error in the SDLEncryptionLifecycleManager private class
extern SDLErrorDomain *const SDLErrorDomainEncryptionLifecycleManager;
@@ -182,7 +185,7 @@ typedef NS_ENUM(NSInteger, SDLSubscribeButtonManagerError) {
};
/**
- Errors associated with the ScreenManager class
+ Errors associated with the Menu Manager class
*/
typedef NS_ENUM(NSInteger, SDLMenuManagerError) {
/// Sending menu-related RPCs returned an error from the remote system
@@ -190,7 +193,7 @@ typedef NS_ENUM(NSInteger, SDLMenuManagerError) {
SDLMenuManagerErrorPendingUpdateSuperseded = -2
};
-/// Errors associated with Choice Set class
+/// Errors associated with Choice Set Manager class
typedef NS_ENUM(NSInteger, SDLChoiceSetManagerError) {
/// The choice set has been deleted before it was presented
SDLChoiceSetManagerErrorPendingPresentationDeleted = -1,
@@ -208,6 +211,15 @@ typedef NS_ENUM(NSInteger, SDLChoiceSetManagerError) {
SDLChoiceSetManagerErrorInvalidState = -5
};
+/// Errors associated with Alert Manager class
+typedef NS_ENUM(NSInteger, SDLAlertManagerError) {
+ /// There was an error presenting the alert
+ SDLAlertManagerPresentationError = -1,
+
+ /// The alert data is invalid
+ SDLAlertManagerInvalidDataError = -2,
+};
+
/// Errors associated with the system capability manager
typedef NS_ENUM(NSInteger, SDLSystemCapabilityManagerError) {
/// The connected head unit does not support any system capabilities
diff --git a/SmartDeviceLink/public/SDLErrorConstants.m b/SmartDeviceLink/public/SDLErrorConstants.m
index 75ae0a7a3..ccfc62472 100644
--- a/SmartDeviceLink/public/SDLErrorConstants.m
+++ b/SmartDeviceLink/public/SDLErrorConstants.m
@@ -13,6 +13,7 @@
SDLErrorDomain *const SDLErrorDomainAudioStreamManager = @"com.sdl.extension.pcmAudioStreamManager";
SDLErrorDomain *const SDLErrorDomainCacheFileManager = @"com.sdl.cachefilemanager.error";
SDLErrorDomain *const SDLErrorDomainChoiceSetManager = @"com.sdl.choicesetmanager.error";
+SDLErrorDomain *const SDLErrorDomainAlertManager = @"com.sdl.alertmanager.error";
SDLErrorDomain *const SDLErrorDomainEncryptionLifecycleManager = @"com.sdl.encryptionlifecyclemanager.error";
SDLErrorDomain *const SDLErrorDomainFileManager = @"com.sdl.filemanager.error";
SDLErrorDomain *const SDLErrorDomainLifecycleManager = @"com.sdl.lifecyclemanager.error";
diff --git a/SmartDeviceLink/public/SDLFileManager.h b/SmartDeviceLink/public/SDLFileManager.h
index 5010b89e4..d5a053e3b 100644
--- a/SmartDeviceLink/public/SDLFileManager.h
+++ b/SmartDeviceLink/public/SDLFileManager.h
@@ -146,7 +146,7 @@ typedef void (^SDLFileManagerStartupCompletionHandler)(BOOL success, NSError *__
* @param file the SDLFile that needs to be checked
* @return BOOL that tells whether file needs to be uploaded to Core or not
*/
-- (BOOL)fileNeedsUpload:(SDLFile *)file;
+- (BOOL)fileNeedsUpload:(nullable SDLFile *)file;
/**
* Uploads an artwork file to the remote file system and returns the name of the uploaded artwork once completed. If an artwork with the same name is already on the remote system, the artwork is not uploaded and the artwork name is simply returned.
diff --git a/SmartDeviceLink/public/SDLFileManager.m b/SmartDeviceLink/public/SDLFileManager.m
index 58ed6a547..2bd0bde31 100644
--- a/SmartDeviceLink/public/SDLFileManager.m
+++ b/SmartDeviceLink/public/SDLFileManager.m
@@ -427,7 +427,7 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError";
#pragma mark Artworks
-- (BOOL)fileNeedsUpload:(SDLFile *)file {
+- (BOOL)fileNeedsUpload:(nullable SDLFile *)file {
if (file == nil || file.isStaticIcon) { return NO; }
return (file.overwrite || ![self hasUploadedFile:file]);
diff --git a/SmartDeviceLink/public/SDLKeyboardCapabilities.h b/SmartDeviceLink/public/SDLKeyboardCapabilities.h
new file mode 100644
index 000000000..9ed4e831e
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardCapabilities.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SDLRPCStruct.h"
+
+@class SDLKeyboardLayoutCapability;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * @added in SmartDeviceLink 7.1.0
+ */
+@interface SDLKeyboardCapabilities : SDLRPCStruct
+
+/**
+ * @param maskInputCharactersSupported - maskInputCharactersSupported
+ * @param supportedKeyboards - supportedKeyboards
+ * @return A SDLKeyboardCapabilities object
+ */
+- (instancetype)initWithMaskInputCharactersSupported:(nullable NSNumber<SDLBool> *)maskInputCharactersSupported supportedKeyboards:(nullable NSArray<SDLKeyboardLayoutCapability *> *)supportedKeyboards;
+
+/**
+ * Availability of capability to mask input characters using keyboard. True: Available, False: Not Available
+ */
+@property (nullable, strong, nonatomic) NSNumber<SDLBool> *maskInputCharactersSupported;
+
+/**
+ * Capabilities of supported keyboard layouts by HMI.
+ * {"array_min_size": 1, "array_max_size": 1000}
+ */
+@property (nullable, strong, nonatomic) NSArray<SDLKeyboardLayoutCapability *> *supportedKeyboards;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardCapabilities.m b/SmartDeviceLink/public/SDLKeyboardCapabilities.m
new file mode 100644
index 000000000..27799f17a
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardCapabilities.m
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "NSMutableDictionary+Store.h"
+#import "SDLKeyboardCapabilities.h"
+#import "SDLKeyboardLayoutCapability.h"
+#import "SDLRPCParameterNames.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLKeyboardCapabilities
+
+- (instancetype)initWithMaskInputCharactersSupported:(nullable NSNumber<SDLBool> *)maskInputCharactersSupported supportedKeyboards:(nullable NSArray<SDLKeyboardLayoutCapability *> *)supportedKeyboards {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+ self.maskInputCharactersSupported = maskInputCharactersSupported;
+ self.supportedKeyboards = supportedKeyboards;
+ return self;
+}
+
+- (void)setMaskInputCharactersSupported:(nullable NSNumber<SDLBool> *)maskInputCharactersSupported {
+ [self.store sdl_setObject:maskInputCharactersSupported forName:SDLRPCParameterNameMaskInputCharactersSupported];
+}
+
+- (nullable NSNumber<SDLBool> *)maskInputCharactersSupported {
+ return [self.store sdl_objectForName:SDLRPCParameterNameMaskInputCharactersSupported ofClass:NSNumber.class error:nil];
+}
+
+- (void)setSupportedKeyboards:(nullable NSArray<SDLKeyboardLayoutCapability *> *)supportedKeyboards {
+ [self.store sdl_setObject:supportedKeyboards forName:SDLRPCParameterNameSupportedKeyboards];
+}
+
+- (nullable NSArray<SDLKeyboardLayoutCapability *> *)supportedKeyboards {
+ return [self.store sdl_objectsForName:SDLRPCParameterNameSupportedKeyboards ofClass:SDLKeyboardLayoutCapability.class error:nil];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardDelegate.h b/SmartDeviceLink/public/SDLKeyboardDelegate.h
index 652066d64..33da49969 100644
--- a/SmartDeviceLink/public/SDLKeyboardDelegate.h
+++ b/SmartDeviceLink/public/SDLKeyboardDelegate.h
@@ -93,6 +93,14 @@ typedef void(^SDLKeyboardCharacterSetCompletionHandler)(NSArray<NSString *> *_Nu
*/
- (void)keyboardDidSendEvent:(SDLKeyboardEvent)event text:(NSString *)currentInputText;
+/**
+ Implement this to be notified of input key mask update (whether or not the user has changed the input to be hidden, like passwords)
+
+ @param isEnabled - YES if the mask is enabled, NO if the mask is disabled
+ @added in SmartDeviceLink 7.1.0
+ */
+- (void)keyboardDidUpdateInputMask:(BOOL)isEnabled;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardEvent.h b/SmartDeviceLink/public/SDLKeyboardEvent.h
index 1ac7b67e4..9e017c8d6 100644
--- a/SmartDeviceLink/public/SDLKeyboardEvent.h
+++ b/SmartDeviceLink/public/SDLKeyboardEvent.h
@@ -37,3 +37,13 @@ extern SDLKeyboardEvent const SDLKeyboardEventAborted;
@since SDL 4.0
*/
extern SDLKeyboardEvent const SDLKeyboardEventVoice;
+
+/**
+ * @added in SmartDeviceLink 7.1.0
+ */
+extern SDLKeyboardEvent const SDLKeyboardEventInputKeyMaskEnabled;
+
+/**
+ * @added in SmartDeviceLink 7.1.0
+ */
+extern SDLKeyboardEvent const SDLKeyboardEventInputKeyMaskDisabled;
diff --git a/SmartDeviceLink/public/SDLKeyboardEvent.m b/SmartDeviceLink/public/SDLKeyboardEvent.m
index 67f4e60f2..f55ac3597 100644
--- a/SmartDeviceLink/public/SDLKeyboardEvent.m
+++ b/SmartDeviceLink/public/SDLKeyboardEvent.m
@@ -9,3 +9,5 @@ SDLKeyboardEvent const SDLKeyboardEventSubmitted = @"ENTRY_SUBMITTED";
SDLKeyboardEvent const SDLKeyboardEventCancelled = @"ENTRY_CANCELLED";
SDLKeyboardEvent const SDLKeyboardEventAborted = @"ENTRY_ABORTED";
SDLKeyboardEvent const SDLKeyboardEventVoice = @"ENTRY_VOICE";
+SDLKeyboardEvent const SDLKeyboardEventInputKeyMaskEnabled = @"INPUT_KEY_MASK_ENABLED";
+SDLKeyboardEvent const SDLKeyboardEventInputKeyMaskDisabled = @"INPUT_KEY_MASK_DISABLED";
diff --git a/SmartDeviceLink/public/SDLKeyboardInputMask.h b/SmartDeviceLink/public/SDLKeyboardInputMask.h
new file mode 100644
index 000000000..fc16b1756
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardInputMask.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SDLEnum.h"
+
+/**
+ * Enumeration listing possible input character masking.
+ *
+ * @added in SmartDeviceLink 7.1.0
+ */
+typedef SDLEnum SDLKeyboardInputMask NS_TYPED_ENUM;
+
+extern SDLKeyboardInputMask const SDLKeyboardInputMaskEnableInputKeyMask;
+
+extern SDLKeyboardInputMask const SDLKeyboardInputMaskDisableInputKeyMask;
+
+extern SDLKeyboardInputMask const SDLKeyboardInputMaskUserChoiceInputKeyMask;
diff --git a/SmartDeviceLink/public/SDLKeyboardInputMask.m b/SmartDeviceLink/public/SDLKeyboardInputMask.m
new file mode 100644
index 000000000..e8be72db1
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardInputMask.m
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SDLKeyboardInputMask.h"
+
+SDLKeyboardInputMask const SDLKeyboardInputMaskEnableInputKeyMask = @"ENABLE_INPUT_KEY_MASK";
+SDLKeyboardInputMask const SDLKeyboardInputMaskDisableInputKeyMask = @"DISABLE_INPUT_KEY_MASK";
+SDLKeyboardInputMask const SDLKeyboardInputMaskUserChoiceInputKeyMask = @"USER_CHOICE_INPUT_KEY_MASK";
diff --git a/SmartDeviceLink/public/SDLKeyboardLayout.h b/SmartDeviceLink/public/SDLKeyboardLayout.h
index 4b4e97550..181836146 100644
--- a/SmartDeviceLink/public/SDLKeyboardLayout.h
+++ b/SmartDeviceLink/public/SDLKeyboardLayout.h
@@ -25,3 +25,8 @@ extern SDLKeyboardLayout const SDLKeyboardLayoutQWERTZ;
AZERTY layout (the name comes from the first six keys<br> appearing on the top left letter row of the keyboard and read from left to right)
*/
extern SDLKeyboardLayout const SDLKeyboardLayoutAZERTY;
+
+/**
+ * @added in SmartDeviceLink 7.1.0
+ */
+extern SDLKeyboardLayout const SDLKeyboardLayoutNumeric;
diff --git a/SmartDeviceLink/public/SDLKeyboardLayout.m b/SmartDeviceLink/public/SDLKeyboardLayout.m
index 7fa8e1958..0bc5ecc3b 100644
--- a/SmartDeviceLink/public/SDLKeyboardLayout.m
+++ b/SmartDeviceLink/public/SDLKeyboardLayout.m
@@ -7,3 +7,4 @@
SDLKeyboardLayout const SDLKeyboardLayoutQWERTY = @"QWERTY";
SDLKeyboardLayout const SDLKeyboardLayoutQWERTZ = @"QWERTZ";
SDLKeyboardLayout const SDLKeyboardLayoutAZERTY = @"AZERTY";
+SDLKeyboardLayout const SDLKeyboardLayoutNumeric = @"NUMERIC";
diff --git a/SmartDeviceLink/public/SDLKeyboardLayoutCapability.h b/SmartDeviceLink/public/SDLKeyboardLayoutCapability.h
new file mode 100644
index 000000000..b78218663
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardLayoutCapability.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SDLKeyboardLayout.h"
+#import "SDLRPCStruct.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Describes the capabilities of a single keyboard layout.
+ *
+ * @added in SmartDeviceLink 7.1.0
+ */
+@interface SDLKeyboardLayoutCapability : SDLRPCStruct
+
+/**
+ * @param keyboardLayout - keyboardLayout
+ * @param numConfigurableKeys - @(numConfigurableKeys)
+ * @return A SDLKeyboardLayoutCapability object
+ */
+- (instancetype)initWithKeyboardLayout:(SDLKeyboardLayout)keyboardLayout numConfigurableKeys:(UInt8)numConfigurableKeys;
+
+@property (strong, nonatomic) SDLKeyboardLayout keyboardLayout;
+
+/**
+ * Number of keys available for special characters, App can customize as per their needs.
+ * {"num_min_value": 0, "num_max_value": 10}
+ */
+@property (strong, nonatomic) NSNumber<SDLUInt> *numConfigurableKeys;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardLayoutCapability.m b/SmartDeviceLink/public/SDLKeyboardLayoutCapability.m
new file mode 100644
index 000000000..57cb9a81c
--- /dev/null
+++ b/SmartDeviceLink/public/SDLKeyboardLayoutCapability.m
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021, SmartDeviceLink Consortium, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the SmartDeviceLink Consortium Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "NSMutableDictionary+Store.h"
+#import "SDLKeyboardLayout.h"
+#import "SDLKeyboardLayoutCapability.h"
+#import "SDLRPCParameterNames.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLKeyboardLayoutCapability
+
+- (instancetype)initWithKeyboardLayout:(SDLKeyboardLayout)keyboardLayout numConfigurableKeys:(UInt8)numConfigurableKeys {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+ self.keyboardLayout = keyboardLayout;
+ self.numConfigurableKeys = @(numConfigurableKeys);
+ return self;
+}
+
+- (void)setKeyboardLayout:(SDLKeyboardLayout)keyboardLayout {
+ [self.store sdl_setObject:keyboardLayout forName:SDLRPCParameterNameKeyboardLayout];
+}
+
+- (SDLKeyboardLayout)keyboardLayout {
+ NSError *error = nil;
+ return [self.store sdl_enumForName:SDLRPCParameterNameKeyboardLayout error:&error];
+}
+
+- (void)setNumConfigurableKeys:(NSNumber<SDLUInt> *)numConfigurableKeys {
+ [self.store sdl_setObject:numConfigurableKeys forName:SDLRPCParameterNameNumConfigurableKeys];
+}
+
+- (NSNumber<SDLUInt> *)numConfigurableKeys {
+ NSError *error = nil;
+ return [self.store sdl_objectForName:SDLRPCParameterNameNumConfigurableKeys ofClass:NSNumber.class error:&error];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardProperties.h b/SmartDeviceLink/public/SDLKeyboardProperties.h
index a538b52bd..55a3ed1b0 100644
--- a/SmartDeviceLink/public/SDLKeyboardProperties.h
+++ b/SmartDeviceLink/public/SDLKeyboardProperties.h
@@ -1,11 +1,11 @@
// SDLKeyboardProperties.h
//
-#import "SDLRPCMessage.h"
-
+#import "SDLKeyboardInputMask.h"
#import "SDLKeyboardLayout.h"
#import "SDLKeypressMode.h"
#import "SDLLanguage.h"
+#import "SDLRPCStruct.h"
NS_ASSUME_NONNULL_BEGIN
@@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
@param autoCompleteList A list of strings to show the user to complete what they are typing.
@return The RPC object
*/
-- (instancetype)initWithLanguage:(nullable SDLLanguage)language layout:(nullable SDLKeyboardLayout)layout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteText:(nullable NSString *)autoCompleteText autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList __deprecated_msg("Use initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList: instead");
+- (instancetype)initWithLanguage:(nullable SDLLanguage)language layout:(nullable SDLKeyboardLayout)layout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteText:(nullable NSString *)autoCompleteText autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList __deprecated_msg("Use initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList:maskInputCharacters:customKeys: instead");
/**
* Convenience init with all properties.
@@ -37,7 +37,19 @@ NS_ASSUME_NONNULL_BEGIN
* @param autoCompleteList - autoCompleteList
* @return A SDLKeyboardProperties object
*/
-- (instancetype)initWithLanguage:(nullable SDLLanguage)language keyboardLayout:(nullable SDLKeyboardLayout)keyboardLayout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList;
+- (instancetype)initWithLanguage:(nullable SDLLanguage)language keyboardLayout:(nullable SDLKeyboardLayout)keyboardLayout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList __deprecated_msg("Use initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList:maskInputCharacters:customKeys: instead");
+
+/**
+ * @param language - language
+ * @param keyboardLayout - keyboardLayout
+ * @param keypressMode - keypressMode
+ * @param limitedCharacterList - limitedCharacterList
+ * @param autoCompleteList - autoCompleteList
+ * @param maskInputCharacters - maskInputCharacters
+ * @param customKeys - customKeys
+ * @return A SDLKeyboardProperties object
+ */
+- (instancetype)initWithLanguage:(nullable SDLLanguage)language keyboardLayout:(nullable SDLKeyboardLayout)keyboardLayout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList maskInputCharacters:(nullable SDLKeyboardInputMask)maskInputCharacters customKeys:(nullable NSArray<NSString *> *)customKeys;
/**
The keyboard language
@@ -85,6 +97,21 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nullable, strong, nonatomic) NSArray<NSString *> *autoCompleteList;
+/**
+ * Allows an app to mask entered characters on HMI
+ *
+ * @added in SmartDeviceLink 7.1.0
+ */
+@property (nullable, strong, nonatomic) SDLKeyboardInputMask maskInputCharacters;
+
+/**
+ * Array of special characters to show in customizable keys. If omitted, keyboard will show default special characters
+ * {"array_min_size": 1, "array_max_size": 10, "string_min_length": 1, "string_max_length": 1}
+ *
+ * @added in SmartDeviceLink 7.1.0
+ */
+@property (nullable, strong, nonatomic) NSArray<NSString *> *customKeys;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLKeyboardProperties.m b/SmartDeviceLink/public/SDLKeyboardProperties.m
index c21c91bc7..d57a21c2c 100644
--- a/SmartDeviceLink/public/SDLKeyboardProperties.m
+++ b/SmartDeviceLink/public/SDLKeyboardProperties.m
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLKeyboardProperties
- (instancetype)initWithLanguage:(nullable SDLLanguage)language layout:(nullable SDLKeyboardLayout)layout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteText:(nullable NSString *)autoCompleteText autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList {
- self = [[self init] initWithLanguage:language keyboardLayout:layout keypressMode:keypressMode limitedCharacterList:limitedCharacterList autoCompleteList:autoCompleteList];
+ self = [self initWithLanguage:language keyboardLayout:layout keypressMode:keypressMode limitedCharacterList:limitedCharacterList autoCompleteList:autoCompleteList maskInputCharacters:nil customKeys:nil];
if (!self) { return nil; }
self.autoCompleteText = autoCompleteText;
@@ -19,17 +19,21 @@ NS_ASSUME_NONNULL_BEGIN
}
- (instancetype)initWithLanguage:(nullable SDLLanguage)language keyboardLayout:(nullable SDLKeyboardLayout)keyboardLayout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList {
+ return [self initWithLanguage:language keyboardLayout:keyboardLayout keypressMode:keypressMode limitedCharacterList:limitedCharacterList autoCompleteList:autoCompleteList maskInputCharacters:nil customKeys:nil];
+}
+
+- (instancetype)initWithLanguage:(nullable SDLLanguage)language keyboardLayout:(nullable SDLKeyboardLayout)keyboardLayout keypressMode:(nullable SDLKeypressMode)keypressMode limitedCharacterList:(nullable NSArray<NSString *> *)limitedCharacterList autoCompleteList:(nullable NSArray<NSString *> *)autoCompleteList maskInputCharacters:(nullable SDLKeyboardInputMask)maskInputCharacters customKeys:(nullable NSArray<NSString *> *)customKeys {
self = [self init];
if (!self) {
return nil;
}
-
self.language = language;
self.keyboardLayout = keyboardLayout;
self.keypressMode = keypressMode;
self.limitedCharacterList = limitedCharacterList;
self.autoCompleteList = autoCompleteList;
-
+ self.maskInputCharacters = maskInputCharacters;
+ self.customKeys = customKeys;
return self;
}
@@ -81,6 +85,22 @@ NS_ASSUME_NONNULL_BEGIN
return [self.store sdl_objectsForName:SDLRPCParameterNameAutoCompleteList ofClass:NSString.class error:nil];
}
+- (void)setMaskInputCharacters:(nullable SDLKeyboardInputMask)maskInputCharacters {
+ [self.store sdl_setObject:maskInputCharacters forName:SDLRPCParameterNameMaskInputCharacters];
+}
+
+- (nullable SDLKeyboardInputMask)maskInputCharacters {
+ return [self.store sdl_enumForName:SDLRPCParameterNameMaskInputCharacters error:nil];
+}
+
+- (void)setCustomKeys:(nullable NSArray<NSString *> *)customKeys {
+ [self.store sdl_setObject:customKeys forName:SDLRPCParameterNameCustomKeys];
+}
+
+- (nullable NSArray<NSString *> *)customKeys {
+ return [self.store sdl_objectsForName:SDLRPCParameterNameCustomKeys ofClass:NSString.class error:nil];
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLManagerDelegate.h b/SmartDeviceLink/public/SDLManagerDelegate.h
index 2b01af879..5b3d6a981 100644
--- a/SmartDeviceLink/public/SDLManagerDelegate.h
+++ b/SmartDeviceLink/public/SDLManagerDelegate.h
@@ -13,6 +13,7 @@
#import "SDLSystemContext.h"
#import "SDLLifecycleConfigurationUpdate.h"
#import "SDLLanguage.h"
+#import "SDLSystemInfo.h"
#import "SDLVideoStreamingState.h"
NS_ASSUME_NONNULL_BEGIN
@@ -67,6 +68,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable SDLLifecycleConfigurationUpdate *)managerShouldUpdateLifecycleToLanguage:(SDLLanguage)language hmiLanguage:(SDLLanguage)hmiLanguage;
+/**
+ * A way to determine if this SDL session should continue to be active while connected to the determined system information of the vehicle.
+ * @param systemInfo The system information of the vehicle that this session is currently active on.
+ * @return True if this session should continue, false if the session should end
+ */
+- (BOOL)didReceiveSystemInfo:(SDLSystemInfo *)systemInfo NS_SWIFT_NAME(didReceive(systemInfo:));
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLMenuCell.h b/SmartDeviceLink/public/SDLMenuCell.h
index 5f1e54849..f8383e44c 100644
--- a/SmartDeviceLink/public/SDLMenuCell.h
+++ b/SmartDeviceLink/public/SDLMenuCell.h
@@ -84,7 +84,7 @@ typedef void(^SDLMenuCellSelectionHandler)(SDLTriggerSource triggerSource);
@param handler The code that will be run when the menu cell is selected
@return The menu cell
*/
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon voiceCommands:(nullable NSArray<NSString *> *)voiceCommands handler:(SDLMenuCellSelectionHandler)handler __deprecated_msg("Use initWithTitle:icon:voiceCommands:secondaryText:tertiaryText:secondaryArtwork:handler: instead");
+- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon voiceCommands:(nullable NSArray<NSString *> *)voiceCommands handler:(SDLMenuCellSelectionHandler)handler __deprecated_msg("Use initWithTitle:secondaryText:tertiaryText:icon:secondaryArtwork:voiceCommands:handler: instead");
/**
Create a menu cell that has subcells and when selected will go into a deeper part of the menu
@@ -95,35 +95,35 @@ typedef void(^SDLMenuCellSelectionHandler)(SDLTriggerSource triggerSource);
@param subCells The subcells that will appear when the cell is selected
@return The menu cell
*/
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells __deprecated_msg("Use initWithTitle:icon:submenuLayout:subCells:secondaryText:tertiaryText:secondaryArtwork: instead");
+- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells __deprecated_msg("Use initWithTitle:secondaryText:tertiaryText:icon:secondaryArtwork:submenuLayout:subCells: instead");
/**
Create a menu cell that has no subcells.
@param title The cell's primary text
- @param icon The cell's image
- @param voiceCommands Voice commands that will activate the menu cell
@param secondaryText - secondaryText
@param tertiaryText - tertiaryText
+ @param icon The cell's image
@param secondaryArtwork - secondaryArtwork
+ @param voiceCommands Voice commands that will activate the menu cell
@param handler The code that will be run when the menu cell is selected
@return The menu cell
*/
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon voiceCommands:(nullable NSArray<NSString *> *)voiceCommands secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork handler:(SDLMenuCellSelectionHandler)handler;
+- (instancetype)initWithTitle:(NSString *)title secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText icon:(nullable SDLArtwork *)icon secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork voiceCommands:(nullable NSArray<NSString *> *)voiceCommands handler:(SDLMenuCellSelectionHandler)handler;
/**
Create a menu cell that has subcells and when selected will go into a deeper part of the menu
@param title The cell's primary text
- @param icon The cell's image
- @param layout The layout that the subCells will be layed out in if that submenu is entered
- @param subCells The subcells that will appear when the cell is selected
@param secondaryText - secondaryText
@param tertiaryText - tertiaryText
+ @param icon The cell's image
@param secondaryArtwork - secondaryArtwork
+ @param layout The layout that the subCells will be layed out in if that submenu is entered
+ @param subCells The subcells that will appear when the cell is selected
@return The menu cell
*/
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork;
+- (instancetype)initWithTitle:(NSString *)title secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText icon:(nullable SDLArtwork *)icon secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells;
@end
diff --git a/SmartDeviceLink/public/SDLMenuCell.m b/SmartDeviceLink/public/SDLMenuCell.m
index 1ad597e11..b9f0a7be4 100644
--- a/SmartDeviceLink/public/SDLMenuCell.m
+++ b/SmartDeviceLink/public/SDLMenuCell.m
@@ -24,14 +24,14 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLMenuCell
- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon voiceCommands:(nullable NSArray<NSString *> *)voiceCommands handler:(SDLMenuCellSelectionHandler)handler {
- return [self initWithTitle:title icon:icon voiceCommands:voiceCommands secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:handler];
+ return [self initWithTitle:title secondaryText:nil tertiaryText:nil icon:icon secondaryArtwork:nil voiceCommands:voiceCommands handler:handler];
}
- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells {
- return [self initWithTitle:title icon:icon submenuLayout:layout subCells:subCells secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ return [self initWithTitle:title secondaryText:nil tertiaryText:nil icon:icon secondaryArtwork:nil submenuLayout:layout subCells:subCells];
}
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon voiceCommands:(nullable NSArray<NSString *> *)voiceCommands secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork handler:(SDLMenuCellSelectionHandler)handler {
+- (instancetype)initWithTitle:(NSString *)title secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText icon:(nullable SDLArtwork *)icon secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork voiceCommands:(nullable NSArray<NSString *> *)voiceCommands handler:(SDLMenuCellSelectionHandler)handler {
self = [super init];
if (!self) { return nil; }
@@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
-- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork {
+- (instancetype)initWithTitle:(NSString *)title secondaryText:(nullable NSString *)secondaryText tertiaryText:(nullable NSString *)tertiaryText icon:(nullable SDLArtwork *)icon secondaryArtwork:(nullable SDLArtwork *)secondaryArtwork submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray<SDLMenuCell *> *)subCells {
self = [super init];
if (!self) { return nil; }
diff --git a/SmartDeviceLink/public/SDLRegisterAppInterfaceResponse.h b/SmartDeviceLink/public/SDLRegisterAppInterfaceResponse.h
index 3538e22e3..ea037da92 100644
--- a/SmartDeviceLink/public/SDLRegisterAppInterfaceResponse.h
+++ b/SmartDeviceLink/public/SDLRegisterAppInterfaceResponse.h
@@ -147,13 +147,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (nullable, strong, nonatomic) SDLAudioPassThruCapabilities *pcmStreamCapabilities;
/**
- * Specifies the connected vehicle's type.
+ * Specifies the vehicle's type. See VehicleType.
*
- * SDLVehicleType, Optional
+ * @deprecated in SmartDeviceLink 7.1.0
*
- * @since SDL 2.0
+ * @added in SmartDeviceLink 2.0.0
*/
-@property (nullable, strong, nonatomic) SDLVehicleType *vehicleType;
+@property (nullable, strong, nonatomic) SDLVehicleType *vehicleType __deprecated_msg("Implement SDLManager.delegate.didReceiveSystemInfo instead");
/**
* Specifies the white-list of supported diagnostic modes (0x00-0xFF) capable for DiagnosticMessage requests. If a mode outside this list is requested, it will be rejected.
@@ -184,12 +184,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
* The software version of the system that implements the SmartDeviceLink core.
+ *
+ * {"string_min_length": 1, "string_max_length": 100}
*
- * String, Optional, Max length: 100
+ * @deprecated in SDL 7.1.0
*
- * @since SDL 3.0
+ * @added in SDL 3.0.0
*/
-@property (nullable, strong, nonatomic) NSString *systemSoftwareVersion;
+@property (nullable, strong, nonatomic) NSString *systemSoftwareVersion __deprecated_msg("Implement SDLManager.delegate.didReceiveSystemInfo instead");
/**
* Existence of apps icon at system. If true, apps icon was resumed at system. If false, apps icon is not resumed at system.
diff --git a/SmartDeviceLink/public/SDLScreenManager.h b/SmartDeviceLink/public/SDLScreenManager.h
index 20d6c151d..c941eaced 100644
--- a/SmartDeviceLink/public/SDLScreenManager.h
+++ b/SmartDeviceLink/public/SDLScreenManager.h
@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import "NSNumber+NumberType.h"
+#import "SDLAlertView.h"
#import "SDLButtonName.h"
#import "SDLInteractionMode.h"
#import "SDLMenuManagerConstants.h"
@@ -25,6 +26,7 @@
@class SDLMenuConfiguration;
@class SDLOnButtonEvent;
@class SDLOnButtonPress;
+@class SDLPermissionManager;
@class SDLSoftButtonObject;
@class SDLSystemCapabilityManager;
@class SDLTemplateConfiguration;
@@ -228,14 +230,27 @@ If set to `SDLDynamicMenuUpdatesModeForceOff`, menu updates will work the legacy
/**
Initialize a screen manager
+ @warning For internal use. An exception will be thrown if used.
+
+ @param connectionManager The connection manager used to send RPCs
+ @param fileManager The file manager used to upload files
+ @param systemCapabilityManager The system capability manager object for reading window capabilities
+ @return The screen manager
+ */
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager __deprecated_msg("Use initWithConnectionManager:fileManager:systemCapabilityManager:permissionManager: instead");
+
+/**
+ Initialize a screen manager
+
@warning For internal use
@param connectionManager The connection manager used to send RPCs
@param fileManager The file manager used to upload files
@param systemCapabilityManager The system capability manager object for reading window capabilities
+ @param permissionManager The permission manager object for checking RPC permissions
@return The screen manager
*/
-- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager;
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager permissionManager:(SDLPermissionManager *)permissionManager;
/**
Starts the manager and all sub-managers
@@ -410,6 +425,18 @@ If set to `SDLDynamicMenuUpdatesModeForceOff`, menu updates will work the legacy
*/
- (BOOL)openSubmenu:(SDLMenuCell *)cell;
+#pragma mark - Alert
+
+/// Present the alert on the screen. To replace a currently presenting alert with a new alert, you must first call `cancel` on the currently presenting alert before sending the new alert. Otherwise the newest alert will only be presented when the module dismisses the currently presented alert (either due to the timeout or the user selecting a button on the alert). Please note that cancelling a currently presented alert will only work on modules supporting RPC Spec v.5.0+.
+///
+/// If the alert contains an audio indication with a file that needs to be uploaded, it will be uploaded before presenting the alert. If the alert contains soft buttons with images, they will be uploaded before presenting the alert. If the alert contains an icon, that will be uploaded before presenting the alert.
+///
+/// The handler will be called when the alert either dismisses from the screen or it has failed to present. If the error value in the handler is present, then the alert failed to appear or was aborted, if not, then the alert dismissed without error. The `userInfo` object on the error contais an `error` key with more information about the error. If the alert failed to present, the `userInfo` object will contain a `tryAgainTime` key with information on how long to wait before trying to send another alert. The value for `tryAgainTime` may be `nil` if the module did not return a value in its response.
+///
+/// @param alert Alert to be presented
+/// @param handler The handler to be called when the alert either dismisses from the screen or it has failed to present.
+- (void)presentAlert:(SDLAlertView *)alert withCompletionHandler:(nullable SDLScreenManagerUpdateCompletionHandler)handler;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLScreenManager.m b/SmartDeviceLink/public/SDLScreenManager.m
index a8792e2fa..ea60f9584 100644
--- a/SmartDeviceLink/public/SDLScreenManager.m
+++ b/SmartDeviceLink/public/SDLScreenManager.m
@@ -7,9 +7,12 @@
//
#import "SDLScreenManager.h"
+
+#import "SDLAlertManager.h"
#import "SDLArtwork.h"
#import "SDLChoiceSetManager.h"
#import "SDLMenuManager.h"
+#import "SDLPermissionManager.h"
#import "SDLSoftButtonManager.h"
#import "SDLSubscribeButtonManager.h"
#import "SDLTextAndGraphicManager.h"
@@ -25,22 +28,29 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic) SDLVoiceCommandManager *voiceCommandMenuManager;
@property (strong, nonatomic) SDLChoiceSetManager *choiceSetManager;
@property (strong, nonatomic) SDLSubscribeButtonManager *subscribeButtonManager;
+@property (strong, nonatomic) SDLAlertManager *alertManager;
-@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
-@property (weak, nonatomic) SDLFileManager *fileManager;
-@property (weak, nonatomic) SDLSystemCapabilityManager *systemCapabilityManager;
+@property (weak, nonatomic, nullable) id<SDLConnectionManagerType> connectionManager;
+@property (weak, nonatomic, nullable) SDLFileManager *fileManager;
+@property (weak, nonatomic, nullable) SDLSystemCapabilityManager *systemCapabilityManager;
+@property (weak, nonatomic, nullable) SDLPermissionManager *permissionManager;
@end
@implementation SDLScreenManager
- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager {
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"This convenience init is for internal use only and is no longer used. The initWithConnectionManager:fileManager:systemCapabilityManager:permissionManager: convenience init is now used." userInfo:nil];
+}
+
+- (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager fileManager:(SDLFileManager *)fileManager systemCapabilityManager:(SDLSystemCapabilityManager *)systemCapabilityManager permissionManager:(SDLPermissionManager *)permissionManager {
self = [super init];
if (!self) { return nil; }
_connectionManager = connectionManager;
_fileManager = fileManager;
_systemCapabilityManager = systemCapabilityManager;
+ _permissionManager = permissionManager;
_textAndGraphicManager = [[SDLTextAndGraphicManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager systemCapabilityManager:systemCapabilityManager];
_softButtonManager = [[SDLSoftButtonManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager systemCapabilityManager:systemCapabilityManager];
@@ -48,6 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
_menuManager = [[SDLMenuManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager systemCapabilityManager:systemCapabilityManager];
_voiceCommandMenuManager = [[SDLVoiceCommandManager alloc] initWithConnectionManager:connectionManager];
_choiceSetManager = [[SDLChoiceSetManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager systemCapabilityManager:systemCapabilityManager];
+ _alertManager = [[SDLAlertManager alloc] initWithConnectionManager:connectionManager fileManager:fileManager systemCapabilityManager:systemCapabilityManager permissionManager:permissionManager];
return self;
}
@@ -58,6 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.menuManager start];
[self.choiceSetManager start];
[self.subscribeButtonManager start];
+ [self.alertManager start];
handler(nil);
}
@@ -69,6 +81,7 @@ NS_ASSUME_NONNULL_BEGIN
[self.voiceCommandMenuManager stop];
[self.choiceSetManager stop];
[self.subscribeButtonManager stop];
+ [self.alertManager stop];
}
#pragma mark - Setters
@@ -326,6 +339,12 @@ NS_ASSUME_NONNULL_BEGIN
return [self.menuManager openSubmenu:cell];
}
+#pragma mark - Alert
+
+- (void)presentAlert:(SDLAlertView *)alert withCompletionHandler:(nullable SDLScreenManagerUpdateCompletionHandler)handler {
+ [self.alertManager presentAlert:alert withCompletionHandler:handler];
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLSystemCapabilityManager.m b/SmartDeviceLink/public/SDLSystemCapabilityManager.m
index bd61a2e05..11f3bd570 100644
--- a/SmartDeviceLink/public/SDLSystemCapabilityManager.m
+++ b/SmartDeviceLink/public/SDLSystemCapabilityManager.m
@@ -170,13 +170,14 @@ typedef NSString * SDLServiceID;
return nil;
}
- SDLDisplayCapability *mainDisplay = capabilities.firstObject;
+ SDLDisplayCapability *mainDisplay = capabilities[0];
for (SDLWindowCapability *windowCapability in mainDisplay.windowCapabilities) {
NSUInteger currentWindowID = windowCapability.windowID != nil ? windowCapability.windowID.unsignedIntegerValue : SDLPredefinedWindowsDefaultWindow;
- if (currentWindowID == windowID) {
- return windowCapability;
- }
+ if (currentWindowID != windowID) { continue; }
+
+ return windowCapability;
}
+
return nil;
}
diff --git a/SmartDeviceLink/public/SDLSystemInfo.h b/SmartDeviceLink/public/SDLSystemInfo.h
new file mode 100644
index 000000000..0a14f7fb8
--- /dev/null
+++ b/SmartDeviceLink/public/SDLSystemInfo.h
@@ -0,0 +1,43 @@
+//
+// SDLSystemInfo.h
+// SmartDeviceLink
+//
+// Created by Joel Fischer on 2/23/21.
+// Copyright © 2021 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class SDLVehicleType;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLSystemInfo : NSObject
+
+/// The connected module's vehicle type: it's make, model, trim, and model year
+@property (strong, nonatomic, readonly, nullable) SDLVehicleType *vehicleType;
+
+/// The connected module's software version
+@property (strong, nonatomic, readonly, nullable) NSString *systemSoftwareVersion;
+
+/// The connected module's hardware version
+@property (strong, nonatomic, readonly, nullable) NSString *systemHardwareVersion;
+
+/// Initialize a system info object with individual pieces
+/// @param make The vehicle's make
+/// @param model The vehicle's model
+/// @param trim The vehicle's trim
+/// @param modelYear The vehicle's model year
+/// @param softwareVersion The vehicle's software version
+/// @param hardwareVersion The vehicle's hardware version
+- (instancetype)initWithMake:(nullable NSString *)make model:(nullable NSString *)model trim:(nullable NSString *)trim modelYear:(nullable NSString *)modelYear softwareVersion:(nullable NSString *)softwareVersion hardwareVersion:(nullable NSString *)hardwareVersion;
+
+/// Initialize a system info object with the vehicle type and versions
+/// @param vehicleType The vehicle information
+/// @param softwareVersion The vehicle's software version
+/// @param hardwareVersion The vehicle's hardware version
+- (instancetype)initWithVehicleType:(nullable SDLVehicleType *)vehicleType softwareVersion:(nullable NSString *)softwareVersion hardwareVersion:(nullable NSString *)hardwareVersion;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLSystemInfo.m b/SmartDeviceLink/public/SDLSystemInfo.m
new file mode 100644
index 000000000..8b0df3100
--- /dev/null
+++ b/SmartDeviceLink/public/SDLSystemInfo.m
@@ -0,0 +1,49 @@
+//
+// SDLSystemInfo.m
+// SmartDeviceLink
+//
+// Created by Joel Fischer on 2/23/21.
+// Copyright © 2021 smartdevicelink. All rights reserved.
+//
+
+#import "SDLSystemInfo.h"
+
+#import "SDLVehicleType.h"
+
+@interface SDLSystemInfo ()
+
+@property (strong, nonatomic, readwrite, nullable) SDLVehicleType *vehicleType;
+@property (strong, nonatomic, readwrite, nullable) NSString *systemSoftwareVersion;
+@property (strong, nonatomic, readwrite, nullable) NSString *systemHardwareVersion;
+
+@end
+
+@implementation SDLSystemInfo
+
+- (instancetype)initWithMake:(nullable NSString *)make model:(nullable NSString *)model trim:(nullable NSString *)trim modelYear:(nullable NSString *)modelYear softwareVersion:(nullable NSString *)softwareVersion hardwareVersion:(nullable NSString *)hardwareVersion {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _vehicleType = [[SDLVehicleType alloc] initWithMake:make model:model modelYear:modelYear trim:trim];
+ _systemSoftwareVersion = softwareVersion;
+ _systemHardwareVersion = hardwareVersion;
+
+ return self;
+}
+
+- (instancetype)initWithVehicleType:(nullable SDLVehicleType *)vehicleType softwareVersion:(nullable NSString *)softwareVersion hardwareVersion:(nullable NSString *)hardwareVersion {
+ self = [super init];
+ if (!self) { return nil; }
+
+ _vehicleType = vehicleType;
+ _systemSoftwareVersion = softwareVersion;
+ _systemHardwareVersion = hardwareVersion;
+
+ return self;
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"Vehicle Type: %@, software version: %@, hardware version: %@", _vehicleType, _systemSoftwareVersion, _systemHardwareVersion];
+}
+
+@end
diff --git a/SmartDeviceLink/public/SDLTextFieldName.h b/SmartDeviceLink/public/SDLTextFieldName.h
index 593c8b26e..33fb61eaf 100644
--- a/SmartDeviceLink/public/SDLTextFieldName.h
+++ b/SmartDeviceLink/public/SDLTextFieldName.h
@@ -232,7 +232,7 @@ extern SDLTextFieldName const SDLTextFieldNameAddressLines;
extern SDLTextFieldName const SDLTextFieldNamePhoneNumber;
/**
- * Optional time to destination field for navigationTexts parameter in ShowConstantTBT
+ * Optional time to destination field for ShowConstantTBT
*
* @added in SmartDeviceLink 7.1.0
*/
diff --git a/SmartDeviceLink/public/SDLVehicleType.h b/SmartDeviceLink/public/SDLVehicleType.h
index 0c9c100dc..f2a4da7ca 100644
--- a/SmartDeviceLink/public/SDLVehicleType.h
+++ b/SmartDeviceLink/public/SDLVehicleType.h
@@ -49,6 +49,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (strong, nonatomic, nullable) NSString *trim;
+/**
+ * Initialize the object
+ *
+ * @param make - make
+ * @param model - model
+ * @param modelYear - modelYear
+ * @param trim - trim
+ * @return A SDLVehicleType object
+ */
+- (instancetype)initWithMake:(nullable NSString *)make model:(nullable NSString *)model modelYear:(nullable NSString *)modelYear trim:(nullable NSString *)trim;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLVehicleType.m b/SmartDeviceLink/public/SDLVehicleType.m
index 5f3df0700..15a47b9f0 100644
--- a/SmartDeviceLink/public/SDLVehicleType.m
+++ b/SmartDeviceLink/public/SDLVehicleType.m
@@ -11,6 +11,18 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLVehicleType
+- (instancetype)initWithMake:(nullable NSString *)make model:(nullable NSString *)model modelYear:(nullable NSString *)modelYear trim:(nullable NSString *)trim {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+ self.make = make;
+ self.model = model;
+ self.modelYear = modelYear;
+ self.trim = trim;
+ return self;
+}
+
- (void)setMake:(nullable NSString *)make {
[self.store sdl_setObject:make forName:SDLRPCParameterNameMake];
}
diff --git a/SmartDeviceLink/public/SDLWindowCapability.h b/SmartDeviceLink/public/SDLWindowCapability.h
index 4795e667b..afb7a905e 100644
--- a/SmartDeviceLink/public/SDLWindowCapability.h
+++ b/SmartDeviceLink/public/SDLWindowCapability.h
@@ -38,10 +38,10 @@
@class SDLButtonCapabilities;
@class SDLDynamicUpdateCapabilities;
@class SDLImageField;
+@class SDLKeyboardCapabilities;
@class SDLSoftButtonCapabilities;
@class SDLTextField;
-
NS_ASSUME_NONNULL_BEGIN
/**
@@ -64,7 +64,23 @@ NS_ASSUME_NONNULL_BEGIN
* @param dynamicUpdateCapabilities - dynamicUpdateCapabilities
* @return A SDLWindowCapability object
*/
-- (instancetype)initWithWindowID:(nullable NSNumber<SDLInt> *)windowID textFields:(nullable NSArray<SDLTextField *> *)textFields imageFields:(nullable NSArray<SDLImageField *> *)imageFields imageTypeSupported:(nullable NSArray<SDLImageType> *)imageTypeSupported templatesAvailable:(nullable NSArray<NSString *> *)templatesAvailable numCustomPresetsAvailable:(nullable NSNumber<SDLUInt> *)numCustomPresetsAvailable buttonCapabilities:(nullable NSArray<SDLButtonCapabilities *> *)buttonCapabilities softButtonCapabilities:(nullable NSArray<SDLSoftButtonCapabilities *> *)softButtonCapabilities menuLayoutsAvailable:(nullable NSArray<SDLMenuLayout> *)menuLayoutsAvailable dynamicUpdateCapabilities:(nullable SDLDynamicUpdateCapabilities *)dynamicUpdateCapabilities;
+- (instancetype)initWithWindowID:(nullable NSNumber<SDLInt> *)windowID textFields:(nullable NSArray<SDLTextField *> *)textFields imageFields:(nullable NSArray<SDLImageField *> *)imageFields imageTypeSupported:(nullable NSArray<SDLImageType> *)imageTypeSupported templatesAvailable:(nullable NSArray<NSString *> *)templatesAvailable numCustomPresetsAvailable:(nullable NSNumber<SDLUInt> *)numCustomPresetsAvailable buttonCapabilities:(nullable NSArray<SDLButtonCapabilities *> *)buttonCapabilities softButtonCapabilities:(nullable NSArray<SDLSoftButtonCapabilities *> *)softButtonCapabilities menuLayoutsAvailable:(nullable NSArray<SDLMenuLayout> *)menuLayoutsAvailable dynamicUpdateCapabilities:(nullable SDLDynamicUpdateCapabilities *)dynamicUpdateCapabilities __deprecated_msg("please use initWithWindowID:textFields:imageFields:imageTypeSupported:templatesAvailable:numCustomPresetsAvailable:buttonCapabilities:softButtonCapabilities:menuLayoutsAvailable:dynamicUpdateCapabilities:keyboardCapabilities: instead");
+
+/**
+ * @param windowID - windowID
+ * @param textFields - textFields
+ * @param imageFields - imageFields
+ * @param imageTypeSupported - imageTypeSupported
+ * @param templatesAvailable - templatesAvailable
+ * @param numCustomPresetsAvailable - numCustomPresetsAvailable
+ * @param buttonCapabilities - buttonCapabilities
+ * @param softButtonCapabilities - softButtonCapabilities
+ * @param menuLayoutsAvailable - menuLayoutsAvailable
+ * @param dynamicUpdateCapabilities - dynamicUpdateCapabilities
+ * @param keyboardCapabilities - keyboardCapabilities
+ * @return A SDLWindowCapability object
+ */
+- (instancetype)initWithWindowID:(nullable NSNumber<SDLInt> *)windowID textFields:(nullable NSArray<SDLTextField *> *)textFields imageFields:(nullable NSArray<SDLImageField *> *)imageFields imageTypeSupported:(nullable NSArray<SDLImageType> *)imageTypeSupported templatesAvailable:(nullable NSArray<NSString *> *)templatesAvailable numCustomPresetsAvailable:(nullable NSNumber<SDLUInt> *)numCustomPresetsAvailable buttonCapabilities:(nullable NSArray<SDLButtonCapabilities *> *)buttonCapabilities softButtonCapabilities:(nullable NSArray<SDLSoftButtonCapabilities *> *)softButtonCapabilities menuLayoutsAvailable:(nullable NSArray<SDLMenuLayout> *)menuLayoutsAvailable dynamicUpdateCapabilities:(nullable SDLDynamicUpdateCapabilities *)dynamicUpdateCapabilities keyboardCapabilities:(nullable SDLKeyboardCapabilities *)keyboardCapabilities;
/**
The specified ID of the window. Can be set to a predefined window, or omitted for the main window on the main display.
@@ -136,6 +152,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nullable, strong, nonatomic) SDLDynamicUpdateCapabilities *dynamicUpdateCapabilities;
+/**
+ * See KeyboardCapabilities
+ *
+ * @added in SmartDeviceLink 7.1.0
+ */
+@property (nullable, strong, nonatomic) SDLKeyboardCapabilities *keyboardCapabilities;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/public/SDLWindowCapability.m b/SmartDeviceLink/public/SDLWindowCapability.m
index 9c3ebe7e2..3db3195ff 100644
--- a/SmartDeviceLink/public/SDLWindowCapability.m
+++ b/SmartDeviceLink/public/SDLWindowCapability.m
@@ -36,6 +36,7 @@
#import "SDLButtonCapabilities.h"
#import "SDLDynamicUpdateCapabilities.h"
#import "SDLImageField.h"
+#import "SDLKeyboardCapabilities.h"
#import "SDLRPCParameterNames.h"
#import "SDLSoftButtonCapabilities.h"
#import "SDLTextField.h"
@@ -43,6 +44,10 @@
@implementation SDLWindowCapability
- (instancetype)initWithWindowID:(nullable NSNumber<SDLInt> *)windowID textFields:(nullable NSArray<SDLTextField *> *)textFields imageFields:(nullable NSArray<SDLImageField *> *)imageFields imageTypeSupported:(nullable NSArray<SDLImageType> *)imageTypeSupported templatesAvailable:(nullable NSArray<NSString *> *)templatesAvailable numCustomPresetsAvailable:(nullable NSNumber<SDLUInt> *)numCustomPresetsAvailable buttonCapabilities:(nullable NSArray<SDLButtonCapabilities *> *)buttonCapabilities softButtonCapabilities:(nullable NSArray<SDLSoftButtonCapabilities *> *)softButtonCapabilities menuLayoutsAvailable:(nullable NSArray<SDLMenuLayout> *)menuLayoutsAvailable dynamicUpdateCapabilities:(nullable SDLDynamicUpdateCapabilities *)dynamicUpdateCapabilities {
+ return [self initWithWindowID:windowID textFields:textFields imageFields:imageFields imageTypeSupported:imageTypeSupported templatesAvailable:templatesAvailable numCustomPresetsAvailable:numCustomPresetsAvailable buttonCapabilities:buttonCapabilities softButtonCapabilities:softButtonCapabilities menuLayoutsAvailable:menuLayoutsAvailable dynamicUpdateCapabilities:dynamicUpdateCapabilities keyboardCapabilities:nil];
+}
+
+- (instancetype)initWithWindowID:(nullable NSNumber<SDLInt> *)windowID textFields:(nullable NSArray<SDLTextField *> *)textFields imageFields:(nullable NSArray<SDLImageField *> *)imageFields imageTypeSupported:(nullable NSArray<SDLImageType> *)imageTypeSupported templatesAvailable:(nullable NSArray<NSString *> *)templatesAvailable numCustomPresetsAvailable:(nullable NSNumber<SDLUInt> *)numCustomPresetsAvailable buttonCapabilities:(nullable NSArray<SDLButtonCapabilities *> *)buttonCapabilities softButtonCapabilities:(nullable NSArray<SDLSoftButtonCapabilities *> *)softButtonCapabilities menuLayoutsAvailable:(nullable NSArray<SDLMenuLayout> *)menuLayoutsAvailable dynamicUpdateCapabilities:(nullable SDLDynamicUpdateCapabilities *)dynamicUpdateCapabilities keyboardCapabilities:(nullable SDLKeyboardCapabilities *)keyboardCapabilities {
self = [super init];
if (!self) {
return nil;
@@ -57,6 +62,7 @@
self.softButtonCapabilities = softButtonCapabilities;
self.menuLayoutsAvailable = menuLayoutsAvailable;
self.dynamicUpdateCapabilities = dynamicUpdateCapabilities;
+ self.keyboardCapabilities = keyboardCapabilities;
return self;
}
@@ -141,4 +147,12 @@
return [self.store sdl_objectForName:SDLRPCParameterNameDynamicUpdateCapabilities ofClass:SDLDynamicUpdateCapabilities.class error:nil];
}
+- (void)setKeyboardCapabilities:(nullable SDLKeyboardCapabilities *)keyboardCapabilities {
+ [self.store sdl_setObject:keyboardCapabilities forName:SDLRPCParameterNameKeyboardCapabilities];
+}
+
+- (nullable SDLKeyboardCapabilities *)keyboardCapabilities {
+ return [self.store sdl_objectForName:SDLRPCParameterNameKeyboardCapabilities ofClass:SDLKeyboardCapabilities.class error:nil];
+}
+
@end
diff --git a/SmartDeviceLink/public/SmartDeviceLink.h b/SmartDeviceLink/public/SmartDeviceLink.h
index 8b8b6f68d..82f0735a6 100644
--- a/SmartDeviceLink/public/SmartDeviceLink.h
+++ b/SmartDeviceLink/public/SmartDeviceLink.h
@@ -225,6 +225,8 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLImage.h"
#import "SDLImageField.h"
#import "SDLImageResolution.h"
+#import "SDLKeyboardCapabilities.h"
+#import "SDLKeyboardLayoutCapability.h"
#import "SDLKeyboardProperties.h"
#import "SDLLightCapabilities.h"
#import "SDLLightControlCapabilities.h"
@@ -340,6 +342,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLImageType.h"
#import "SDLInteractionMode.h"
#import "SDLKeyboardEvent.h"
+#import "SDLKeyboardInputMask.h"
#import "SDLKeyboardLayout.h"
#import "SDLKeypressMode.h"
#import "SDLLanguage.h"
@@ -472,6 +475,10 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLChoiceSetDelegate.h"
#import "SDLKeyboardDelegate.h"
+#import "SDLAlertAudioData.h"
+#import "SDLAlertView.h"
+#import "SDLAudioData.h"
+
#pragma mark Touches
#import "SDLPinchGesture.h"
#import "SDLTouch.h"
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
index 1a44ad8f5..3fde3aa15 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLChoiceSetManagerSpec.m
@@ -35,6 +35,7 @@
@interface SDLPresentChoiceSetOperation()
@property (copy, nonatomic, nullable) NSError *internalError;
+@property (assign, nonatomic) UInt16 cancelId;
@end
@@ -48,6 +49,7 @@
@property (strong, nonatomic, readonly) SDLStateMachine *stateMachine;
@property (strong, nonatomic) NSOperationQueue *transactionQueue;
+@property (assign, nonatomic) UInt16 nextCancelId;
@property (copy, nonatomic, nullable) SDLHMILevel currentHMILevel;
@property (copy, nonatomic, nullable) SDLSystemContext currentSystemContext;
@@ -62,7 +64,7 @@
@property (assign, nonatomic, getter=isVROptional) BOOL vrOptional;
- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification;
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability;
+- (void)sdl_displayCapabilityDidUpdate;
- (void)sdl_addUniqueNamesToCells:(NSMutableSet<SDLChoiceCell *> *)choices;
@end
@@ -112,7 +114,7 @@ describe(@"choice set manager tests", ^{
it(@"should be in the correct startup state", ^{
expect(testManager.currentState).to(equal(SDLChoiceManagerStateShutdown));
- SDLKeyboardProperties *defaultProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageEnUs keyboardLayout:SDLKeyboardLayoutQWERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil];
+ SDLKeyboardProperties *defaultProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageEnUs keyboardLayout:SDLKeyboardLayoutQWERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil];
expect(testManager.keyboardConfiguration).to(equal(defaultProperties));
});
@@ -141,9 +143,8 @@ describe(@"choice set manager tests", ^{
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]]];
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(enabledWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
expect(testManager.transactionQueue.isSuspended).to(beFalse());
});
@@ -165,15 +166,15 @@ describe(@"choice set manager tests", ^{
});
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]]];
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(disabledWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
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]]];
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(blankWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
expect(testManager.transactionQueue.isSuspended).to(beTrue());
});
@@ -573,6 +574,45 @@ describe(@"choice set manager tests", ^{
});
});
+ describe(@"generating a cancel id", ^{
+ __block SDLChoiceSet *testChoiceSet = nil;
+ __block id<SDLChoiceSetDelegate> testChoiceDelegate = nil;
+
+ beforeEach(^{
+ testChoiceDelegate = OCMProtocolMock(@protocol(SDLChoiceSetDelegate));
+ testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:@"tests" delegate:testChoiceDelegate choices:@[testCell1]];
+ testManager = [[SDLChoiceSetManager alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager systemCapabilityManager:testSystemCapabilityManager];
+ [testManager.stateMachine setToState:SDLChoiceManagerStateReady fromOldState:SDLChoiceManagerStateCheckingVoiceOptional callEnterTransition:NO];
+ });
+
+ it(@"should set the first cancelID correctly", ^{
+ [testManager presentChoiceSet:testChoiceSet mode:SDLInteractionModeBoth withKeyboardDelegate:nil];
+
+ expect(testManager.transactionQueue.operations.count).to(equal(2));
+ expect(testManager.transactionQueue.operations[0]).to(beAKindOf([SDLPreloadChoicesOperation class]));
+ SDLPresentChoiceSetOperation *testPresentOp = (SDLPresentChoiceSetOperation *)testManager.transactionQueue.operations[1];
+ expect(@(testPresentOp.cancelId)).to(equal(101));
+ });
+
+ it(@"should reset the cancelID correctly once the max has been reached", ^{
+ testManager.nextCancelId = 200;
+ [testManager presentChoiceSet:testChoiceSet mode:SDLInteractionModeBoth withKeyboardDelegate:nil];
+
+ expect(testManager.transactionQueue.operations.count).to(equal(2));
+
+ expect(testManager.transactionQueue.operations[0]).to(beAKindOf([SDLPreloadChoicesOperation class]));
+ SDLPresentChoiceSetOperation *testPresentOp = (SDLPresentChoiceSetOperation *)testManager.transactionQueue.operations[1];
+ expect(@(testPresentOp.cancelId)).to(equal(200));
+
+ [testManager presentChoiceSet:testChoiceSet mode:SDLInteractionModeBoth withKeyboardDelegate:nil];
+
+ expect(testManager.transactionQueue.operations.count).to(equal(3));
+
+ SDLPresentChoiceSetOperation *testPresentOp2 = (SDLPresentChoiceSetOperation *)testManager.transactionQueue.operations[2];
+ expect(@(testPresentOp2.cancelId)).to(equal(101));
+ });
+ });
+
describe(@"dismissing the keyboard", ^{
__block SDLPresentKeyboardOperation *mockKeyboardOp1 = nil;
__block SDLPresentKeyboardOperation *mockKeyboardOp2 = nil;
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
index 8d2cf9dbc..4d7f71d93 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLLifecycleManagerSpec.m
@@ -43,10 +43,10 @@
#import "SDLTTSChunk.h"
#import "SDLUnregisterAppInterface.h"
#import "SDLUnregisterAppInterfaceResponse.h"
+#import "SDLVehicleType.h"
#import "SDLVersion.h"
#import "SDLVideoStreamingState.h"
-
@interface SDLStreamingMediaManager ()
@property (strong, nonatomic, nullable) SDLSecondaryTransportManager *secondaryTransportManager;
@@ -91,7 +91,7 @@ QuickSpecBegin(SDLLifecycleManagerSpec)
describe(@"a lifecycle manager", ^{
__block SDLLifecycleManager *testManager = nil;
__block SDLConfiguration *testConfig = nil;
- __block id protocolMock = nil;
+ __block SDLProtocol *protocolMock = nil;
__block id sdlManagerDelegateProtocolMock = nil;
__block id lockScreenManagerMock = nil;
__block id fileManagerMock = nil;
@@ -100,6 +100,9 @@ describe(@"a lifecycle manager", ^{
__block id systemCapabilityMock = nil;
__block id secondaryTransportManagerMock = nil;
__block id encryptionManagerMock = nil;
+ SDLVehicleType *vehicleType = [[SDLVehicleType alloc] initWithMake:@"Make" model:@"Model" modelYear:@"Model Year" trim:@"Trim"];
+ NSString *softwareVersion = @"1.1.1.1";
+ NSString *hardwareVersion = @"2.2.2.2";
void (^transitionToState)(SDLState *) = ^(SDLState *state) {
dispatch_sync(testManager.lifecycleQueue, ^{
@@ -253,11 +256,35 @@ describe(@"a lifecycle manager", ^{
beforeEach(^{
// When we connect, we should be creating an sending an RAI
OCMExpect([protocolMock sendRPC:[OCMArg isKindOfClass:[SDLRegisterAppInterface class]]]);
-
- [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
+ });
+
+ context(@"when the protocol system info is set", ^{
+ SDLSystemInfo *testSystemInfo = [[SDLSystemInfo alloc] initWithVehicleType:vehicleType softwareVersion:softwareVersion hardwareVersion:hardwareVersion];
+
+ beforeEach(^{
+ OCMStub(protocolMock.systemInfo).andReturn(testSystemInfo);
+ OCMExpect([sdlManagerDelegateProtocolMock didReceiveSystemInfo:[OCMArg isEqual:testSystemInfo]]).andReturn(YES);
+ [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
+ });
+
+ it(@"should call the delegate handler", ^{
+ OCMVerifyAllWithDelay(sdlManagerDelegateProtocolMock, 1.0);
+ });
+ });
+
+ context(@"when the protocol system info is not set", ^{
+ beforeEach(^{
+ OCMStub(protocolMock.systemInfo).andReturn(nil);
+ [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
+ });
+
+ it(@"should call the delegate handler", ^{
+ OCMReject([sdlManagerDelegateProtocolMock didReceiveSystemInfo:[OCMArg isNil]]);
+ });
});
it(@"should send a register app interface request and be in the connected state", ^{
+ [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
OCMVerifyAllWithDelay(protocolMock, 1.0);
expect(testManager.lifecycleState).toEventually(equal(SDLLifecycleStateConnected));
});
@@ -266,6 +293,7 @@ describe(@"a lifecycle manager", ^{
describe(@"after receiving a disconnect notification", ^{
beforeEach(^{
+ [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
[testManager.notificationDispatcher postNotificationName:SDLTransportDidDisconnect infoObject:nil];
[NSThread sleepForTimeInterval:0.1];
});
@@ -277,6 +305,7 @@ describe(@"a lifecycle manager", ^{
describe(@"stopping the manager", ^{
it(@"should simply stop", ^{
+ [testManager.notificationDispatcher postNotificationName:SDLRPCServiceDidConnect infoObject:nil];
[testManager stop];
expect(testManager.lifecycleState).toEventually(equal(SDLLifecycleStateStopped));
@@ -324,6 +353,138 @@ describe(@"a lifecycle manager", ^{
itBehavesLike(@"unable to send an RPC", ^{ return @{ @"manager": testManager }; });
});
+
+ context(@"when the protocol system info is not set", ^{
+ beforeEach(^{
+ testManager.systemInfo = nil;
+ OCMExpect([sdlManagerDelegateProtocolMock didReceiveSystemInfo:[OCMArg isNotNil]]).andReturn(YES);
+ });
+
+ it(@"should call the delegate handler", ^{
+ SDLRegisterAppInterfaceResponse *response = [[SDLRegisterAppInterfaceResponse alloc] init];
+ response.resultCode = SDLResultSuccess;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+ response.vehicleType = vehicleType;
+ response.systemSoftwareVersion = softwareVersion;
+#pragma clang diagnostic pop
+ testManager.registerResponse = response;
+ [testManager.lifecycleStateMachine setToState:SDLLifecycleStateRegistered fromOldState:nil callEnterTransition:YES];
+
+ OCMVerifyAllWithDelay(sdlManagerDelegateProtocolMock, 1.0);
+ });
+ });
+
+ context(@"when the protocol system info is set", ^{
+ SDLSystemInfo *testSystemInfo = [[SDLSystemInfo alloc] initWithVehicleType:vehicleType softwareVersion:softwareVersion hardwareVersion:hardwareVersion];
+
+ beforeEach(^{
+ testManager.systemInfo = testSystemInfo;
+ });
+
+ it(@"should call not the delegate handler", ^{
+ SDLRegisterAppInterfaceResponse *response = [[SDLRegisterAppInterfaceResponse alloc] init];
+ response.resultCode = SDLResultSuccess;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+ response.vehicleType = vehicleType;
+ response.systemSoftwareVersion = softwareVersion;
+#pragma clang diagnostic pop
+ [testManager.lifecycleStateMachine setToState:SDLLifecycleStateRegistered fromOldState:nil callEnterTransition:YES];
+
+ OCMReject([sdlManagerDelegateProtocolMock didReceiveSystemInfo:[OCMArg isNotNil]]);
+ });
+ });
+
+ context(@"when the register response returns different language than the one passed with the lifecycle configuration", ^{
+ it(@"should should update the configuration when the app supports the head unit language", ^{
+ SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
+ registerAppInterfaceResponse.success = @YES;
+ registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
+ registerAppInterfaceResponse.info = @"Language mismatch";
+ registerAppInterfaceResponse.language = SDLLanguageEnGb;
+ registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageEnGb;
+ testManager.registerResponse = registerAppInterfaceResponse;
+
+ SDLLifecycleConfigurationUpdate *update = [[SDLLifecycleConfigurationUpdate alloc] initWithAppName:@"EnGb" shortAppName:@"E" ttsName:[SDLTTSChunk textChunksFromString:@"EnGb ttsName"] voiceRecognitionCommandNames:@[@"EnGb", @"Gb"]];
+ OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any] hmiLanguage:[OCMArg any]]).andReturn(update);
+
+ OCMExpect([protocolMock sendRPC:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLChangeRegistration *changeRegistration = (SDLChangeRegistration *)value;
+ expect(changeRegistration.appName).to(equal(update.appName));
+ expect(changeRegistration.ngnMediaScreenAppName).to(equal(update.shortAppName));
+ expect(changeRegistration.ttsName).to(equal(update.ttsName));
+ expect(changeRegistration.vrSynonyms).to(equal(@[@"EnGb", @"Gb"]));
+ return [value isKindOfClass:[SDLChangeRegistration class]];
+ }]]);
+
+ setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
+
+ OCMVerifyAllWithDelay(protocolMock, 0.5);
+
+ expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnGb));
+ expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnGb));
+ expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"EnGb"));
+ expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"E"));
+ expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(equal([SDLTTSChunk textChunksFromString:@"EnGb ttsName"]));
+ });
+
+ it(@"should not update the configuration when the app does not support the head unit language or display language", ^{
+ SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
+ registerAppInterfaceResponse.success = @YES;
+ registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
+ registerAppInterfaceResponse.info = @"Language mismatch";
+ registerAppInterfaceResponse.language = SDLLanguageDeDe;
+ registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageDeDe;
+ testManager.registerResponse = registerAppInterfaceResponse;
+
+ OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any] hmiLanguage:[OCMArg any]]).andReturn(nil);
+
+ setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
+
+ OCMVerifyAllWithDelay(protocolMock, 0.5);
+
+ expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnUs));
+ expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnUs));
+ expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"Test App"));
+ expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"Short Name"));
+ expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(beNil());
+ });
+
+ it(@"should update when the app supports the head unit display language", ^{
+ SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
+ registerAppInterfaceResponse.success = @YES;
+ registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
+ registerAppInterfaceResponse.info = @"Language mismatch";
+ registerAppInterfaceResponse.language = SDLLanguageEnUs;
+ registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageEnGb;
+ testManager.registerResponse = registerAppInterfaceResponse;
+
+ SDLLifecycleConfigurationUpdate *update = [[SDLLifecycleConfigurationUpdate alloc] initWithAppName:@"EnGb" shortAppName:@"Gb" ttsName:nil voiceRecognitionCommandNames:nil];
+ OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:registerAppInterfaceResponse.language hmiLanguage:registerAppInterfaceResponse.hmiDisplayLanguage]).andReturn(update);
+
+ setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
+
+ OCMExpect([protocolMock sendRPC:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLChangeRegistration *changeRegistration = (SDLChangeRegistration *)value;
+ expect(changeRegistration.appName).to(equal(update.appName));
+ expect(changeRegistration.ngnMediaScreenAppName).to(equal(update.shortAppName));
+ expect(changeRegistration.ttsName).to(beNil());
+ expect(changeRegistration.vrSynonyms).to(beNil());
+ return [value isKindOfClass:[SDLChangeRegistration class]];
+ }]]);
+
+ setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
+
+ OCMVerifyAllWithDelay(protocolMock, 0.5);
+
+ expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnGb));
+ expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnUs));
+ expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"EnGb"));
+ expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"Gb"));
+ expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(beNil());
+ });
+ });
describe(@"after receiving a disconnect notification", ^{
beforeEach(^{
@@ -361,7 +522,7 @@ describe(@"a lifecycle manager", ^{
});
});
- describe(@"transitioning to the Setting Up HMI state", ^{
+ describe(@"transitioning from setting app icon state to the Setting Up HMI state", ^{
context(@"before register response is a success", ^{
it(@"ready handler should not be called yet", ^{
SDLRegisterAppInterfaceResponse *response = [[SDLRegisterAppInterfaceResponse alloc] init];
@@ -399,7 +560,7 @@ describe(@"a lifecycle manager", ^{
});
});
- describe(@"transitioning to the ready state", ^{
+ describe(@"transitioning from the registered state to the ready state", ^{
beforeEach(^{
[testManager.lifecycleStateMachine setToState:SDLLifecycleStateRegistered fromOldState:nil callEnterTransition:NO];
});
@@ -432,96 +593,6 @@ describe(@"a lifecycle manager", ^{
expect(readyHandlerError.userInfo[NSLocalizedFailureReasonErrorKey]).toEventually(match(response.info));
});
});
-
- context(@"when the register response returns different language than the one passed with the lifecycle configuration", ^{
- it(@"should should update the configuration when the app supports the head unit language", ^{
- SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
- registerAppInterfaceResponse.success = @YES;
- registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
- registerAppInterfaceResponse.info = @"Language mismatch";
- registerAppInterfaceResponse.language = SDLLanguageEnGb;
- registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageEnGb;
- testManager.registerResponse = registerAppInterfaceResponse;
-
- SDLLifecycleConfigurationUpdate *update = [[SDLLifecycleConfigurationUpdate alloc] initWithAppName:@"EnGb" shortAppName:@"E" ttsName:[SDLTTSChunk textChunksFromString:@"EnGb ttsName"] voiceRecognitionCommandNames:@[@"EnGb", @"Gb"]];
- OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any] hmiLanguage:[OCMArg any]]).andReturn(update);
-
- OCMExpect([protocolMock sendRPC:[OCMArg checkWithBlock:^BOOL(id value) {
- SDLChangeRegistration *changeRegistration = (SDLChangeRegistration *)value;
- expect(changeRegistration.appName).to(equal(update.appName));
- expect(changeRegistration.ngnMediaScreenAppName).to(equal(update.shortAppName));
- expect(changeRegistration.ttsName).to(equal(update.ttsName));
- expect(changeRegistration.vrSynonyms).to(equal(@[@"EnGb", @"Gb"]));
- return [value isKindOfClass:[SDLChangeRegistration class]];
- }]]);
-
- setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
-
- OCMVerifyAllWithDelay(protocolMock, 0.5);
-
- expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnGb));
- expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnGb));
- expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"EnGb"));
- expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"E"));
- expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(equal([SDLTTSChunk textChunksFromString:@"EnGb ttsName"]));
- });
-
- it(@"should not update the configuration when the app does not support the head unit language or display language", ^{
- SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
- registerAppInterfaceResponse.success = @YES;
- registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
- registerAppInterfaceResponse.info = @"Language mismatch";
- registerAppInterfaceResponse.language = SDLLanguageDeDe;
- registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageDeDe;
- testManager.registerResponse = registerAppInterfaceResponse;
-
- OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:[OCMArg any] hmiLanguage:[OCMArg any]]).andReturn(nil);
-
- setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
-
- OCMVerifyAllWithDelay(protocolMock, 0.5);
-
- expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnUs));
- expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnUs));
- expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"Test App"));
- expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"Short Name"));
- expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(beNil());
- });
-
- it(@"should update when the app supports the head unit display language", ^{
- SDLRegisterAppInterfaceResponse *registerAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
- registerAppInterfaceResponse.success = @YES;
- registerAppInterfaceResponse.resultCode = SDLResultWrongLanguage;
- registerAppInterfaceResponse.info = @"Language mismatch";
- registerAppInterfaceResponse.language = SDLLanguageEnUs;
- registerAppInterfaceResponse.hmiDisplayLanguage = SDLLanguageEnGb;
- testManager.registerResponse = registerAppInterfaceResponse;
-
- SDLLifecycleConfigurationUpdate *update = [[SDLLifecycleConfigurationUpdate alloc] initWithAppName:@"EnGb" shortAppName:@"Gb" ttsName:nil voiceRecognitionCommandNames:nil];
- OCMStub([testManager.delegate managerShouldUpdateLifecycleToLanguage:registerAppInterfaceResponse.language hmiLanguage:registerAppInterfaceResponse.hmiDisplayLanguage]).andReturn(update);
-
- transitionToState(SDLLifecycleStateUpdatingConfiguration);
-
- OCMExpect([protocolMock sendRPC:[OCMArg checkWithBlock:^BOOL(id value) {
- SDLChangeRegistration *changeRegistration = (SDLChangeRegistration *)value;
- expect(changeRegistration.appName).to(equal(update.appName));
- expect(changeRegistration.ngnMediaScreenAppName).to(equal(update.shortAppName));
- expect(changeRegistration.ttsName).to(beNil());
- expect(changeRegistration.vrSynonyms).to(beNil());
- return [value isKindOfClass:[SDLChangeRegistration class]];
- }]]);
-
- setToStateWithEnterTransition(SDLLifecycleStateRegistered, SDLLifecycleStateUpdatingConfiguration);
-
- OCMVerifyAllWithDelay(protocolMock, 0.5);
-
- expect(testManager.configuration.lifecycleConfig.language).toEventually(equal(SDLLanguageEnGb));
- expect(testManager.currentVRLanguage).toEventually(equal(SDLLanguageEnUs));
- expect(testManager.configuration.lifecycleConfig.appName).toEventually(equal(@"EnGb"));
- expect(testManager.configuration.lifecycleConfig.shortAppName).toEventually(equal(@"Gb"));
- expect(testManager.configuration.lifecycleConfig.ttsName).toEventually(beNil());
- });
- });
});
describe(@"in the ready state", ^{
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
index e4749b944..fd4349887 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m
@@ -31,7 +31,7 @@ describe(@"a menu cell", ^{
beforeEach(^{
someVoiceCommands = @[@"some command"];
- SDLMenuCell *subcell = [[SDLMenuCell alloc] initWithTitle:@"Hello" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ SDLMenuCell *subcell = [[SDLMenuCell alloc] initWithTitle:@"Hello" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
someSubcells = @[subcell];
});
@@ -67,7 +67,7 @@ describe(@"a menu cell", ^{
});
it(@"should set initWithTitle:icon:voiceCommands:secondaryText:tertiaryText:secondaryArtwork:handler: properly", ^{
- testCell = [[SDLMenuCell alloc] initWithTitle:someTitle icon:someArtwork voiceCommands:someVoiceCommands secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle secondaryArtwork:someSecondaryArtwork handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ testCell = [[SDLMenuCell alloc] initWithTitle:someTitle secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle icon:someArtwork secondaryArtwork:someSecondaryArtwork voiceCommands:someVoiceCommands handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
expect(testCell.title).to(equal(someTitle));
expect(testCell.icon).to(equal(someArtwork));
@@ -79,7 +79,7 @@ describe(@"a menu cell", ^{
});
it(@"should initWithTitle:icon:submenuLayout:subCells:secondaryText:tertiaryText:secondaryArtwork: initialize", ^{
- testCell = [[SDLMenuCell alloc] initWithTitle:someTitle icon:someArtwork submenuLayout:testLayout subCells:someSubcells secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle secondaryArtwork:someSecondaryArtwork];
+ testCell = [[SDLMenuCell alloc] initWithTitle:someTitle secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle icon:someArtwork secondaryArtwork:someSecondaryArtwork submenuLayout:testLayout subCells:someSubcells];
expect(testCell.title).to(equal(someTitle));
expect(testCell.icon).to(equal(someArtwork));
@@ -95,15 +95,15 @@ describe(@"a menu cell", ^{
describe(@"check cell eqality", ^{
it(@"should compare cells and return true if cells equal", ^{
- testCell = [[SDLMenuCell alloc] initWithTitle:someTitle icon:nil submenuLayout:testLayout subCells:@[] secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle secondaryArtwork:someSecondaryArtwork];
- testCell2 = [[SDLMenuCell alloc] initWithTitle:someTitle icon:nil submenuLayout:testLayout subCells:@[] secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle secondaryArtwork:someSecondaryArtwork];
+ testCell = [[SDLMenuCell alloc] initWithTitle:someTitle secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle icon:nil secondaryArtwork:someSecondaryArtwork submenuLayout:testLayout subCells:@[]];
+ testCell2 = [[SDLMenuCell alloc] initWithTitle:someTitle secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle icon:nil secondaryArtwork:someSecondaryArtwork submenuLayout:testLayout subCells:@[]];
expect([testCell isEqual:testCell2]).to(equal(true));
});
it(@"should compare cells and return false if not equal ", ^{
- testCell = [[SDLMenuCell alloc] initWithTitle:@"True" icon:nil submenuLayout:testLayout subCells:@[] secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle secondaryArtwork:someSecondaryArtwork];
- testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" icon:nil submenuLayout:testLayout subCells:@[] secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ testCell = [[SDLMenuCell alloc] initWithTitle:@"True" secondaryText:someSecondaryTitle tertiaryText:someTertiaryTitle icon:nil secondaryArtwork:someSecondaryArtwork submenuLayout:testLayout subCells:@[]];
+ testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil submenuLayout:testLayout subCells:@[]];
expect([testCell isEqual:testCell2]).to(equal(false));
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
index 3065533a3..bee4ec136 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m
@@ -24,18 +24,18 @@
@property (copy, nonatomic, nullable) SDLHMILevel currentHMILevel;
@property (copy, nonatomic, nullable) SDLSystemContext currentSystemContext;
-
+@property (strong, nonatomic, nullable) SDLWindowCapability *windowCapability;
@property (strong, nonatomic, nullable) NSArray<SDLRPCRequest *> *inProgressUpdate;
@property (assign, nonatomic) BOOL hasQueuedUpdate;
@property (assign, nonatomic) BOOL waitingOnHMIUpdate;
@property (copy, nonatomic) NSArray<SDLMenuCell *> *waitingUpdateMenuCells;
-@property (strong, nonatomic, nullable) SDLWindowCapability *windowCapability;
@property (assign, nonatomic) UInt32 lastMenuId;
@property (copy, nonatomic) NSArray<SDLMenuCell *> *oldMenuCells;
- (BOOL)sdl_shouldRPCsIncludeImages:(NSArray<SDLMenuCell *> *)cells;
+- (void)sdl_displayCapabilityDidUpdate;
@end
@@ -173,6 +173,22 @@ describe(@"menu manager", ^{
});
});
+ describe(@"display capability updates", ^{
+ beforeEach(^{
+ testManager.currentHMILevel = SDLHMILevelFull;
+ testManager.currentSystemContext = SDLSystemContextMain;
+ });
+
+ it(@"should save the new window capability", ^{
+ SDLWindowCapability *testWindowCapability = [[SDLWindowCapability alloc] init];
+ testWindowCapability.textFields = @[[[SDLTextField alloc] initWithName:SDLTextFieldNameMenuName characterSet:SDLCharacterSetUtf8 width:500 rows:1]];
+ OCMStub([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+
+ expect(testManager.windowCapability).to(equal(testWindowCapability));
+ });
+ });
+
describe(@"updating menu cells", ^{
beforeEach(^{
testManager.currentHMILevel = SDLHMILevelFull;
@@ -241,8 +257,8 @@ describe(@"menu manager", ^{
});
context(@"duplicate VR commands", ^{
- __block SDLMenuCell *textAndVRCell1 = [[SDLMenuCell alloc] initWithTitle:@"Test 1" icon:nil voiceCommands:@[@"Cat", @"Turtle"] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- __block SDLMenuCell *textAndVRCell2 = [[SDLMenuCell alloc] initWithTitle:@"Test 3" icon:nil voiceCommands:@[@"Cat", @"Dog"] secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ __block SDLMenuCell *textAndVRCell1 = [[SDLMenuCell alloc] initWithTitle:@"Test 1" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[@"Cat", @"Turtle"] handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ __block SDLMenuCell *textAndVRCell2 = [[SDLMenuCell alloc] initWithTitle:@"Test 3" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[@"Cat", @"Dog"] handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
it(@"should fail when menu items have duplicate vr commands", ^{
testManager.menuCells = @[textAndVRCell1, textAndVRCell2];
@@ -263,14 +279,14 @@ describe(@"menu manager", ^{
});
it(@"should check if all artworks are uploaded and return NO", ^{
- textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:testArtwork handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:testArtwork voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
testManager.menuCells = @[textAndImageCell, textOnlyCell];
OCMVerify([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]);
expect([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]).to(beFalse());
});
it(@"should check if all artworks are uploaded and return NO", ^{
- textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork3 voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" secondaryText:nil tertiaryText:nil icon:testArtwork3 secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
testManager.menuCells = @[textAndImageCell, textOnlyCell];
OCMVerify([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]);
expect([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]).to(beFalse());
@@ -310,7 +326,7 @@ describe(@"menu manager", ^{
});
it(@"should check if all artworks are uploaded", ^{
- textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork3 voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" secondaryText:nil tertiaryText:nil icon:testArtwork3 secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
testManager.menuCells = @[textAndImageCell, textOnlyCell];
OCMVerify([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]);
expect([testManager sdl_shouldRPCsIncludeImages:testManager.menuCells]).to(beTrue());
@@ -336,7 +352,7 @@ describe(@"menu manager", ^{
it(@"should properly overwrite an image cell", ^{
OCMStub([mockFileManager fileNeedsUpload:[OCMArg isNotNil]]).andReturn(YES);
- textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork3 voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" secondaryText:nil tertiaryText:nil icon:testArtwork3 secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
testManager.menuCells = @[textAndImageCell, submenuImageCell];
OCMVerify([mockFileManager uploadArtworks:[OCMArg any] completionHandler:[OCMArg any]]);
});
@@ -622,7 +638,7 @@ describe(@"menu manager", ^{
context(@"on a main menu cell", ^{
beforeEach(^{
- cellWithHandler = [[SDLMenuCell alloc] initWithTitle:@"Hello" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ cellWithHandler = [[SDLMenuCell alloc] initWithTitle:@"Hello" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
cellCalled = YES;
testTriggerSource = triggerSource;
}];
@@ -645,12 +661,12 @@ describe(@"menu manager", ^{
context(@"on a submenu menu cell", ^{
beforeEach(^{
- cellWithHandler = [[SDLMenuCell alloc] initWithTitle:@"Hello" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
+ cellWithHandler = [[SDLMenuCell alloc] initWithTitle:@"Hello" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
cellCalled = YES;
testTriggerSource = triggerSource;
}];
- SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" icon:nil submenuLayout:SDLMenuLayoutTiles subCells:@[cellWithHandler] secondaryText:nil tertiaryText:nil secondaryArtwork:nil];
+ SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil submenuLayout:SDLMenuLayoutTiles subCells:@[cellWithHandler]];
testManager.menuCells = @[submenuCell];
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
index 883720b82..f918c6909 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentChoiceSetOperationSpec.m
@@ -46,6 +46,7 @@ describe(@"present choice operation", ^{
__block BOOL hasCalledOperationCompletionHandler = NO;
__block NSError *resultError = nil;
+ __block SDLWindowCapability *windowCapability = nil;
beforeEach(^{
resultError = nil;
@@ -58,9 +59,10 @@ describe(@"present choice operation", ^{
testChoices = @[cell1];
testChoiceSet = [[SDLChoiceSet alloc] initWithTitle:@"Test Title" delegate:testChoiceDelegate layout:SDLChoiceSetLayoutTiles timeout:13 initialPromptString:@"Test initial prompt" timeoutPromptString:@"Test timeout prompt" helpPromptString:@"Test help prompt" vrHelpList:nil choices:testChoices];
+ windowCapability = [[SDLWindowCapability alloc] init];
testKeyboardDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate));
OCMStub([testKeyboardDelegate customKeyboardConfiguration]).andReturn(nil);
- testKeyboardProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil];
+ testKeyboardProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil];
});
it(@"should have a priority of 'normal'", ^{
@@ -71,7 +73,7 @@ describe(@"present choice operation", ^{
describe(@"running a non-searchable choice set operation", ^{
beforeEach(^{
- testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID];
+ testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID windowCapability:windowCapability];
testOp.completionBlock = ^{
hasCalledOperationCompletionHandler = YES;
};
@@ -125,7 +127,7 @@ describe(@"present choice operation", ^{
__block SDLPresentChoiceSetOperation *testCancelOp = nil;
beforeEach(^{
- testCancelOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID];
+ testCancelOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:nil keyboardDelegate:nil cancelID:testCancelID windowCapability:windowCapability];
testCancelOp.completionBlock = ^{
hasCalledOperationCompletionHandler = YES;
};
@@ -313,7 +315,7 @@ describe(@"present choice operation", ^{
describe(@"running a searchable choice set operation", ^{
beforeEach(^{
- testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:testKeyboardProperties keyboardDelegate:testKeyboardDelegate cancelID:testCancelID];
+ testOp = [[SDLPresentChoiceSetOperation alloc] initWithConnectionManager:testConnectionManager choiceSet:testChoiceSet mode:testInteractionMode keyboardProperties:testKeyboardProperties keyboardDelegate:testKeyboardDelegate cancelID:testCancelID windowCapability:windowCapability];
testOp.completionBlock = ^{
hasCalledOperationCompletionHandler = YES;
@@ -414,6 +416,25 @@ describe(@"present choice operation", ^{
}]]);
});
+ it(@"should respond to enabled keyboard event", ^{
+ SDLRPCNotificationNotification *notification = nil;
+
+ // Submit notification
+ SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init];
+ input.event = SDLKeyboardEventInputKeyMaskEnabled;
+ notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input];
+
+ [[NSNotificationCenter defaultCenter] postNotification:notification];
+
+ OCMVerify([testKeyboardDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) {
+ return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ }] text:[OCMArg isNil]]);
+
+ OCMVerify([testKeyboardDelegate keyboardDidUpdateInputMask:[OCMArg checkWithBlock:^BOOL(id obj) {
+ return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ }]]);
+ });
+
it(@"should respond to cancellation notifications", ^{
SDLRPCNotificationNotification *notification = nil;
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
index 29ed6d0b0..389e0367d 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLPresentKeyboardOperationSpec.m
@@ -33,6 +33,7 @@ describe(@"present keyboard operation", ^{
__block BOOL hasCalledOperationCompletionHandler = NO;
__block NSError *resultError = nil;
+ __block SDLWindowCapability *windowCapability = nil;
beforeEach(^{
testOp = nil;
@@ -43,7 +44,17 @@ describe(@"present keyboard operation", ^{
testDelegate = OCMProtocolMock(@protocol(SDLKeyboardDelegate));
OCMStub([testDelegate customKeyboardConfiguration]).andReturn(nil);
- testInitialProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil];
+ windowCapability = [[SDLWindowCapability alloc] init];
+ testInitialProperties = [[SDLKeyboardProperties alloc] initWithLanguage:SDLLanguageArSa keyboardLayout:SDLKeyboardLayoutAZERTY keypressMode:SDLKeypressModeResendCurrentEntry limitedCharacterList:nil autoCompleteList:nil maskInputCharacters:nil customKeys:nil];
+ });
+
+ afterEach(^{
+ if (testOp) {
+ // rationale: every test run creates a new operation to test, the old operation from a previous test
+ // stays 'undead' undefined time and can receive notifications causing a test fail at random
+ [[NSNotificationCenter defaultCenter] removeObserver:testOp];
+ testOp = nil;
+ }
});
it(@"should have a priority of 'normal'", ^{
@@ -54,7 +65,7 @@ describe(@"present keyboard operation", ^{
describe(@"running the operation", ^{
beforeEach(^{
- testOp = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:testConnectionManager keyboardProperties:testInitialProperties initialText:testInitialText keyboardDelegate:testDelegate cancelID:testCancelID];
+ testOp = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:testConnectionManager keyboardProperties:testInitialProperties initialText:testInitialText keyboardDelegate:testDelegate cancelID:testCancelID windowCapability:windowCapability];
testOp.completionBlock = ^{
hasCalledOperationCompletionHandler = YES;
};
@@ -148,6 +159,25 @@ describe(@"present keyboard operation", ^{
}]]);
});
+ it(@"should respond to enabled keyboard event", ^{
+ SDLRPCNotificationNotification *notification = nil;
+
+ // Submit notification
+ SDLOnKeyboardInput *input = [[SDLOnKeyboardInput alloc] init];
+ input.event = SDLKeyboardEventInputKeyMaskEnabled;
+ notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveKeyboardInputNotification object:nil rpcNotification:input];
+
+ [[NSNotificationCenter defaultCenter] postNotification:notification];
+
+ OCMVerify([testDelegate keyboardDidSendEvent:[OCMArg checkWithBlock:^BOOL(id obj) {
+ return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ }] text:[OCMArg isNil]]);
+
+ OCMVerify([testDelegate keyboardDidUpdateInputMask:[OCMArg checkWithBlock:^BOOL(id obj) {
+ return [(SDLKeyboardEvent)obj isEqualToEnum:SDLKeyboardEventInputKeyMaskEnabled];
+ }]]);
+ });
+
it(@"should respond to cancellation notifications", ^{
SDLRPCNotificationNotification *notification = nil;
@@ -260,7 +290,7 @@ describe(@"present keyboard operation", ^{
describe(@"Canceling the keyboard", ^{
beforeEach(^{
- testOp = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:testConnectionManager keyboardProperties:testInitialProperties initialText:testInitialText keyboardDelegate:testDelegate cancelID:testCancelID];
+ testOp = [[SDLPresentKeyboardOperation alloc] initWithConnectionManager:testConnectionManager keyboardProperties:testInitialProperties initialText:testInitialText keyboardDelegate:testDelegate cancelID:testCancelID windowCapability:windowCapability];
testOp.completionBlock = ^{
hasCalledOperationCompletionHandler = YES;
};
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
index a24c432a7..8ddfd6aec 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLSoftButtonManagerSpec.m
@@ -46,7 +46,7 @@
@property (strong, nonatomic) NSMutableArray<SDLAsynchronousOperation *> *batchQueue;
- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification;
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability;
+- (void)sdl_displayCapabilityDidUpdate;
@end
@@ -76,6 +76,8 @@ describe(@"a soft button manager", ^{
__block SDLArtwork *object2State1Art = [[SDLArtwork alloc] initWithData:[@"TestData" dataUsingEncoding:NSUTF8StringEncoding] name:object2State1ArtworkName fileExtension:@"png" persistent:YES];
__block SDLSoftButtonState *object2State1 = [[SDLSoftButtonState alloc] initWithStateName:object2State1Name text:object2State1Text artwork:object2State1Art];
+ __block SDLWindowCapability *testWindowCapability = nil;
+
beforeEach(^{
testFileManager = OCMClassMock([SDLFileManager class]);
testSystemCapabilityManager = OCMClassMock([SDLSystemCapabilityManager class]);
@@ -84,71 +86,102 @@ describe(@"a soft button manager", ^{
testManager = [[SDLSoftButtonManager alloc] initWithConnectionManager:testConnectionManager fileManager:testFileManager systemCapabilityManager:testSystemCapabilityManager];
[testManager start];
- 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]]];
+ testWindowCapability = [[SDLWindowCapability alloc] init];
+ testWindowCapability.softButtonCapabilities = @[softButtonCapabilities];
});
it(@"should instantiate correctly", ^{
expect(testManager.connectionManager).to(equal(testConnectionManager));
expect(testManager.fileManager).to(equal(testFileManager));
-
expect(testManager.softButtonObjects).to(beEmpty());
expect(testManager.currentMainField1).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());
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ expect(testManager.softButtonCapabilities).to(beNil());
+ expect(testManager.currentLevel).to(beNil());
});
- context(@"when in HMI NONE", ^{
+ describe(@"the SDL app has not been opened", ^{
beforeEach(^{
- 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];
-
testManager.softButtonObjects = @[testObject1, testObject2];
});
- it(@"should set the soft buttons, but not update", ^{
- expect(testManager.softButtonObjects).toNot(beEmpty());
- expect(testManager.transactionQueue.suspended).to(beTrue());
+ context(@"when the HMI level notification has not been received", ^{
+ it(@"should set the soft buttons, but not update", ^{
+ expect(testManager.currentLevel).to(beNil());
+ expect(testManager.softButtonObjects).toNot(beEmpty());
+ expect(testManager.transactionQueue.suspended).to(beTrue());
+ });
+ });
+
+ context(@"when the HMI level is NONE", ^{
+ beforeEach(^{
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelNone;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+ });
+
+ it(@"should set the soft buttons, but not update", ^{
+ expect(testManager.currentLevel).to(equal(SDLHMILevelNone));
+ expect(testManager.softButtonObjects).toNot(beEmpty());
+ expect(testManager.transactionQueue.suspended).to(beTrue());
+ });
});
});
- context(@"when there are no soft button capabilities", ^{
+ describe(@"the SDL app has been opened", ^{
beforeEach(^{
- SDLWindowCapability *windowCapability = [[SDLWindowCapability alloc] init];
- SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"TEST" windowCapabilities:@[windowCapability] windowTypeSupported:nil];
- [testManager sdl_displayCapabilityDidUpdate:[[SDLSystemCapability alloc] initWithDisplayCapabilities:@[displayCapability]]];
+ 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];
+
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
});
- it(@"should set the buttons but have the queue suspended", ^{
- expect(testManager.softButtonObjects).toNot(beNil());
- expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ context(@"when the soft button capabilities notification has not been received", ^{
+ beforeEach(^{
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(nil);
+ [testManager sdl_displayCapabilityDidUpdate];
+ });
+
+ it(@"should set the buttons but have the queue suspended", ^{
+ expect(testManager.softButtonObjects).toNot(beNil());
+ expect(testManager.transactionQueue.isSuspended).to(beTrue());
+ });
+ });
+
+ context(@"when the soft button capabilities notification has been received", ^{
+ beforeEach(^{
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+ });
+
+ it(@"should set the buttons and unsuspend the queue", ^{
+ expect(testManager.softButtonObjects).toNot(beNil());
+ expect(testManager.transactionQueue.isSuspended).to(beFalse());
+ });
});
});
- context(@"when button objects have the same name", ^{
+ describe(@"invalid button objects (button objects have same names)", ^{
beforeEach(^{
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+
NSString *sameName = @"Same name";
testObject1 = [[SDLSoftButtonObject alloc] initWithName:sameName states:@[object1State1, object1State2] initialStateName:object1State1Name handler:nil];
testObject2 = [[SDLSoftButtonObject alloc] initWithName:sameName state:object2State1 handler:nil];
@@ -162,8 +195,15 @@ describe(@"a soft button manager", ^{
});
});
- context(@"when button objects have different names", ^{
+ describe(@"valid button objects (button objects have different names)", ^{
beforeEach(^{
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+
testObject1 = [[SDLSoftButtonObject alloc] initWithName:object1Name states:@[object1State1, object1State2] initialStateName:object1State1Name handler:nil];
testObject2 = [[SDLSoftButtonObject alloc] initWithName:object2Name state:object2State1 handler:nil];
@@ -228,6 +268,13 @@ describe(@"a soft button manager", ^{
describe(@"transitioning soft button states", ^{
beforeEach(^{
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+
testObject1 = [[SDLSoftButtonObject alloc] initWithName:object1Name states:@[object1State1, object1State2] initialStateName:object1State1Name handler:nil];
testObject2 = [[SDLSoftButtonObject alloc] initWithName:object2Name state:object2State1 handler:nil];
@@ -266,6 +313,17 @@ describe(@"a soft button manager", ^{
context(@"On disconnects", ^{
beforeEach(^{
+ SDLOnHMIStatus *status = [[SDLOnHMIStatus alloc] init];
+ status.hmiLevel = SDLHMILevelFull;
+ [testManager sdl_hmiStatusNotification:[[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:status]];
+
+ OCMStub([testSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
+
+ 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];
+
[testManager stop];
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingAudioLifecycleManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingAudioLifecycleManagerSpec.m
index 4a39a0676..cca65997b 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingAudioLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingAudioLifecycleManagerSpec.m
@@ -27,7 +27,6 @@
@interface SDLStreamingAudioLifecycleManager()
@property (weak, nonatomic) SDLProtocol *protocol;
-@property (copy, nonatomic, nullable) NSString *connectedVehicleMake;
@property (nonatomic, strong, readwrite) SDLAudioStreamManager *audioTranscodingManager;
@end
@@ -98,32 +97,11 @@ describe(@"the streaming audio manager", ^{
expect(streamingLifecycleManager.currentAudioStreamState).to(match(SDLAudioStreamManagerStateStopped));
});
- describe(@"after receiving a register app interface response", ^{
- __block SDLRegisterAppInterfaceResponse *someRegisterAppInterfaceResponse = nil;
- __block SDLVehicleType *testVehicleType = nil;
-
- beforeEach(^{
- someRegisterAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
- testVehicleType = [[SDLVehicleType alloc] init];
- testVehicleType.make = @"TestVehicleType";
- someRegisterAppInterfaceResponse.vehicleType = testVehicleType;
-
- SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:someRegisterAppInterfaceResponse];
-
- [[NSNotificationCenter defaultCenter] postNotification:notification];
- });
-
- it(@"should should save the connected vehicle make", ^{
- expect(streamingLifecycleManager.connectedVehicleMake).toEventually(equal(testVehicleType.make));
- });
- });
-
describe(@"if the app state is active", ^{
__block id streamStub = nil;
beforeEach(^{
streamStub = OCMPartialMock(streamingLifecycleManager);
-
OCMStub([streamStub isStreamingSupported]).andReturn(YES);
[streamingLifecycleManager.appStateMachine setToState:SDLAppStateActive fromOldState:nil callEnterTransition:NO];
@@ -395,7 +373,6 @@ describe(@"the streaming audio manager", ^{
[streamingLifecycleManager endAudioServiceWithCompletionHandler:^ {
handlerCalled = YES;
}];
- streamingLifecycleManager.connectedVehicleMake = @"OEM_make_2";
});
context(@"when the manager is READY", ^{
@@ -409,7 +386,6 @@ describe(@"the streaming audio manager", ^{
expect(streamingLifecycleManager.protocol).to(beNil());
expect(streamingLifecycleManager.hmiLevel).to(equal(SDLHMILevelNone));
- expect(streamingLifecycleManager.connectedVehicleMake).to(beNil());
OCMVerify([mockAudioStreamManager stop]);
expect(handlerCalled).to(beTrue());
});
@@ -426,7 +402,6 @@ describe(@"the streaming audio manager", ^{
expect(streamingLifecycleManager.protocol).to(beNil());
expect(streamingLifecycleManager.hmiLevel).to(equal(SDLHMILevelNone));
- expect(streamingLifecycleManager.connectedVehicleMake).to(beNil());
OCMReject([mockAudioStreamManager stop]);
expect(handlerCalled).to(beFalse());
});
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingVideoLifecycleManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingVideoLifecycleManagerSpec.m
index 8543f4db0..4065b5077 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingVideoLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLStreamingVideoLifecycleManagerSpec.m
@@ -49,7 +49,6 @@
@property (weak, nonatomic) SDLProtocol *protocol;
@property (copy, nonatomic, readonly) NSString *appName;
@property (copy, nonatomic, readonly) NSString *videoStreamBackgroundString;
-@property (copy, nonatomic, nullable) NSString *connectedVehicleMake;
@end
@@ -65,6 +64,7 @@ describe(@"the streaming video manager", ^{
__block SDLLifecycleConfiguration *testLifecycleConfiguration = [SDLLifecycleConfiguration defaultConfigurationWithAppName:testAppName fullAppId:@""];
__block SDLSystemCapabilityManager *testSystemCapabilityManager = nil;
__block SDLConfiguration *testConfig = nil;
+ SDLSystemInfo *testSystemInfo = [[SDLSystemInfo alloc] initWithMake:@"Livio" model:@"Model" trim:@"Trim" modelYear:@"2021" softwareVersion:@"1.1.1.1" hardwareVersion:@"2.2.2.2"];
__block void (^sendNotificationForHMILevel)(SDLHMILevel hmiLevel, SDLVideoStreamingState streamState) = ^(SDLHMILevel hmiLevel, SDLVideoStreamingState streamState) {
SDLOnHMIStatus *hmiStatus = [[SDLOnHMIStatus alloc] init];
@@ -81,6 +81,7 @@ describe(@"the streaming video manager", ^{
testConfiguration.dataSource = testDataSource;
testConfiguration.rootViewController = testViewController;
testConnectionManager = [[TestConnectionManager alloc] init];
+ testConnectionManager.systemInfo = testSystemInfo;
testLifecycleConfiguration.appType = SDLAppHMITypeNavigation;
@@ -158,7 +159,6 @@ describe(@"the streaming video manager", ^{
__block SDLScreenParams *someScreenParams = nil;
__block SDLImageResolution *someImageResolution = nil;
__block SDLHMICapabilities *someHMICapabilities = nil;
- __block SDLVehicleType *testVehicleType = nil;
beforeEach(^{
someImageResolution = [[SDLImageResolution alloc] init];
@@ -167,9 +167,6 @@ describe(@"the streaming video manager", ^{
someScreenParams = [[SDLScreenParams alloc] init];
someScreenParams.resolution = someImageResolution;
-
- testVehicleType = [[SDLVehicleType alloc] init];
- testVehicleType.make = @"TestVehicleType";
});
describe(@"that does not support video streaming", ^{
@@ -179,16 +176,14 @@ describe(@"the streaming video manager", ^{
someRegisterAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init];
someRegisterAppInterfaceResponse.hmiCapabilities = someHMICapabilities;
- someRegisterAppInterfaceResponse.vehicleType = testVehicleType;
SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:someRegisterAppInterfaceResponse];
[[NSNotificationCenter defaultCenter] postNotification:notification];
});
- it(@"should save the connected vehicle make but not the screen size", ^{
+ it(@"should not save the screen size", ^{
expect(@(CGSizeEqualToSize(streamingLifecycleManager.videoScaleManager.displayViewportResolution, CGSizeZero))).toEventually(equal(@YES));
- expect(streamingLifecycleManager.connectedVehicleMake).toEventually(equal(testVehicleType.make));
});
});
@@ -209,18 +204,14 @@ describe(@"the streaming video manager", ^{
#pragma clang diagnostic ignored "-Wdeprecated"
someRegisterAppInterfaceResponse.displayCapabilities = someDisplayCapabilities;
#pragma clang diagnostic pop
- someRegisterAppInterfaceResponse.vehicleType = testVehicleType;
-
- someRegisterAppInterfaceResponse.vehicleType = testVehicleType;
SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:someRegisterAppInterfaceResponse];
[[NSNotificationCenter defaultCenter] postNotification:notification];
});
- it(@"should save the connected vehicle make and the screen size", ^{
+ it(@"should save the screen size", ^{
expect(@(CGSizeEqualToSize(streamingLifecycleManager.videoScaleManager.displayViewportResolution, CGSizeMake(600, 100)))).toEventually(equal(@YES));
- expect(streamingLifecycleManager.connectedVehicleMake).toEventually(equal(testVehicleType.make));
});
});
});
@@ -774,7 +765,6 @@ describe(@"the streaming video manager", ^{
[streamingLifecycleManager endVideoServiceWithCompletionHandler:^ {
handlerCalled = YES;
}];
- streamingLifecycleManager.connectedVehicleMake = @"OEM_make_2";
});
context(@"when the manager is not stopped", ^{
@@ -786,7 +776,6 @@ describe(@"the streaming video manager", ^{
it(@"should transition to the stopped state", ^{
expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamManagerStateStopped));
expect(streamingLifecycleManager.protocol).to(beNil());
- expect(streamingLifecycleManager.connectedVehicleMake).to(beNil());
expect(streamingLifecycleManager.hmiLevel).to(equal(SDLHMILevelNone));
expect(streamingLifecycleManager.videoStreamingState).to(equal(SDLVideoStreamingStateNotStreamable));
expect(streamingLifecycleManager.preferredFormatIndex).to(equal(0));
@@ -804,7 +793,6 @@ describe(@"the streaming video manager", ^{
it(@"should stay in the stopped state", ^{
expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamManagerStateStopped));
expect(streamingLifecycleManager.protocol).to(beNil());
- expect(streamingLifecycleManager.connectedVehicleMake).to(beNil());
expect(streamingLifecycleManager.hmiLevel).to(equal(SDLHMILevelNone));
expect(streamingLifecycleManager.videoStreamingState).to(equal(SDLVideoStreamingStateNotStreamable));
expect(streamingLifecycleManager.preferredFormatIndex).to(equal(0));
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLSystemInfoSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLSystemInfoSpec.m
new file mode 100644
index 000000000..a1be29973
--- /dev/null
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLSystemInfoSpec.m
@@ -0,0 +1,83 @@
+//
+// SDLSystemInfoSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Joel Fischer on 2/24/21.
+// Copyright © 2021 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLSystemInfo.h"
+#import "SDLVehicleType.h"
+
+QuickSpecBegin(SDLSystemInfoSpec)
+
+NSString *hardVersion = @"1.2.3";
+NSString *softVersion = @"9.8.7";
+NSString *make = @"Make";
+NSString *model = @"model";
+NSString *trim = @"trim";
+NSString *modelYear = @"2021";
+SDLVehicleType *vehicleType = [[SDLVehicleType alloc] initWithMake:make model:model modelYear:modelYear trim:trim];
+
+describe(@"system info", ^{
+ __block SDLSystemInfo *systemInfo = nil;
+
+ context(@"init", ^{
+ beforeEach(^{
+ systemInfo = [[SDLSystemInfo alloc] init];
+ });
+
+ it(@"expect all properties to be nil", ^{
+ expect(systemInfo).notTo(beNil());
+ expect(systemInfo.vehicleType).to(beNil());
+ expect(systemInfo.systemSoftwareVersion).to(beNil());
+ expect(systemInfo.systemHardwareVersion).to(beNil());
+ });
+ });
+
+ context(@"initWithMake:model:trim:modelYear:softwareVersion:hardwareVersion:", ^{
+ beforeEach(^{
+ systemInfo = [[SDLSystemInfo alloc] initWithMake:make model:model trim:trim modelYear:modelYear softwareVersion:softVersion hardwareVersion:hardVersion];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(systemInfo).notTo(beNil());
+ expect(systemInfo.vehicleType.make).to(equal(make));
+ expect(systemInfo.vehicleType.model).to(equal(model));
+ expect(systemInfo.vehicleType.trim).to(equal(trim));
+ expect(systemInfo.vehicleType.modelYear).to(equal(modelYear));
+ expect(systemInfo.systemSoftwareVersion).to(equal(softVersion));
+ expect(systemInfo.systemHardwareVersion).to(equal(hardVersion));
+ });
+ });
+
+ context(@"initWithVehicleType:systemSoftwareVersion:systemHardwareVersion:", ^{
+ beforeEach(^{
+ systemInfo = [[SDLSystemInfo alloc] initWithVehicleType:vehicleType softwareVersion:softVersion hardwareVersion:hardVersion];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(systemInfo).notTo(beNil());
+ expect(systemInfo.vehicleType).to(equal(vehicleType));
+ expect(systemInfo.systemSoftwareVersion).to(equal(softVersion));
+ expect(systemInfo.systemHardwareVersion).to(equal(hardVersion));
+ });
+ });
+
+ context(@"alloc and init", ^{
+ beforeEach(^{
+ systemInfo = [SDLSystemInfo alloc];
+ });
+
+ it(@"expect test object to be inited", ^{
+ expect(systemInfo.vehicleType).to(beNil());
+ expect(systemInfo.systemHardwareVersion).to(beNil());
+ expect(systemInfo.systemSoftwareVersion).to(beNil());
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
index 41ff4ba56..ea230248c 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLTextAndGraphicManagerSpec.m
@@ -42,7 +42,7 @@
@property (assign, nonatomic) BOOL isDirty;
-- (void)sdl_displayCapabilityDidUpdate:(SDLSystemCapability *)systemCapability;
+- (void)sdl_displayCapabilityDidUpdate;
@end
@@ -489,11 +489,11 @@ describe(@"text and graphic manager", ^{
beforeEach(^{
testHMIStatus = [[SDLOnHMIStatus alloc] init];
- testWindowCapability = [[SDLWindowCapability alloc] initWithWindowID:@(SDLPredefinedWindowsDefaultWindow) textFields:nil imageFields:nil imageTypeSupported:nil templatesAvailable:nil numCustomPresetsAvailable:nil buttonCapabilities:nil softButtonCapabilities:nil menuLayoutsAvailable:nil dynamicUpdateCapabilities:nil];
+ testWindowCapability = [[SDLWindowCapability alloc] initWithWindowID:@(SDLPredefinedWindowsDefaultWindow) textFields:nil imageFields:nil imageTypeSupported:nil templatesAvailable:nil numCustomPresetsAvailable:nil buttonCapabilities:nil softButtonCapabilities:nil menuLayoutsAvailable:nil dynamicUpdateCapabilities:nil keyboardCapabilities:nil];
testDisplayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"Test display" windowCapabilities:@[testWindowCapability] windowTypeSupported:nil];
- testSystemCapability = [[SDLSystemCapability alloc] initWithDisplayCapabilities:@[testDisplayCapability]];
- [testManager sdl_displayCapabilityDidUpdate:testSystemCapability];
+ OCMStub([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
});
// with a non-default window
@@ -554,13 +554,14 @@ describe(@"text and graphic manager", ^{
SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:testHMIStatus];
[[NSNotificationCenter defaultCenter] postNotification:notification];
- testWindowCapability = [[SDLWindowCapability alloc] initWithWindowID:@(SDLPredefinedWindowsDefaultWindow) textFields:nil imageFields:nil imageTypeSupported:nil templatesAvailable:nil numCustomPresetsAvailable:nil buttonCapabilities:nil softButtonCapabilities:nil menuLayoutsAvailable:nil dynamicUpdateCapabilities:nil];
+ testWindowCapability = [[SDLWindowCapability alloc] initWithWindowID:@(SDLPredefinedWindowsDefaultWindow) textFields:nil imageFields:nil imageTypeSupported:nil templatesAvailable:nil numCustomPresetsAvailable:nil buttonCapabilities:nil softButtonCapabilities:nil menuLayoutsAvailable:nil dynamicUpdateCapabilities:nil keyboardCapabilities:nil];
testDisplayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:@"Test display" windowCapabilities:@[testWindowCapability] windowTypeSupported:nil];
testSystemCapability = [[SDLSystemCapability alloc] initWithDisplayCapabilities:@[testDisplayCapability]];
});
it(@"should start the transaction queue and not send a transaction", ^{
- [testManager sdl_displayCapabilityDidUpdate:testSystemCapability];
+ OCMStub([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
expect(testManager.transactionQueue.isSuspended).to(beFalse());
expect(testManager.transactionQueue.operationCount).to(equal(0));
@@ -569,7 +570,8 @@ describe(@"text and graphic manager", ^{
context(@"if there's data", ^{
beforeEach(^{
testManager.textField1 = @"test";
- [testManager sdl_displayCapabilityDidUpdate:testSystemCapability];
+ OCMStub([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testManager sdl_displayCapabilityDidUpdate];
});
it(@"should send an update and not supersede the previous update", ^{
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLControlFramePayloadConstantsSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLControlFramePayloadConstantsSpec.m
index dba3e9a8b..480adbe27 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLControlFramePayloadConstantsSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLControlFramePayloadConstantsSpec.m
@@ -17,21 +17,28 @@ describe(@"Individual Enum Value Tests", ^ {
it(@"Should match internal values", ^ {
expect(SDLControlFrameInt32NotFound).to(equal(-1));
expect(SDLControlFrameInt64NotFound).to(equal(-1));
- expect(SDLControlFrameProtocolVersionKey).to(equal(@"protocolVersion"));
+
+ expect(SDLControlFrameAuthTokenKey).to(equal(@"authToken"));
+ expect(SDLControlFrameAudioServiceTransportsKey).to(equal(@"audioServiceTransports"));
expect(SDLControlFrameHashIdKey).to(equal(@"hashId"));
+ expect(SDLControlFrameHeightKey).to(equal(@"height"));
expect(SDLControlFrameMTUKey).to(equal(@"mtu"));
- expect(SDLControlFrameSecondaryTransportsKey).to(equal(@"secondaryTransports"));
- expect(SDLControlFrameAudioServiceTransportsKey).to(equal(@"audioServiceTransports"));
- expect(SDLControlFrameVideoServiceTransportsKey).to(equal(@"videoServiceTransports"));
- expect(SDLControlFrameAuthTokenKey).to(equal(@"authToken"));
- expect(SDLControlFrameRejectedParams).to(equal(@"rejectedParams"));
+ expect(SDLControlFrameProtocolVersionKey).to(equal(@"protocolVersion"));
expect(SDLControlFrameReasonKey).to(equal(@"reason"));
- expect(SDLControlFrameVideoProtocolKey).to(equal(@"videoProtocol"));
- expect(SDLControlFrameVideoCodecKey).to(equal(@"videoCodec"));
- expect(SDLControlFrameHeightKey).to(equal(@"height"));
- expect(SDLControlFrameWidthKey).to(equal(@"width"));
+ expect(SDLControlFrameRejectedParams).to(equal(@"rejectedParams"));
+ expect(SDLControlFrameSecondaryTransportsKey).to(equal(@"secondaryTransports"));
expect(SDLControlFrameTCPIPAddressKey).to(equal(@"tcpIpAddress"));
expect(SDLControlFrameTCPPortKey).to(equal(@"tcpPort"));
+ expect(SDLControlFrameVehicleHardwareVersionKey).to(equal(@"systemHardwareVersion"));
+ expect(SDLControlFrameVehicleMakeKey).to(equal(@"make"));
+ expect(SDLControlFrameVehicleModelKey).to(equal(@"model"));
+ expect(SDLControlFrameVehicleModelYearKey).to(equal(@"modelYear"));
+ expect(SDLControlFrameVehicleSoftwareVersionKey).to(equal(@"systemSoftwareVersion"));
+ expect(SDLControlFrameVehicleTrimKey).to(equal(@"trim"));
+ expect(SDLControlFrameVideoCodecKey).to(equal(@"videoCodec"));
+ expect(SDLControlFrameVideoProtocolKey).to(equal(@"videoProtocol"));
+ expect(SDLControlFrameVideoServiceTransportsKey).to(equal(@"videoServiceTransports"));
+ expect(SDLControlFrameWidthKey).to(equal(@"width"));
});
});
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
index 483033569..ba5957369 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/MessageSpecs/SDLProtocolSpec.m
@@ -10,8 +10,10 @@
#import <OCMock/OCMock.h>
#import "SDLTransportType.h"
+#import "SDLControlFramePayloadAudioStartServiceAck.h"
#import "SDLControlFramePayloadRegisterSecondaryTransportNak.h"
#import "SDLControlFramePayloadRPCStartServiceAck.h"
+#import "SDLControlFramePayloadVideoStartServiceAck.h"
#import "SDLGlobals.h"
#import "SDLProtocolHeader.h"
#import "SDLProtocol.h"
@@ -399,8 +401,15 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
__block id transportMock = nil;
__block SDLProtocol *testProtocol = nil;
__block id delegateMock = nil;
- __block int64_t testMTU = 989786483;
- __block int32_t hashId = 1545784;
+ int64_t testMTU = 989786483;
+ int32_t hashId = 1545784;
+ NSString *testAuthToken = @"testAuthToken";;
+ NSString *testMake = @"Livio";
+ NSString *testModel = @"Is";
+ NSString *testTrim = @"Awesome";
+ NSString *testModelYear = @"2021";
+ NSString *testSystemSoftwareVersion = @"1.1.1.1";
+ NSString *testSystemHardwareVersion = @"2.2.2.2";
beforeEach(^{
transportMock = OCMProtocolMock(@protocol(SDLTransportType));
@@ -413,15 +422,9 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
});
context(@"For protocol versions 5.0.0 and greater", ^{
- __block NSString *testAuthToken = nil;
-
- beforeEach(^{
- testAuthToken = @"testAuthToken";
- });
-
context(@"If the service type is RPC", ^{
- it(@"Should store the auth token and the protocol version and pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.2.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ it(@"Should store the auth token, system info, and the protocol version and pass the start service along to the delegate", ^{
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.2.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:testMake model:testModel trim:testTrim modelYear:testModelYear systemSoftwareVersion:testSystemSoftwareVersion systemHardwareVersion:testSystemHardwareVersion];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -445,7 +448,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
});
it(@"Should store the protocol version, but not get the auth token, and pass the start service along to the delegate if the protocol version is greater than 5.0.0 but less than 5.2.0", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -463,13 +466,13 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
OCMVerifyAllWithDelay(delegateMock, 0.1);
- expect(testProtocol.authToken).to(beNil());
+ expect(testProtocol.authToken).to(equal(testAuthToken));
expect([SDLGlobals sharedGlobals].protocolVersion.stringVersion).to(equal(@"5.1.0"));
expect([SDLGlobals sharedGlobals].maxHeadUnitProtocolVersion.stringVersion).to(equal(@"5.1.0"));
});
it(@"Should set the max head unit version using the header version if the protocol version is missing from the payload", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:nil secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:nil secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -495,7 +498,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is control", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -522,7 +525,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is Audio", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadAudioStartServiceAck *testPayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithMTU:testMTU];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -550,7 +553,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is Video", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:testAuthToken protocolVersion:@"5.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadVideoStartServiceAck *testPayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:0 width:0 protocol:nil codec:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -580,7 +583,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"For protocol versions below 5.0.0", ^{
context(@"If the service type is RPC", ^{
it(@"Should store the protocol version and pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"3.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"3.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
@@ -605,7 +608,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is not RPC", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"4.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"4.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:4];
@@ -630,7 +633,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is Audio", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"4.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadAudioStartServiceAck *testPayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithMTU:testMTU];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:4];
@@ -656,7 +659,7 @@ describe(@"HandleProtocolSessionStarted tests", ^ {
context(@"If the service type is Video", ^{
it(@"Should just pass the start service along to the delegate", ^{
- SDLControlFramePayloadRPCStartServiceAck *testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:hashId mtu:testMTU authToken:nil protocolVersion:@"4.1.0" secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ SDLControlFramePayloadVideoStartServiceAck *testPayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithMTU:testMTU height:0 width:0 protocol:nil codec:nil];
NSData *testData = testPayload.data;
SDLV2ProtocolHeader* testHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:4];
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
index 63e927d5f..a1e94e896 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
@@ -9,136 +9,85 @@
QuickSpecBegin(SDLControlFramePayloadRPCStartServiceAckSpec)
-describe(@"Test encoding data", ^{
+describe(@"The payload", ^{
__block SDLControlFramePayloadRPCStartServiceAck *testPayload = nil;
- __block int32_t testHashId = 0;
- __block int64_t testMTU = 0;
- __block NSString *testProtocolVersion = nil;
- __block NSArray<NSString *> *testSecondaryTransports = nil;
- __block NSArray<NSNumber *> *testAudioServiceTransports = nil;
- __block NSArray<NSNumber *> *testVideoServiceTransports = nil;
-
- context(@"with parameters", ^{
- beforeEach(^{
- testHashId = 1457689;
- testMTU = 5984649;
- testProtocolVersion = @"1.32.32";
-
- testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:nil protocolVersion:testProtocolVersion secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
+ __block NSData *testData = nil;
+ int32_t testHashId = 1457689;
+ int64_t testMTU = 5984649;
+ NSString *testProtocolVersion = @"1.32.32";
+ NSString *testAuthToken = @"Test Auth Token";
+ NSArray<NSString *> *testSecondaryTransports = @[@"TCP_WIFI", @"IAP_USB"];
+ NSArray<NSNumber *> *testAudioServiceTransports = @[@(2)];
+ NSArray<NSNumber *> *testVideoServiceTransports = @[@2, @1];
+ NSString *testMake = @"Livio";
+ NSString *testModel = @"Is";
+ NSString *testTrim = @"Awesome";
+ NSString *testModelYear = @"2021";
+ NSString *testSystemSoftwareVersion = @"1.1.1.1";
+ NSString *testSystemHardwareVersion = @"2.2.2.2";
+
+ describe(@"Test encoding data", ^{
+ context(@"with parameters", ^{
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:testAuthToken protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:testMake model:testModel trim:testTrim modelYear:testModelYear systemSoftwareVersion:testSystemSoftwareVersion systemHardwareVersion:testSystemHardwareVersion];
+ });
+
+ it(@"should create the correct data", ^{
+ NSString *base64Encoded = [testPayload.data base64EncodedStringWithOptions:0];
+ expect(base64Encoded).to(equal(@"bAEAAAR2aWRlb1NlcnZpY2VUcmFuc3BvcnRzABMAAAAQMAACAAAAEDEAAQAAAAAQaGFzaElkABk+FgACbW9kZWwAAwAAAElzABJtdHUAiVFbAAAAAAACbW9kZWxZZWFyAAUAAAAyMDIxAAJzeXN0ZW1IYXJkd2FyZVZlcnNpb24ACAAAADIuMi4yLjIAAm1ha2UABgAAAExpdmlvAAJhdXRoVG9rZW4AEAAAAFRlc3QgQXV0aCBUb2tlbgAEc2Vjb25kYXJ5VHJhbnNwb3J0cwAkAAAAAjAACQAAAFRDUF9XSUZJAAIxAAgAAABJQVBfVVNCAAACc3lzdGVtU29mdHdhcmVWZXJzaW9uAAgAAAAxLjEuMS4xAAJ0cmltAAgAAABBd2Vzb21lAARhdWRpb1NlcnZpY2VUcmFuc3BvcnRzAAwAAAAQMAACAAAAAAJwcm90b2NvbFZlcnNpb24ACAAAADEuMzIuMzIAAA=="));
+ });
});
- it(@"should create the correct data", ^{
- NSString *base64Encoded = [testPayload.data base64EncodedStringWithOptions:0];
- expect(base64Encoded).to(equal(@"OwAAABBoYXNoSWQAGT4WABJtdHUAiVFbAAAAAAACcHJvdG9jb2xWZXJzaW9uAAgAAAAxLjMyLjMyAAA="));
- });
- });
+ context(@"without parameters", ^{
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:SDLControlFrameInt32NotFound mtu:SDLControlFrameInt64NotFound authToken:nil protocolVersion:nil secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
+ });
- context(@"with secondary transport parameters", ^{
- beforeEach(^{
- testHashId = 987654;
- testMTU = 4096;
- testProtocolVersion = @"5.10.01";
- testSecondaryTransports = @[@"TCP_WIFI", @"IAP_USB"];
- testAudioServiceTransports = @[@(2)];
- testVideoServiceTransports = @[(@2), @(1)];
-
- testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
- });
-
- it(@"should create the correct data", ^{
- NSString *base64Encoded = [testPayload.data base64EncodedStringWithOptions:0];
- expect(base64Encoded).to(equal(@"wwAAAAR2aWRlb1NlcnZpY2VUcmFuc3BvcnRzABMAAAAQMAACAAAAEDEAAQAAAAAQaGFzaElkAAYSDwASbXR1AAAQAAAAAAAABHNlY29uZGFyeVRyYW5zcG9ydHMAJAAAAAIwAAkAAABUQ1BfV0lGSQACMQAIAAAASUFQX1VTQgAABGF1ZGlvU2VydmljZVRyYW5zcG9ydHMADAAAABAwAAIAAAAAAnByb3RvY29sVmVyc2lvbgAIAAAANS4xMC4wMQAA"));
+ it(@"should create no data", ^{
+ expect(testPayload.data.length).to(equal(0));
+ });
});
});
- context(@"without parameters", ^{
- beforeEach(^{
- testHashId = SDLControlFrameInt32NotFound;
- testMTU = SDLControlFrameInt64NotFound;
-
- testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:nil protocolVersion:nil secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
- });
-
- it(@"should create no data", ^{
- expect(testPayload.data.length).to(equal(0));
+ describe(@"Test decoding data", ^{
+ context(@"with parameters", ^{
+ beforeEach(^{
+ SDLControlFramePayloadRPCStartServiceAck *firstPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:testAuthToken protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:testMake model:testModel trim:testTrim modelYear:testModelYear systemSoftwareVersion:testSystemSoftwareVersion systemHardwareVersion:testSystemHardwareVersion];
+ testData = firstPayload.data;
+
+ testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.hashId).to(equal(testHashId));
+ expect(testPayload.mtu).to(equal(testMTU));
+ expect(testPayload.authToken).to(equal(testAuthToken));
+ expect(testPayload.protocolVersion).to(equal(testProtocolVersion));
+ expect(testPayload.secondaryTransports).to(equal(testSecondaryTransports));
+ expect(testPayload.audioServiceTransports).to(equal(testAudioServiceTransports));
+ expect(testPayload.videoServiceTransports).to(equal(testVideoServiceTransports));
+ expect(testPayload.make).to(equal(testMake));
+ expect(testPayload.model).to(equal(testModel));
+ expect(testPayload.trim).to(equal(testTrim));
+ expect(testPayload.modelYear).to(equal(testModelYear));
+ expect(testPayload.systemSoftwareVersion).to(equal(testSystemSoftwareVersion));
+ expect(testPayload.systemHardwareVersion).to(equal(testSystemHardwareVersion));
+ });
});
});
-});
-
-describe(@"Test decoding data", ^{
- __block SDLControlFramePayloadRPCStartServiceAck *testPayload = nil;
- __block NSData *testData = nil;
- __block int32_t testHashId = 0;
- __block int64_t testMTU = 0;
- __block NSString *testAuthToken = nil;
- __block NSString *testProtocolVersion = nil;
- __block NSArray<NSString *> *testSecondaryTransports = nil;
- __block NSArray<NSNumber *> *testAudioServiceTransports = nil;
- __block NSArray<NSNumber *> *testVideoServiceTransports = nil;
-
- context(@"with parameters", ^{
- beforeEach(^{
- testHashId = 1545784;
- testMTU = 989786483;
- testAuthToken = @"testAuthToken";
- testProtocolVersion = @"3.89.5";
- SDLControlFramePayloadRPCStartServiceAck *firstPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:testAuthToken protocolVersion:testProtocolVersion secondaryTransports:nil audioServiceTransports:nil videoServiceTransports:nil];
- testData = firstPayload.data;
+ describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadRPCStartServiceAck *testPayload = nil;
+ __block NSData *testData = nil;
- testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:testData];
- });
-
- it(@"should output the correct params", ^{
- expect(testPayload.hashId).to(equal(testHashId));
- expect(testPayload.mtu).to(equal(testMTU));
- expect(testPayload.authToken).to(equal(testAuthToken));
- expect(testPayload.protocolVersion).to(equal(testProtocolVersion));
- expect(testPayload.secondaryTransports).to(beNil());
- expect(testPayload.audioServiceTransports).to(beNil());
- expect(testPayload.videoServiceTransports).to(beNil());
- });
- });
-
- context(@"with secondary transport parameters", ^{
beforeEach(^{
- testHashId = 17999024;
- testMTU = 1798250;
- testAuthToken = @"testAuthToken";
- testProtocolVersion = @"6.01.00";
- testSecondaryTransports = @[@"TCP_WIFI"];
- testAudioServiceTransports = @[@(2), @(1)];
- testVideoServiceTransports = @[@(1)];
-
- SDLControlFramePayloadRPCStartServiceAck *firstPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMTU authToken:testAuthToken protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
- testData = firstPayload.data;
-
testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:testData];
});
it(@"should output the correct params", ^{
- expect(testPayload.hashId).to(equal(testHashId));
- expect(testPayload.mtu).to(equal(testMTU));
- expect(testPayload.authToken).to(equal(testAuthToken));
- expect(testPayload.protocolVersion).to(equal(testProtocolVersion));
- expect(testPayload.secondaryTransports).to(equal(testSecondaryTransports));
- expect(testPayload.audioServiceTransports).to(equal(testAudioServiceTransports));
- expect(testPayload.videoServiceTransports).to(equal(testVideoServiceTransports));
+ expect(testPayload.data.length).to(equal(0));
});
});
});
-describe(@"Test nil data", ^{
- __block SDLControlFramePayloadRPCStartServiceAck *testPayload = nil;
- __block NSData *testData = nil;
-
- beforeEach(^{
- testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:testData];
- });
-
- it(@"should output the correct params", ^{
- expect(testPayload.data.length).to(equal(0));
- });
-});
-
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m b/SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m
index b7279a352..41db3cdad 100644
--- a/SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m
+++ b/SmartDeviceLinkTests/ProxySpecs/SDLSecondaryTransportManagerSpec.m
@@ -248,7 +248,7 @@ describe(@"the secondary transport manager ", ^{
testAudioServiceTransports = @[@(2), @(1)];
testVideoServiceTransports = @[@(2)];
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
});
@@ -274,7 +274,7 @@ describe(@"the secondary transport manager ", ^{
// Note: this is not allowed for now. It should contain only one element.
testSecondaryTransports = @[@"TCP_WIFI", @"IAP_USB_HOST_MODE"];
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
});
@@ -299,7 +299,7 @@ describe(@"the secondary transport manager ", ^{
testAudioServiceTransports = @[@(2)];
testVideoServiceTransports = @[@(2)];
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
});
@@ -320,7 +320,7 @@ describe(@"the secondary transport manager ", ^{
context(@"without secondary transport related parameter", ^{
beforeEach(^{
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
});
@@ -411,7 +411,7 @@ describe(@"the secondary transport manager ", ^{
testTransportEventUpdatePayload = [[SDLControlFramePayloadTransportEventUpdate alloc] initWithTcpIpAddress:testTcpIpAddress tcpPort:testTcpPort];
testTransportEventUpdateMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testTransportEventUpdateHeader andPayload:testTransportEventUpdatePayload.data];
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
manager.currentHMILevel = SDLHMILevelFull;
manager.currentApplicationState = UIApplicationStateActive;
@@ -450,7 +450,7 @@ describe(@"the secondary transport manager ", ^{
testTransportEventUpdatePayload = [[SDLControlFramePayloadTransportEventUpdate alloc] initWithTcpIpAddress:testTcpIpAddress tcpPort:testTcpPort];
testTransportEventUpdateMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testTransportEventUpdateHeader andPayload:testTransportEventUpdatePayload.data];
- testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports];
+ testStartServiceACKPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithHashId:testHashId mtu:testMtu authToken:nil protocolVersion:testProtocolVersion secondaryTransports:testSecondaryTransports audioServiceTransports:testAudioServiceTransports videoServiceTransports:testVideoServiceTransports make:nil model:nil trim:nil modelYear:nil systemSoftwareVersion:nil systemHardwareVersion:nil];
testStartServiceACKMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testStartServiceACKHeader andPayload:testStartServiceACKPayload.data];
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardEventSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardEventSpec.m
index ce2782d3f..d47e87d4c 100644
--- a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardEventSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardEventSpec.m
@@ -12,13 +12,15 @@
QuickSpecBegin(SDLKeyboardEventSpec)
-describe(@"Individual Enum Value Tests", ^ {
- it(@"Should match internal values", ^ {
+describe(@"individual enum value tests", ^{
+ it(@"should match internal values", ^{
expect(SDLKeyboardEventKeypress).to(equal(@"KEYPRESS"));
expect(SDLKeyboardEventSubmitted).to(equal(@"ENTRY_SUBMITTED"));
expect(SDLKeyboardEventCancelled).to(equal(@"ENTRY_CANCELLED"));
expect(SDLKeyboardEventAborted).to(equal(@"ENTRY_ABORTED"));
expect(SDLKeyboardEventVoice).to(equal(@"ENTRY_VOICE"));
+ expect(SDLKeyboardEventInputKeyMaskEnabled).to(equal(@"INPUT_KEY_MASK_ENABLED"));
+ expect(SDLKeyboardEventInputKeyMaskDisabled).to(equal(@"INPUT_KEY_MASK_DISABLED"));
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardInputMaskSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardInputMaskSpec.m
new file mode 100644
index 000000000..dd7bd708e
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardInputMaskSpec.m
@@ -0,0 +1,23 @@
+//
+// SDLAppHMITypeSpec.m
+// SmartDeviceLink
+
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLKeyboardInputMask.h"
+
+QuickSpecBegin(SDLKeyboardInputMaskSpec)
+
+describe(@"individual enum value tests", ^{
+ it(@"should match internal values", ^{
+ expect(SDLKeyboardInputMaskEnableInputKeyMask).to(equal(@"ENABLE_INPUT_KEY_MASK"));
+ expect(SDLKeyboardInputMaskDisableInputKeyMask).to(equal(@"DISABLE_INPUT_KEY_MASK"));
+ expect(SDLKeyboardInputMaskUserChoiceInputKeyMask).to(equal(@"USER_CHOICE_INPUT_KEY_MASK"));
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardLayoutSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardLayoutSpec.m
index ec0298852..d254c9d06 100644
--- a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardLayoutSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLKeyboardLayoutSpec.m
@@ -12,11 +12,12 @@
QuickSpecBegin(SDLKeyboardLayoutSpec)
-describe(@"Individual Enum Value Tests", ^ {
- it(@"Should match internal values", ^ {
+describe(@"individual enum value tests", ^{
+ it(@"should match internal values", ^{
expect(SDLKeyboardLayoutQWERTY).to(equal(@"QWERTY"));
expect(SDLKeyboardLayoutQWERTZ).to(equal(@"QWERTZ"));
expect(SDLKeyboardLayoutAZERTY).to(equal(@"AZERTY"));
+ expect(SDLKeyboardLayoutNumeric).to(equal(@"NUMERIC"));
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLRegisterAppInterfaceResponseSpec.m b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLRegisterAppInterfaceResponseSpec.m
index 1b00938fb..3ad17cb87 100644
--- a/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLRegisterAppInterfaceResponseSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLRegisterAppInterfaceResponseSpec.m
@@ -39,18 +39,18 @@ describe(@"Getter/Setter Tests", ^ {
testResponse.buttonCapabilities = @[button];
testResponse.softButtonCapabilities = @[softButton];
testResponse.presetBankCapabilities = presetBank;
+ testResponse.vehicleType = vehicle;
+ testResponse.systemSoftwareVersion = @"systemSoftwareVersion";
#pragma clang diagnostic pop
testResponse.hmiZoneCapabilities = @[SDLHMIZoneCapabilitiesBack, SDLHMIZoneCapabilitiesFront];
testResponse.speechCapabilities = @[SDLSpeechCapabilitiesSAPIPhonemes, SDLSpeechCapabilitiesSilence];
testResponse.vrCapabilities = @[SDLVRCapabilitiesText];
testResponse.audioPassThruCapabilities = @[audioPassThru];
testResponse.pcmStreamCapabilities = audioPassThru;
- testResponse.vehicleType = vehicle;
testResponse.prerecordedSpeech = @[SDLPrerecordedSpeechListen, SDLPrerecordedSpeechHelp];
testResponse.supportedDiagModes = @[@67, @99, @111];
testResponse.hmiCapabilities = hmiCapabilities;
testResponse.sdlVersion = @"sdlVersion";
- testResponse.systemSoftwareVersion = @"systemSoftwareVersion";
testResponse.iconResumed = @YES;
testResponse.sdlMsgVersion = sdlVersion;
@@ -63,18 +63,18 @@ describe(@"Getter/Setter Tests", ^ {
expect(testResponse.buttonCapabilities).to(equal(@[button]));
expect(testResponse.softButtonCapabilities).to(equal(@[softButton]));
expect(testResponse.presetBankCapabilities).to(equal(presetBank));
+ expect(testResponse.vehicleType).to(equal(vehicle));
+ expect(testResponse.systemSoftwareVersion).to(equal(@"systemSoftwareVersion"));
#pragma clang diagnostic pop
expect(testResponse.hmiZoneCapabilities).to(equal(@[SDLHMIZoneCapabilitiesBack, SDLHMIZoneCapabilitiesFront]));
expect(testResponse.speechCapabilities).to(equal(@[SDLSpeechCapabilitiesSAPIPhonemes, SDLSpeechCapabilitiesSilence]));
expect(testResponse.vrCapabilities).to(equal(@[SDLVRCapabilitiesText]));
expect(testResponse.audioPassThruCapabilities).to(equal(@[audioPassThru]));
expect(testResponse.pcmStreamCapabilities).to(equal(audioPassThru));
- expect(testResponse.vehicleType).to(equal(vehicle));
expect(testResponse.prerecordedSpeech).to(equal(@[SDLPrerecordedSpeechListen, SDLPrerecordedSpeechHelp]));
expect(testResponse.supportedDiagModes).to(equal(@[@67, @99, @111]));
expect(testResponse.hmiCapabilities).to(equal(hmiCapabilities));
expect(testResponse.sdlVersion).to(equal(@"sdlVersion"));
- expect(testResponse.systemSoftwareVersion).to(equal(@"systemSoftwareVersion"));
expect(testResponse.iconResumed).to(beTrue());
});
@@ -118,18 +118,18 @@ describe(@"Getter/Setter Tests", ^ {
expect(testResponse.buttonCapabilities).to(equal(@[button]));
expect(testResponse.softButtonCapabilities).to(equal(@[softButton]));
expect(testResponse.presetBankCapabilities).to(equal(presetBank));
+ expect(testResponse.vehicleType).to(equal(vehicle));
+ expect(testResponse.systemSoftwareVersion).to(equal(@"systemSoftwareVersion"));
#pragma clang diagnostic pop
expect(testResponse.hmiZoneCapabilities).to(equal(@[SDLHMIZoneCapabilitiesBack, SDLHMIZoneCapabilitiesFront]));
expect(testResponse.speechCapabilities).to(equal(@[SDLSpeechCapabilitiesSAPIPhonemes, SDLSpeechCapabilitiesSilence]));
expect(testResponse.vrCapabilities).to(equal(@[SDLVRCapabilitiesText]));
expect(testResponse.audioPassThruCapabilities).to(equal(@[audioPassThru]));
expect(testResponse.pcmStreamCapabilities).to(equal(audioPassThru));
- expect(testResponse.vehicleType).to(equal(vehicle));
expect(testResponse.prerecordedSpeech).to(equal(@[SDLPrerecordedSpeechListen, SDLPrerecordedSpeechHelp]));
expect(testResponse.supportedDiagModes).to(equal(@[@67, @99, @111]));
expect(testResponse.hmiCapabilities).to(equal(hmiCapabilities));
expect(testResponse.sdlVersion).to(equal(@"sdlVersion"));
- expect(testResponse.systemSoftwareVersion).to(equal(@"systemSoftwareVersion"));
expect(testResponse.iconResumed).to(beTrue());
});
@@ -147,18 +147,18 @@ describe(@"Getter/Setter Tests", ^ {
expect(testResponse.buttonCapabilities).to(beNil());
expect(testResponse.softButtonCapabilities).to(beNil());
expect(testResponse.presetBankCapabilities).to(beNil());
+ expect(testResponse.vehicleType).to(beNil());
+ expect(testResponse.systemSoftwareVersion).to(beNil());
#pragma clang diagnostic pop
expect(testResponse.hmiZoneCapabilities).to(beNil());
expect(testResponse.speechCapabilities).to(beNil());
expect(testResponse.vrCapabilities).to(beNil());
expect(testResponse.audioPassThruCapabilities).to(beNil());
expect(testResponse.pcmStreamCapabilities).to(beNil());
- expect(testResponse.vehicleType).to(beNil());
expect(testResponse.prerecordedSpeech).to(beNil());
expect(testResponse.supportedDiagModes).to(beNil());
expect(testResponse.hmiCapabilities).to(beNil());
expect(testResponse.sdlVersion).to(beNil());
- expect(testResponse.systemSoftwareVersion).to(beNil());
expect(testResponse.iconResumed).to(beNil());
});
@@ -197,18 +197,18 @@ describe(@"Getter/Setter Tests", ^ {
expectAction(^{ [testResponse buttonCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse softButtonCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse presetBankCapabilities]; }).to(raiseException());
+ expectAction(^{ [testResponse vehicleType]; }).to(raiseException());
+ expectAction(^{ [testResponse systemSoftwareVersion]; }).to(raiseException());
#pragma clang diagnostic pop
expectAction(^{ [testResponse hmiZoneCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse speechCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse vrCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse audioPassThruCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse pcmStreamCapabilities]; }).to(raiseException());
- expectAction(^{ [testResponse vehicleType]; }).to(raiseException());
expectAction(^{ [testResponse prerecordedSpeech]; }).to(raiseException());
expectAction(^{ [testResponse supportedDiagModes]; }).to(raiseException());
expectAction(^{ [testResponse hmiCapabilities]; }).to(raiseException());
expectAction(^{ [testResponse sdlVersion]; }).to(raiseException());
- expectAction(^{ [testResponse systemSoftwareVersion]; }).to(raiseException());
expectAction(^{ [testResponse iconResumed]; }).to(raiseException());
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardCapabilitiesSpec.m
new file mode 100644
index 000000000..18abde7e6
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardCapabilitiesSpec.m
@@ -0,0 +1,75 @@
+//
+// SDLKeyboardCapabilitiesSpec.m
+// SmartDeviceLink
+
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLKeyboardCapabilities.h"
+#import "SDLRPCParameterNames.h"
+#import "SDLKeyboardLayoutCapability.h"
+
+QuickSpecBegin(SDLKeyboardCapabilitiesSpec)
+
+NSNumber *maskInputCharactersSupported = @YES;
+SDLKeyboardLayoutCapability *keyboardLayoutCapability = [[SDLKeyboardLayoutCapability alloc] init];
+NSArray<SDLKeyboardLayoutCapability *> *supportedKeyboards = @[keyboardLayoutCapability];
+__block SDLKeyboardCapabilities* testStruct = nil;
+
+describe(@"getter/setter tests", ^{
+ context(@"init", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardCapabilities alloc] init];
+ });
+
+ it(@"should return nil if not set", ^{
+ expect(testStruct.maskInputCharactersSupported).to(beNil());
+ expect(testStruct.supportedKeyboards).to(beNil());
+ });
+ });
+
+ context(@"init and assign", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardCapabilities alloc] init];
+ testStruct.maskInputCharactersSupported = maskInputCharactersSupported;
+ testStruct.supportedKeyboards = supportedKeyboards;
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.maskInputCharactersSupported).to(equal(maskInputCharactersSupported));
+ expect(testStruct.supportedKeyboards).to(equal(supportedKeyboards));
+ });
+ });
+
+ context(@"initWithDictionary:", ^{
+ beforeEach(^{
+ NSDictionary<NSString *, id> *dict = @{
+ SDLRPCParameterNameMaskInputCharactersSupported: maskInputCharactersSupported,
+ SDLRPCParameterNameSupportedKeyboards: supportedKeyboards,
+ };
+ testStruct = [[SDLKeyboardCapabilities alloc] initWithDictionary:dict];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.maskInputCharactersSupported).to(equal(maskInputCharactersSupported));
+ expect(testStruct.supportedKeyboards).to(equal(supportedKeyboards));
+ });
+ });
+
+ context(@"initWithMaskInputCharactersSupported:supportedKeyboards:", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardCapabilities alloc] initWithMaskInputCharactersSupported:maskInputCharactersSupported supportedKeyboards:supportedKeyboards];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct).notTo(beNil());
+ expect(testStruct.maskInputCharactersSupported).to(equal(maskInputCharactersSupported));
+ expect(testStruct.supportedKeyboards).to(equal(supportedKeyboards));
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardLayoutCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardLayoutCapabilitySpec.m
new file mode 100644
index 000000000..f938c30a9
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardLayoutCapabilitySpec.m
@@ -0,0 +1,75 @@
+//
+// SDLKeyboardLayoutCapabilitySpec.m
+// SmartDeviceLink
+
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLKeyboardCapabilities.h"
+#import "SDLKeyboardLayout.h"
+#import "SDLRPCParameterNames.h"
+#import "SDLKeyboardLayoutCapability.h"
+
+QuickSpecBegin(SDLKeyboardLayoutCapabilitySpec)
+
+SDLKeyboardLayout keyboardLayout = SDLKeyboardLayoutNumeric;
+UInt8 numConfigurableKeys = 9;
+__block SDLKeyboardLayoutCapability* testStruct = nil;
+
+describe(@"getter/setter tests", ^{
+ context(@"init", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardLayoutCapability alloc] init];
+ });
+
+ it(@"should return nil if not set", ^{
+ expect(testStruct.keyboardLayout).to(beNil());
+ expect(testStruct.numConfigurableKeys).to(beNil());
+ });
+ });
+
+ context(@"init and assign", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardLayoutCapability alloc] init];
+ testStruct.numConfigurableKeys = @(numConfigurableKeys);
+ testStruct.keyboardLayout = keyboardLayout;
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.numConfigurableKeys).to(equal(@(numConfigurableKeys)));
+ expect(testStruct.keyboardLayout).to(equal(keyboardLayout));
+ });
+ });
+
+ context(@"initWithDictionary:", ^{
+ beforeEach(^{
+ NSDictionary<NSString *, id> *dict = @{
+ SDLRPCParameterNameNumConfigurableKeys: @(numConfigurableKeys),
+ SDLRPCParameterNameKeyboardLayout: keyboardLayout,
+ };
+ testStruct = [[SDLKeyboardLayoutCapability alloc] initWithDictionary:dict];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.numConfigurableKeys).to(equal(@(numConfigurableKeys)));
+ expect(testStruct.keyboardLayout).to(equal(keyboardLayout));
+ });
+ });
+
+ context(@"initWithKeyboardLayout:numConfigurableKeys:", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardLayoutCapability alloc] initWithKeyboardLayout:keyboardLayout numConfigurableKeys:numConfigurableKeys];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct).notTo(beNil());
+ expect(testStruct.numConfigurableKeys).to(equal(@(numConfigurableKeys)));
+ expect(testStruct.keyboardLayout).to(equal(keyboardLayout));
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardPropertiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardPropertiesSpec.m
index b1f15a63f..8735babca 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardPropertiesSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLKeyboardPropertiesSpec.m
@@ -8,109 +8,182 @@
#import <Quick/Quick.h>
#import <Nimble/Nimble.h>
+#import "SDLKeyboardInputMask.h"
#import "SDLKeyboardLayout.h"
#import "SDLKeypressMode.h"
#import "SDLKeyboardProperties.h"
#import "SDLLanguage.h"
#import "SDLRPCParameterNames.h"
-
QuickSpecBegin(SDLKeyboardPropertiesSpec)
-describe(@"Getter/Setter Tests", ^ {
- __block SDLLanguage testLanguage = SDLLanguageDaDk;
- __block SDLKeyboardLayout testLayout = SDLKeyboardLayoutAZERTY;
- __block SDLKeypressMode testMode = SDLKeypressModeSingleKeypress;
- __block NSArray<NSString *> *testLimitedCharacterList = @[@"s", @"r", @"f"];
- __block NSString *testAutoCompleteText = @"Auto Carrot";
- __block NSArray<NSString *> *testAutoCompleteList = @[@"Hello World", @"How are you"];
-
- it(@"Should set and get correctly", ^ {
- SDLKeyboardProperties* testStruct = [[SDLKeyboardProperties alloc] init];
-
- testStruct.language = testLanguage;
- testStruct.keyboardLayout = testLayout;
- testStruct.keypressMode = testMode;
- testStruct.limitedCharacterList = testLimitedCharacterList;
- testStruct.autoCompleteList = testAutoCompleteList;
+__block SDLLanguage testLanguage = nil;
+__block SDLKeyboardLayout testLayout = nil;
+__block SDLKeypressMode testMode = nil;
+__block NSArray<NSString *> *testLimitedCharacterList = nil;
+__block NSString *testAutoCompleteText = nil;
+__block NSArray<NSString *> *testAutoCompleteList = nil;
+__block SDLKeyboardInputMask maskInputCharacters = nil;
+__block NSArray<NSString *> *customKeys = nil;
+__block SDLKeyboardProperties* testStruct = nil;
+
+describe(@"getter/setter tests", ^{
+ beforeEach(^{
+ testLanguage = SDLLanguageDaDk;
+ testLayout = SDLKeyboardLayoutAZERTY;
+ testMode = SDLKeypressModeSingleKeypress;
+ testLimitedCharacterList = @[@"s", @"r", @"f"];
+ testAutoCompleteText = @"Auto Carrot";
+ testAutoCompleteList = @[@"Hello World", @"How are you"];
+ maskInputCharacters = SDLKeyboardInputMaskEnableInputKeyMask;
+ customKeys = @[@"abc", @"DEF"];
+ });
+
+ context(@"init", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardProperties alloc] init];
+ });
+
+ it(@"expect all properties to be nil", ^{
+ expect(testStruct.language).to(beNil());
+ expect(testStruct.keyboardLayout).to(beNil());
+ expect(testStruct.keypressMode).to(beNil());
+ expect(testStruct.limitedCharacterList).to(beNil());
+ expect(testStruct.autoCompleteList).to(beNil());
+ expect(testStruct.maskInputCharacters).to(beNil());
+ expect(testStruct.customKeys).to(beNil());
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ expect(testStruct.autoCompleteText).to(beNil());
+#pragma clang diagnostic pop
+ });
+ });
+
+ context(@"init and assign", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardProperties alloc] init];
+ testStruct.language = testLanguage;
+ testStruct.keyboardLayout = testLayout;
+ testStruct.keypressMode = testMode;
+ testStruct.limitedCharacterList = testLimitedCharacterList;
+ testStruct.autoCompleteList = testAutoCompleteList;
+ testStruct.maskInputCharacters = maskInputCharacters;
+ testStruct.customKeys = customKeys;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- testStruct.autoCompleteText = testAutoCompleteText;
+ testStruct.autoCompleteText = testAutoCompleteText;
#pragma clang diagnostic pop
+ testStruct.maskInputCharacters = maskInputCharacters;
+ });
- expect(testStruct.language).to(equal(testLanguage));
- expect(testStruct.keyboardLayout).to(equal(testLayout));
- expect(testStruct.keypressMode).to(equal(testMode));
- expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
- expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ it(@"should be set properly", ^{
+ expect(testStruct.language).to(equal(testLanguage));
+ expect(testStruct.keyboardLayout).to(equal(testLayout));
+ expect(testStruct.keypressMode).to(equal(testMode));
+ expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ expect(testStruct.maskInputCharacters).to(equal(maskInputCharacters));
+ expect(testStruct.customKeys).to(equal(customKeys));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
+ expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
#pragma clang diagnostic pop
+ });
});
-
- it(@"Should get correctly when initialized with a dictionary", ^ {
- NSDictionary* dict = @{SDLRPCParameterNameLanguage: testLanguage,
- SDLRPCParameterNameKeyboardLayout: testLayout,
- SDLRPCParameterNameKeypressMode: testMode,
- SDLRPCParameterNameLimitedCharacterList: testLimitedCharacterList,
- SDLRPCParameterNameAutoCompleteList: testAutoCompleteList,
- SDLRPCParameterNameAutoCompleteText: testAutoCompleteText
- };
- SDLKeyboardProperties* testStruct = [[SDLKeyboardProperties alloc] initWithDictionary:dict];
-
- expect(testStruct.language).to(equal(testLanguage));
- expect(testStruct.keyboardLayout).to(equal(testLayout));
- expect(testStruct.keypressMode).to(equal(testMode));
- expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
- expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+
+ context(@"initWithDictionary:", ^{
+ beforeEach(^{
+ NSDictionary* dict = @{SDLRPCParameterNameLanguage: testLanguage,
+ SDLRPCParameterNameKeyboardLayout: testLayout,
+ SDLRPCParameterNameKeypressMode: testMode,
+ SDLRPCParameterNameLimitedCharacterList: testLimitedCharacterList,
+ SDLRPCParameterNameAutoCompleteList: testAutoCompleteList,
+ SDLRPCParameterNameAutoCompleteText: testAutoCompleteText,
+ SDLRPCParameterNameMaskInputCharacters: maskInputCharacters,
+ SDLRPCParameterNameCustomKeys: customKeys,
+ };
+ testStruct = [[SDLKeyboardProperties alloc] initWithDictionary:dict];
+ });
+
+ it(@"should be set properly", ^{
+ expect(testStruct.language).to(equal(testLanguage));
+ expect(testStruct.keyboardLayout).to(equal(testLayout));
+ expect(testStruct.keypressMode).to(equal(testMode));
+ expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ expect(testStruct.maskInputCharacters).to(equal(maskInputCharacters));
+ expect(testStruct.customKeys).to(equal(customKeys));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
+ expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
#pragma clang diagnostic pop
+ });
});
- it(@"Should get correctly when initialized with initWithLanguage:layout:keypressMode:limitedCharacterList:autoCompleteText:autoCompleteList:", ^ {
+ context(@"initWithLanguage:layout:keypressMode:limitedCharacterList:autoCompleteText:autoCompleteList:", ^{
+ beforeEach(^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- SDLKeyboardProperties *testStruct = [[SDLKeyboardProperties alloc] initWithLanguage:testLanguage layout:testLayout keypressMode:testMode limitedCharacterList:testLimitedCharacterList autoCompleteText:testAutoCompleteText autoCompleteList:testAutoCompleteList];
+ testStruct = [[SDLKeyboardProperties alloc] initWithLanguage:testLanguage layout:testLayout keypressMode:testMode limitedCharacterList:testLimitedCharacterList autoCompleteText:testAutoCompleteText autoCompleteList:testAutoCompleteList];
#pragma clang diagnostic pop
- expect(testStruct.language).to(equal(testLanguage));
- expect(testStruct.keyboardLayout).to(equal(testLayout));
- expect(testStruct.keypressMode).to(equal(testMode));
- expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ });
+
+ it(@"should be set properly", ^{
+ expect(testStruct.language).to(equal(testLanguage));
+ expect(testStruct.keyboardLayout).to(equal(testLayout));
+ expect(testStruct.keypressMode).to(equal(testMode));
+ expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ expect(testStruct.maskInputCharacters).to(beNil());
+ expect(testStruct.customKeys).to(beNil());
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
+ expect(testStruct.autoCompleteText).to(equal(testAutoCompleteText));
#pragma clang diagnostic pop
- expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ });
});
- it(@"Should get correctly when initialized with initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList:", ^ {
- SDLKeyboardProperties *testStruct = [[SDLKeyboardProperties alloc] initWithLanguage:testLanguage keyboardLayout:testLayout keypressMode:testMode limitedCharacterList:testLimitedCharacterList autoCompleteList:testAutoCompleteList];
- expect(testStruct.language).to(equal(testLanguage));
- expect(testStruct.keyboardLayout).to(equal(testLayout));
- expect(testStruct.keypressMode).to(equal(testMode));
- expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
- expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ context(@"initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList:", ^{
+ beforeEach(^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- expect(testStruct.autoCompleteText).to(beNil());
+ testStruct = [[SDLKeyboardProperties alloc] initWithLanguage:testLanguage keyboardLayout:testLayout keypressMode:testMode limitedCharacterList:testLimitedCharacterList autoCompleteList:testAutoCompleteList];
#pragma clang diagnostic pop
+ });
+
+ it(@"should be set properly", ^{
+ expect(testStruct.language).to(equal(testLanguage));
+ expect(testStruct.keyboardLayout).to(equal(testLayout));
+ expect(testStruct.keypressMode).to(equal(testMode));
+ expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ expect(testStruct.maskInputCharacters).to(beNil());
+ expect(testStruct.customKeys).to(beNil());
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ expect(testStruct.autoCompleteText).to(beNil());
+#pragma clang diagnostic pop
+ });
});
-
- it(@"Should return nil if not set", ^ {
- SDLKeyboardProperties* testStruct = [[SDLKeyboardProperties alloc] init];
-
- expect(testStruct.language).to(beNil());
- expect(testStruct.keyboardLayout).to(beNil());
- expect(testStruct.keypressMode).to(beNil());
- expect(testStruct.limitedCharacterList).to(beNil());
- expect(testStruct.autoCompleteList).to(beNil());
+
+ context(@"initWithLanguage:keyboardLayout:keypressMode:limitedCharacterList:autoCompleteList:maskInputCharacters:customKeys:", ^{
+ beforeEach(^{
+ testStruct = [[SDLKeyboardProperties alloc] initWithLanguage:testLanguage keyboardLayout:testLayout keypressMode:testMode limitedCharacterList:testLimitedCharacterList autoCompleteList:testAutoCompleteList maskInputCharacters:maskInputCharacters customKeys:customKeys];
+ });
+
+ it(@"should be set properly", ^{
+ expect(testStruct.language).to(equal(testLanguage));
+ expect(testStruct.keyboardLayout).to(equal(testLayout));
+ expect(testStruct.keypressMode).to(equal(testMode));
+ expect(testStruct.limitedCharacterList).to(equal(testLimitedCharacterList));
+ expect(testStruct.autoCompleteList).to(equal(testAutoCompleteList));
+ expect(testStruct.maskInputCharacters).to(equal(maskInputCharacters));
+ expect(testStruct.customKeys).to(equal(customKeys));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- expect(testStruct.autoCompleteText).to(beNil());
+ expect(testStruct.autoCompleteText).to(beNil());
#pragma clang diagnostic pop
+ });
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVehicleTypeSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVehicleTypeSpec.m
index a4f3efa0d..207667dd5 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVehicleTypeSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVehicleTypeSpec.m
@@ -14,41 +14,57 @@
QuickSpecBegin(SDLVehicleTypeSpec)
describe(@"Getter/Setter Tests", ^ {
+ NSString *make = @"make";
+ NSString *model = @"model";
+ NSString *modelYear = @"modelYear";
+ NSString *trim = @"trim";
+
it(@"Should set and get correctly", ^ {
- SDLVehicleType* testStruct = [[SDLVehicleType alloc] init];
+ SDLVehicleType *testStruct = [[SDLVehicleType alloc] init];
- testStruct.make = @"Make";
- testStruct.model = @"Model";
- testStruct.modelYear = @"3.141*10^36";
- testStruct.trim = @"AE";
+ testStruct.make = make;
+ testStruct.model = model;
+ testStruct.modelYear = modelYear;
+ testStruct.trim = trim;
- expect(testStruct.make).to(equal(@"Make"));
- expect(testStruct.model).to(equal(@"Model"));
- expect(testStruct.modelYear).to(equal(@"3.141*10^36"));
- expect(testStruct.trim).to(equal(@"AE"));
+ expect(testStruct.make).to(equal(make));
+ expect(testStruct.model).to(equal(model));
+ expect(testStruct.modelYear).to(equal(modelYear));
+ expect(testStruct.trim).to(equal(trim));
});
- it(@"Should get correctly when initialized", ^ {
- NSMutableDictionary<NSString *, id> *dict = [@{SDLRPCParameterNameMake:@"Make",
- SDLRPCParameterNameModel:@"Model",
- SDLRPCParameterNameModelYear:@"3.141*10^36",
- SDLRPCParameterNameTrim:@"AE"} mutableCopy];
- SDLVehicleType* testStruct = [[SDLVehicleType alloc] initWithDictionary:dict];
+ it(@"Should get correctly when initialized with a dictionary", ^ {
+ NSDictionary *dict = @{
+ SDLRPCParameterNameMake: make,
+ SDLRPCParameterNameModel: model,
+ SDLRPCParameterNameModelYear: modelYear,
+ SDLRPCParameterNameTrim: trim
+ };
+ SDLVehicleType *testStruct = [[SDLVehicleType alloc] initWithDictionary:dict];
- expect(testStruct.make).to(equal(@"Make"));
- expect(testStruct.model).to(equal(@"Model"));
- expect(testStruct.modelYear).to(equal(@"3.141*10^36"));
- expect(testStruct.trim).to(equal(@"AE"));
+ expect(testStruct.make).to(equal(make));
+ expect(testStruct.model).to(equal(model));
+ expect(testStruct.modelYear).to(equal(modelYear));
+ expect(testStruct.trim).to(equal(trim));
});
- it(@"Should return nil if not set", ^ {
- SDLVehicleType* testStruct = [[SDLVehicleType alloc] init];
+ it(@"should initialize correctly with init", ^ {
+ SDLVehicleType *testStruct = [[SDLVehicleType alloc] init];
expect(testStruct.make).to(beNil());
expect(testStruct.model).to(beNil());
expect(testStruct.modelYear).to(beNil());
expect(testStruct.trim).to(beNil());
});
+
+ it(@"should initialize correctly with initWithMake:model:modelYear:trim:", ^{
+ SDLVehicleType *testStruct = [[SDLVehicleType alloc] initWithMake:make model:model modelYear:modelYear trim:trim];
+
+ expect(testStruct.make).to(equal(make));
+ expect(testStruct.model).to(equal(model));
+ expect(testStruct.modelYear).to(equal(modelYear));
+ expect(testStruct.trim).to(equal(trim));
+ });
});
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m
index e8c2514b4..7543826eb 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m
@@ -5,16 +5,19 @@
#import <Quick/Quick.h>
#import <Nimble/Nimble.h>
-#import "SDLWindowCapability.h"
-
#import "SDLButtonCapabilities.h"
#import "SDLDynamicUpdateCapabilities.h"
#import "SDLImageField.h"
#import "SDLImageType.h"
+#import "SDLKeyboardCapabilities.h"
+#import "SDLKeyboardLayoutCapability.h"
+#import "SDLKeyboardProperties.h"
#import "SDLRPCParameterNames.h"
#import "SDLSoftButtonCapabilities.h"
#import "SDLTextField.h"
#import "SDLTextFieldName.h"
+#import "SDLWindowCapability+ScreenManagerExtensions.h"
+
QuickSpecBegin(SDLWindowCapabilitySpec)
@@ -30,89 +33,360 @@ __block NSString *testImageName = nil;
__block NSString *testTemplateAvailable = nil;
__block SDLMenuLayout testMenuLayout = SDLMenuLayoutTiles;
__block SDLDynamicUpdateCapabilities *testDynamicUpdates = nil;
+__block NSArray<SDLTextField *> *textFields = nil;
+__block NSArray<SDLImageField *> *imageFields = nil;
+__block NSArray<SDLButtonCapabilities *> *buttonCapabilities = nil;
+__block SDLKeyboardCapabilities *keyboardCapabilities = nil;
+__block id windowID = nil;
+__block id numCustomPresetsAvailable = nil;
+__block NSArray<SDLImageType> *imageTypeSupported = nil;
+__block NSArray<NSString *> *templatesAvailable = nil;
+__block NSArray<SDLSoftButtonCapabilities *> *softButtonCapabilities = nil;
+__block NSArray<SDLMenuLayout> *menuLayoutsAvailable = nil;
-describe(@"Getter/Setter Tests", ^ {
+describe(@"getter/setter tests", ^{
beforeEach(^{
testImageType = SDLImageTypeDynamic;
testTextName = @"test Text field";
testImageName = @"test Image field";
-
+
testTextField = [[SDLTextField alloc] init];
testTextField.name = SDLTextFieldNameTertiaryText;
testImageField = [[SDLImageField alloc] init];
testImageField.name = testImageName;
-
+
testButtonCapabilities = [[SDLButtonCapabilities alloc] init];
testButtonCapabilities.name = SDLButtonNameOk;
testButtonCapabilities.shortPressAvailable = @YES;
testButtonCapabilities.longPressAvailable = @YES;
testButtonCapabilities.upDownAvailable = @YES;
-
+
testSoftButtonsCapabilities = [[SDLSoftButtonCapabilities alloc] init];
testSoftButtonsCapabilities.imageSupported = @YES;
testTemplateAvailable = @"myTemplate";
testDynamicUpdates = [[SDLDynamicUpdateCapabilities alloc] initWithSupportedDynamicImageFieldNames:@[SDLImageFieldNameSubMenuIcon] supportsDynamicSubMenus:@YES];
+
+ textFields = @[testTextField];
+ imageFields = @[testImageField];
+ buttonCapabilities = @[testButtonCapabilities];
+ keyboardCapabilities = [[SDLKeyboardCapabilities alloc] init];
+ windowID = @444;
+ numCustomPresetsAvailable = @10;
+ imageTypeSupported = @[testImageType];
+ templatesAvailable = @[testTemplateAvailable];
+ softButtonCapabilities = @[testSoftButtonsCapabilities];
+ menuLayoutsAvailable = @[testMenuLayout];
});
-
- it(@"Should set and get correctly", ^ {
- testStruct = [[SDLWindowCapability alloc] init];
- testStruct.windowID = @444;
- testStruct.numCustomPresetsAvailable = @10;
- testStruct.textFields = @[testTextField];
- testStruct.imageFields = @[testImageField];
- testStruct.imageTypeSupported = @[testImageType];
- testStruct.buttonCapabilities = @[testButtonCapabilities];
- testStruct.softButtonCapabilities = @[testSoftButtonsCapabilities];
- testStruct.menuLayoutsAvailable = @[testMenuLayout];
- testStruct.templatesAvailable = @[testTemplateAvailable];
- testStruct.dynamicUpdateCapabilities = testDynamicUpdates;
-
- expect(testStruct.windowID).to(equal(@444));
- expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText));
- expect(testStruct.imageFields.firstObject.name).to(equal(testImageName));
- expect(testStruct.numCustomPresetsAvailable).to(equal(@10));
- expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
- expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(equal(@YES));
- expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(equal(@YES));
- expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
- expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(equal(@YES));
- expect(testStruct.menuLayoutsAvailable).to(equal(@[testMenuLayout]));
- expect(testStruct.templatesAvailable).to(equal(@[testTemplateAvailable]));
- expect(testStruct.dynamicUpdateCapabilities).to(equal(testDynamicUpdates));
+
+ context(@"init", ^{
+ beforeEach(^{
+ testStruct = [[SDLWindowCapability alloc] init];
+ });
+
+ it(@"expect all properties to be nil", ^{
+ expect(testStruct.windowID).to(beNil());
+ expect(testStruct.textFields.firstObject.name).to(beNil());
+ expect(testStruct.imageFields.firstObject.name).to(beNil());
+ expect(testStruct.numCustomPresetsAvailable).to(beNil());
+ expect(testStruct.buttonCapabilities.firstObject.name).to(beNil());
+ expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(beNil());
+ expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(beNil());
+ expect(testStruct.buttonCapabilities.firstObject.name).to(beNil());
+ expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(beNil());
+ expect(testStruct.menuLayoutsAvailable).to(beNil());
+ expect(testStruct.templatesAvailable).to(beNil());
+ expect(testStruct.dynamicUpdateCapabilities).to(beNil());
+ expect(testStruct.imageTypeSupported).to(beNil());
+ expect(testStruct.keyboardCapabilities).to(beNil());
+ });
+ });
+
+ context(@"init and assign", ^{
+ beforeEach(^{
+ testStruct = [[SDLWindowCapability alloc] init];
+ testStruct.windowID = windowID;
+ testStruct.numCustomPresetsAvailable = numCustomPresetsAvailable;
+ testStruct.textFields = @[testTextField];
+ testStruct.imageFields = @[testImageField];
+ testStruct.imageTypeSupported = @[testImageType];
+ testStruct.buttonCapabilities = @[testButtonCapabilities];
+ testStruct.softButtonCapabilities = @[testSoftButtonsCapabilities];
+ testStruct.menuLayoutsAvailable = @[testMenuLayout];
+ testStruct.templatesAvailable = @[testTemplateAvailable];
+ testStruct.dynamicUpdateCapabilities = testDynamicUpdates;
+ testStruct.keyboardCapabilities = keyboardCapabilities;
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.windowID).to(equal(windowID));
+ expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText));
+ expect(testStruct.imageFields.firstObject.name).to(equal(testImageName));
+ expect(testStruct.numCustomPresetsAvailable).to(equal(numCustomPresetsAvailable));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(equal(@YES));
+ expect(testStruct.menuLayoutsAvailable).to(equal(@[testMenuLayout]));
+ expect(testStruct.templatesAvailable).to(equal(@[testTemplateAvailable]));
+ expect(testStruct.dynamicUpdateCapabilities).to(equal(testDynamicUpdates));
+ expect(testStruct.imageTypeSupported).to(equal(@[testImageType]));
+ expect(testStruct.keyboardCapabilities).to(equal(keyboardCapabilities));
+ });
+ });
+
+ context(@"initWithWindowID:textFields:imageFields:imageTypeSupported:templatesAvailable:numCustomPresetsAvailable:buttonCapabilities:softButtonCapabilities:menuLayoutsAvailable:dynamicUpdateCapabilities:", ^{
+ beforeEach(^{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ testStruct = [[SDLWindowCapability alloc] initWithWindowID:windowID textFields:textFields imageFields:imageFields imageTypeSupported:imageTypeSupported templatesAvailable:templatesAvailable numCustomPresetsAvailable:numCustomPresetsAvailable buttonCapabilities:buttonCapabilities softButtonCapabilities:softButtonCapabilities menuLayoutsAvailable:menuLayoutsAvailable dynamicUpdateCapabilities:testDynamicUpdates];
+#pragma clang diagnostic pop
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.windowID).to(equal(windowID));
+ expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText));
+ expect(testStruct.imageFields.firstObject.name).to(equal(testImageName));
+ expect(testStruct.numCustomPresetsAvailable).to(equal(numCustomPresetsAvailable));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(equal(@YES));
+ expect(testStruct.menuLayoutsAvailable).to(equal(@[testMenuLayout]));
+ expect(testStruct.templatesAvailable).to(equal(@[testTemplateAvailable]));
+ expect(testStruct.dynamicUpdateCapabilities).to(equal(testDynamicUpdates));
+ expect(testStruct.imageTypeSupported).to(equal(@[testImageType]));
+ expect(testStruct.keyboardCapabilities).to(beNil());
+ });
+ });
+
+ context(@"initWithWindowID:textFields:imageFields:imageTypeSupported:templatesAvailable:numCustomPresetsAvailable:buttonCapabilities:softButtonCapabilities:menuLayoutsAvailable:dynamicUpdateCapabilities:keyboardCapabilities:", ^{
+ beforeEach(^{
+ testStruct = [[SDLWindowCapability alloc] initWithWindowID:windowID textFields:textFields imageFields:imageFields imageTypeSupported:imageTypeSupported templatesAvailable:templatesAvailable numCustomPresetsAvailable:numCustomPresetsAvailable buttonCapabilities:buttonCapabilities softButtonCapabilities:softButtonCapabilities menuLayoutsAvailable:menuLayoutsAvailable dynamicUpdateCapabilities:testDynamicUpdates keyboardCapabilities:keyboardCapabilities];
+ });
+
+ it(@"expect all properties to be set properly", ^{
+ expect(testStruct.windowID).to(equal(windowID));
+ expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText));
+ expect(testStruct.imageFields.firstObject.name).to(equal(testImageName));
+ expect(testStruct.numCustomPresetsAvailable).to(equal(numCustomPresetsAvailable));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(equal(@YES));
+ expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
+ expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(equal(@YES));
+ expect(testStruct.menuLayoutsAvailable).to(equal(@[testMenuLayout]));
+ expect(testStruct.templatesAvailable).to(equal(@[testTemplateAvailable]));
+ expect(testStruct.dynamicUpdateCapabilities).to(equal(testDynamicUpdates));
+ expect(testStruct.imageTypeSupported).to(equal(@[testImageType]));
+ expect(testStruct.keyboardCapabilities).to(equal(keyboardCapabilities));
+ });
});
});
-describe(@"initializing with ", ^{
+describe(@"creating a valid keyboard configuration based on keyboard capabilities", ^{
+ UInt8 numConfigurableKeys = 7;
+
beforeEach(^{
- testStruct = [[SDLWindowCapability alloc] initWithWindowID:@444 textFields:@[testTextField] imageFields:@[testImageField] imageTypeSupported:@[testImageType] templatesAvailable:@[testTemplateAvailable] numCustomPresetsAvailable:@10 buttonCapabilities:@[testButtonCapabilities] softButtonCapabilities:@[testSoftButtonsCapabilities] menuLayoutsAvailable:@[testMenuLayout] dynamicUpdateCapabilities:testDynamicUpdates];
+ testStruct = [[SDLWindowCapability alloc] init];
+ testStruct.keyboardCapabilities = nil;
});
- it(@"Should set and get correctly", ^ {
- testStruct = [[SDLWindowCapability alloc] init];
- testStruct.windowID = @444;
- testStruct.numCustomPresetsAvailable = @10;
- testStruct.textFields = @[testTextField];
- testStruct.imageFields = @[testImageField];
- testStruct.imageTypeSupported = @[testImageType];
- testStruct.buttonCapabilities = @[testButtonCapabilities];
- testStruct.softButtonCapabilities = @[testSoftButtonsCapabilities];
- testStruct.menuLayoutsAvailable = @[testMenuLayout];
- testStruct.templatesAvailable = @[testTemplateAvailable];
- testStruct.dynamicUpdateCapabilities = testDynamicUpdates;
-
- expect(testStruct.windowID).to(equal(@444));
- expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText));
- expect(testStruct.imageFields.firstObject.name).to(equal(testImageName));
- expect(testStruct.numCustomPresetsAvailable).to(equal(@10));
- expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
- expect(testStruct.buttonCapabilities.firstObject.shortPressAvailable).to(equal(@YES));
- expect(testStruct.buttonCapabilities.firstObject.longPressAvailable).to(equal(@YES));
- expect(testStruct.buttonCapabilities.firstObject.name).to(equal(SDLButtonNameOk));
- expect(testStruct.softButtonCapabilities.firstObject.imageSupported).to(equal(@YES));
- expect(testStruct.menuLayoutsAvailable).to(equal(@[testMenuLayout]));
- expect(testStruct.templatesAvailable).to(equal(@[testTemplateAvailable]));
- expect(testStruct.dynamicUpdateCapabilities).to(equal(testDynamicUpdates));
+ context(@"when keyboardCapabilities is nil or empty", ^{
+ it(@"result should be nil when the argument is nil", ^{
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:nil];
+ expect(resultProperties).to(beNil());
+ });
+
+ it(@"result should be equal to the argument when keyboardLayout is nil", ^{
+ SDLKeyboardProperties *testKeyboardProperties = [[SDLKeyboardProperties alloc] init];
+ testKeyboardProperties.maskInputCharacters = SDLKeyboardInputMaskUserChoiceInputKeyMask;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).notTo(beNil());
+ expect(resultProperties).to(equal(testKeyboardProperties));
+ expect(resultProperties.maskInputCharacters).to(equal(SDLKeyboardInputMaskUserChoiceInputKeyMask));
+ });
+
+ it(@"result should be nil when the argument is not nil and keyboardCapabilities is empty", ^{
+ testStruct.keyboardCapabilities = [[SDLKeyboardCapabilities alloc] init];
+ SDLKeyboardProperties *testKeyboardProperties = [[SDLKeyboardProperties alloc] init];
+ testKeyboardProperties.keyboardLayout = SDLKeyboardLayoutNumeric;
+ testKeyboardProperties.maskInputCharacters = SDLKeyboardInputMaskUserChoiceInputKeyMask;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).to(beNil());
+ });
+
+ context(@"when keyboardCapabilities is not empty", ^{
+ __block SDLKeyboardProperties *testKeyboardProperties = nil;
+ __block SDLKeyboardCapabilities *keyboardCapabilities = nil;
+ __block NSArray *testCustomKeysLong = nil;
+
+ beforeEach(^{
+ // create a long array that contains more custom keys than <numConfigurableKeys>
+ testCustomKeysLong = [@"a ä æ b c d e ê f j h i j k l m n o p q r s ß t u v w x y z" componentsSeparatedByString:@" "];
+ NSArray *arrayLayouts = @[SDLKeyboardLayoutQWERTY, SDLKeyboardLayoutQWERTZ, SDLKeyboardLayoutAZERTY, SDLKeyboardLayoutNumeric];
+ NSMutableArray *arrayLayoutCapability = [[NSMutableArray alloc] initWithCapacity:arrayLayouts.count];
+ for (SDLKeyboardLayout layout in arrayLayouts) {
+ SDLKeyboardLayoutCapability *layoutCapability = [[SDLKeyboardLayoutCapability alloc] initWithKeyboardLayout:layout numConfigurableKeys:numConfigurableKeys];
+ [arrayLayoutCapability addObject:layoutCapability];
+ }
+ keyboardCapabilities = [[SDLKeyboardCapabilities alloc] init];
+ keyboardCapabilities.supportedKeyboards = arrayLayoutCapability;
+ testStruct.keyboardCapabilities = keyboardCapabilities;
+
+ testKeyboardProperties = [[SDLKeyboardProperties alloc] init];
+ testKeyboardProperties.keyboardLayout = SDLKeyboardLayoutNumeric;
+ // create custom keys array longer than <numConfigurableKeys>
+ testKeyboardProperties.customKeys = testCustomKeysLong;
+ testKeyboardProperties.maskInputCharacters = SDLKeyboardInputMaskUserChoiceInputKeyMask;
+ testKeyboardProperties.keyboardLayout = SDLKeyboardLayoutAZERTY;
+ });
+
+ it(@"maskInputCharacters should not be nil when maskInputCharactersSupported = YES", ^{
+ keyboardCapabilities.maskInputCharactersSupported = @YES;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).notTo(beNil());
+ expect(resultProperties).notTo(equal(testKeyboardProperties));
+ expect(resultProperties.customKeys.count).to(equal(numConfigurableKeys));
+ expect(resultProperties.maskInputCharacters).to(equal(SDLKeyboardInputMaskUserChoiceInputKeyMask));
+ });
+
+ it(@"maskInputCharacters should be nil when maskInputCharactersSupported = NO", ^{
+ keyboardCapabilities.maskInputCharactersSupported = @NO;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).notTo(beNil());
+ expect(resultProperties).notTo(equal(testKeyboardProperties));
+ expect(resultProperties.customKeys.count).to(equal(numConfigurableKeys));
+ expect(resultProperties.maskInputCharacters).to(beNil());
+ });
+
+ it(@"customKeys should be trimmed to contain <numConfigurableKeys> items", ^{
+ NSArray *expectedCustomKeys = [testCustomKeysLong subarrayWithRange:NSMakeRange(0, numConfigurableKeys)];
+ testKeyboardProperties.customKeys = testCustomKeysLong;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).notTo(beNil());
+ expect(resultProperties.customKeys.count).to(equal(numConfigurableKeys));
+ expect(resultProperties.customKeys).to(equal(expectedCustomKeys));
+ });
+
+ it(@"customKeys should not be trimmed and should be equal to the initial array", ^{
+ NSArray *testCustomKeys = [testCustomKeysLong subarrayWithRange:NSMakeRange(0, numConfigurableKeys)];
+ testKeyboardProperties.customKeys = testCustomKeys;
+ SDLKeyboardProperties *resultProperties = [testStruct createValidKeyboardConfigurationBasedOnKeyboardCapabilitiesFromConfiguration:testKeyboardProperties];
+ expect(resultProperties).notTo(beNil());
+ expect(resultProperties.customKeys.count).to(equal(numConfigurableKeys));
+ expect(resultProperties.customKeys).to(equal(testCustomKeys));
+ });
+ });
+ });
+});
+
+describe(@"extensions", ^{
+ describe(@"getting the max number of main field lines", ^{
+ __block SDLTextField *testTextField1 = nil;
+ __block SDLTextField *testTextField2 = nil;
+ __block SDLTextField *testTextField3 = nil;
+ __block SDLTextField *testTextField4 = nil;
+
+ beforeEach(^{
+ testTextField1 = [[SDLTextField alloc] init];
+ testTextField1.name = SDLTextFieldNameMainField1;
+
+ testTextField2 = [[SDLTextField alloc] init];
+ testTextField2.name = SDLTextFieldNameMainField2;
+
+ testTextField3 = [[SDLTextField alloc] init];
+ testTextField3.name = SDLTextFieldNameMainField3;
+
+ testTextField4 = [[SDLTextField alloc] init];
+ testTextField4.name = SDLTextFieldNameMainField4;
+
+ testStruct = [[SDLWindowCapability alloc] init];
+ });
+
+ it(@"should return 0 if none of the text fields are supported", ^ {
+ testStruct.textFields = @[];
+ NSUInteger maxNumberOfMainFieldLines = [testStruct maxNumberOfMainFieldLines];
+
+ expect(maxNumberOfMainFieldLines).to(equal(0));
+ });
+
+ it(@"should return 1 if only one text field is supported", ^ {
+ testStruct.textFields = @[testTextField1];
+ NSUInteger maxNumberOfMainFieldLines = [testStruct maxNumberOfMainFieldLines];
+
+ expect(maxNumberOfMainFieldLines).to(equal(1));
+ });
+
+ it(@"should return 2 if two text fields are supported", ^ {
+ testStruct.textFields = @[testTextField2, testTextField1];
+ NSUInteger maxNumberOfMainFieldLines = [testStruct maxNumberOfMainFieldLines];
+
+ expect(maxNumberOfMainFieldLines).to(equal(2));
+ });
+
+ it(@"should return 3 if all the text fields are supported", ^ {
+ testStruct.textFields = @[testTextField2, testTextField1, testTextField3];
+ NSUInteger maxNumberOfMainFieldLines = [testStruct maxNumberOfMainFieldLines];
+
+ expect(maxNumberOfMainFieldLines).to(equal(3));
+ });
+
+ it(@"should return 4 if all the text fields are supported", ^ {
+ testStruct.textFields = @[testTextField1, testTextField2, testTextField3, testTextField4];
+ NSUInteger maxNumberOfMainFieldLines = [testStruct maxNumberOfMainFieldLines];
+
+ expect(maxNumberOfMainFieldLines).to(equal(4));
+ });
+ });
+
+ describe(@"getting the max number of alert text field lines", ^{
+ __block SDLTextField *testAlertTextField1 = nil;
+ __block SDLTextField *testAlertTextField2 = nil;
+ __block SDLTextField *testAlertTextField3 = nil;
+
+ beforeEach(^{
+ testAlertTextField1 = [[SDLTextField alloc] init];
+ testAlertTextField1.name = SDLTextFieldNameAlertText1;
+
+ testAlertTextField2 = [[SDLTextField alloc] init];
+ testAlertTextField2.name = SDLTextFieldNameAlertText2;
+
+ testAlertTextField3 = [[SDLTextField alloc] init];
+ testAlertTextField3.name = SDLTextFieldNameAlertText3;
+
+ testStruct = [[SDLWindowCapability alloc] init];
+ });
+
+ it(@"should return 0 if none of the text fields are supported", ^ {
+ testStruct.textFields = @[];
+ NSUInteger maxNumberOfAlertMainFieldLines = [testStruct maxNumberOfAlertFieldLines];
+
+ expect(maxNumberOfAlertMainFieldLines).to(equal(0));
+ });
+
+ it(@"should return 1 if only one text field is supported", ^ {
+ testStruct.textFields = @[testAlertTextField1];
+ NSUInteger maxNumberOfAlertMainFieldLines = [testStruct maxNumberOfAlertFieldLines];
+
+ expect(maxNumberOfAlertMainFieldLines).to(equal(1));
+ });
+
+ it(@"should return 2 if two text fields are supported", ^ {
+ testStruct.textFields = @[testAlertTextField1, testAlertTextField2];
+ NSUInteger maxNumberOfAlertMainFieldLines = [testStruct maxNumberOfAlertFieldLines];
+
+ expect(maxNumberOfAlertMainFieldLines).to(equal(2));
+ });
+
+ it(@"should return 3 if all the text fields are supported", ^ {
+ testStruct.textFields = @[testAlertTextField1, testAlertTextField2, testAlertTextField3];
+ NSUInteger maxNumberOfAlertMainFieldLines = [testStruct maxNumberOfAlertFieldLines];
+
+ expect(maxNumberOfAlertMainFieldLines).to(equal(3));
+ });
});
});
diff --git a/SmartDeviceLinkTests/SDLAlertAudioDataSpec.m b/SmartDeviceLinkTests/SDLAlertAudioDataSpec.m
new file mode 100644
index 000000000..33aab3d0d
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLAlertAudioDataSpec.m
@@ -0,0 +1,98 @@
+//
+// SDLAlertAudioDataSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLAlertAudioData.h"
+#import "SDLFile.h"
+#import "SDLTTSChunk.h"
+
+
+@interface SDLAlertAudioData()
+
+@property (nullable, copy, nonatomic, readonly) NSDictionary<NSString *, SDLFile *> *audioFileData;
+
+@end
+
+QuickSpecBegin(SDLAlertAudioDataSpec)
+
+describe(@"SDLAlertAudioData", ^{
+ __block NSString *testSpeechSynthesizerString = nil;
+ __block SDLFile *testAudioFile = nil;
+ __block SDLFile *testAudioFile2 = nil;
+
+ beforeEach(^{
+ testSpeechSynthesizerString = @"testSpeechSynthesizerString";
+
+ NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
+ testAudioFile = [[SDLFile alloc] initWithFileURL:[testBundle URLForResource:@"testAudio" withExtension:@"mp3"] name:@"testAudioFile" persistent:YES];
+ testAudioFile2 = [[SDLFile alloc] initWithFileURL:[testBundle URLForResource:@"testAudio" withExtension:@"mp3"] name:@"testAudioFile2" persistent:YES];
+ });
+
+ describe(@"Initialization", ^{
+ it(@"Should get and set playTone correctly", ^{
+ SDLAlertAudioData *testAlertAudioData = [[SDLAlertAudioData alloc] initWithAudioFile:testAudioFile];
+ testAlertAudioData.playTone = YES;
+
+ expect(testAlertAudioData.playTone).to(beTrue());
+ expect(testAlertAudioData.audioData).to(haveCount(1));
+ expect(testAlertAudioData.audioFileData).to(haveCount(1));
+ });
+ });
+
+ describe(@"Copying alert audio data", ^{
+ __block SDLAlertAudioData *testAlertAudioData = nil;
+ __block SDLAlertAudioData *copiedTestAlertAudioData = nil;
+ __block NSString *testSpeechSynthesizerString1 = @"testSpeechSynthesizerString1";
+ __block NSString *testSpeechSynthesizerString2 = @"testSpeechSynthesizerString2";
+
+ beforeEach(^{
+ testAlertAudioData = [[SDLAlertAudioData alloc] initWithAudioFile:testAudioFile];
+ [testAlertAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString1]];
+ testAlertAudioData.playTone = YES;
+
+ copiedTestAlertAudioData = [testAlertAudioData copy];
+ });
+
+ it(@"Should copy correctly", ^{
+ expect(testAlertAudioData == copiedTestAlertAudioData).to(beFalse());
+ expect(testAlertAudioData.audioData).to(equal(copiedTestAlertAudioData.audioData));
+ expect(testAlertAudioData.audioFileData).to(equal(copiedTestAlertAudioData.audioFileData));
+ expect(testAlertAudioData.playTone).to(equal(copiedTestAlertAudioData.playTone));
+ });
+
+ it(@"Should not update the copy if changes are made to the original", ^{
+ [testAlertAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString2]];
+ [testAlertAudioData addAudioFiles:@[testAudioFile2]];
+ testAlertAudioData.playTone = NO;
+
+ expect(testAlertAudioData.audioData).to(haveCount(4));
+ expect(testAlertAudioData.audioData[0].text).to(equal(testAudioFile.name));
+ expect(testAlertAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString1));
+ expect(testAlertAudioData.audioData[2].text).to(equal(testSpeechSynthesizerString2));
+ expect(testAlertAudioData.audioData[3].text).to(equal(testAudioFile2.name));
+
+ expect(copiedTestAlertAudioData.audioData).to(haveCount(2));
+ expect(copiedTestAlertAudioData.audioData[0].text).to(equal(testAudioFile.name));
+ expect(copiedTestAlertAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString1));
+
+ expect(testAlertAudioData.audioFileData).to(haveCount(2));
+ expect(testAlertAudioData.audioFileData[testAudioFile.name]).to(equal(testAudioFile));
+ expect(testAlertAudioData.audioFileData[testAudioFile2.name]).to(equal(testAudioFile2));
+
+ expect(copiedTestAlertAudioData.audioFileData).to(haveCount(1));
+ expect(testAlertAudioData.audioFileData[testAudioFile.name]).to(equal(testAudioFile));
+
+ expect(testAlertAudioData.playTone).to(beFalse());
+ expect(copiedTestAlertAudioData.playTone).to(beTrue());
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLAlertManagerSpec.m b/SmartDeviceLinkTests/SDLAlertManagerSpec.m
new file mode 100644
index 000000000..e39d770cc
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLAlertManagerSpec.m
@@ -0,0 +1,316 @@
+//
+// SDLAlertManagerSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 11/18/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "SDLAlertManager.h"
+#import "SDLAlertView.h"
+#import "SDLFileManager.h"
+#import "SDLPermissionElement.h"
+#import "SDLPermissionManager.h"
+#import "SDLPresentAlertOperation.h"
+#import "SDLSystemCapabilityManager.h"
+#import "SDLWindowCapability.h"
+#import "TestConnectionManager.h"
+
+@interface SDLAlertManager()
+
+@property (strong, nonatomic) NSOperationQueue *transactionQueue;
+@property (assign, nonatomic) UInt16 nextCancelId;
+@property (copy, nonatomic, nullable) SDLWindowCapability *currentWindowCapability;
+
+- (void)sdl_displayCapabilityDidUpdate;
+
+@end
+
+@interface SDLPresentAlertOperation()
+
+@property (copy, nonatomic, nullable) NSError *internalError;
+@property (assign, nonatomic) UInt16 cancelId;
+
+@end
+
+QuickSpecBegin(SDLAlertManagerSpec)
+
+describe(@"alert manager tests", ^{
+ __block SDLAlertManager *testAlertManager = nil;
+ __block id mockConnectionManager = nil;
+ __block id mockFileManager = nil;
+ __block id mockSystemCapabilityManager = nil;
+ __block id mockCurrentWindowCapability = nil;
+ __block id mockPermissionManager = nil;
+ __block SDLWindowCapability *testWindowCapability = nil;
+
+ beforeEach(^{
+ mockConnectionManager = OCMProtocolMock(@protocol(SDLConnectionManagerType));
+ mockFileManager = OCMClassMock([SDLFileManager class]);
+ mockSystemCapabilityManager = OCMClassMock([SDLSystemCapabilityManager class]);
+ mockCurrentWindowCapability = OCMClassMock([SDLWindowCapability class]);
+ mockPermissionManager = OCMClassMock([SDLPermissionManager class]);
+
+ testWindowCapability = [[SDLWindowCapability alloc] init];
+ testWindowCapability.numCustomPresetsAvailable = @10;
+ testWindowCapability.windowID = @(SDLPredefinedWindowsDefaultWindow);
+ });
+
+ describe(@"when initialized", ^{
+ it(@"the transaction queue should be suspended", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+
+ expect(testAlertManager.transactionQueue.suspended).toEventually(beTrue());
+ });
+ });
+
+ describe(@"when started", ^{
+ it(@"should subscribe to capability and permission updates", ^{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundeclared-selector"
+ SEL testSelector = @selector(sdl_displayCapabilityDidUpdate);
+#pragma clang diagnostic pop
+
+ OCMExpect([mockSystemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:[OCMArg any] selector:testSelector]);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLPermissionElement *> *permissionElements = (NSArray<SDLPermissionElement *> *)value;
+ SDLPermissionElement *permissionElement = permissionElements[0];
+ expect(permissionElement.rpcName).to(equal(SDLRPCFunctionNameAlert));
+ return [permissionElement isKindOfClass:[SDLPermissionElement class]];
+ }] groupType:SDLPermissionGroupTypeAny withHandler:[OCMArg any]]);
+
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ OCMVerifyAll(mockSystemCapabilityManager);
+ OCMVerifyAll(mockPermissionManager);
+ });
+
+ describe(@"transaction queue state", ^{
+ it(@"should not start the transaction queue until the alert rpc has the correct permissions to be sent", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg any] groupType:SDLPermissionGroupTypeAny withHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], @(SDLPermissionGroupStatusDisallowed), nil])]);
+
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ expect(testAlertManager.transactionQueue.suspended).to(beTrue());
+ });
+
+ it(@"should start the transaction queue if the alert rpc has the correct permissions and the currentWindowCapability has been set", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg any] groupType:SDLPermissionGroupTypeAny withHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], @(SDLPermissionGroupStatusAllowed), nil])]);
+
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ expect(testAlertManager.transactionQueue.suspended).toEventually(beFalse());
+ });
+
+ it(@"should not start the transaction queue until the currentWindowCapability has been set", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(nil);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg any] groupType:SDLPermissionGroupTypeAny withHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], @(SDLPermissionGroupStatusAllowed), nil])]);
+
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ expect(testAlertManager.transactionQueue.suspended).toEventually(beTrue());
+ });
+ });
+ });
+
+ describe(@"When the display capability updates", ^{
+ __block SDLAlertView *testAlertView = nil;
+ __block SDLAlertView *testAlertView2 = nil;
+
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"alert text" secondaryText:nil tertiaryText:nil timeout:@(5.0) showWaitIndicator:@(NO) audioIndication:nil buttons:nil icon:nil];
+ testAlertView2 = [[SDLAlertView alloc] initWithText:@"alert 2 text" secondaryText:nil tertiaryText:nil timeout:@(5.0) showWaitIndicator:@(NO) audioIndication:nil buttons:nil icon:nil];
+ });
+
+ it(@"should suspend the queue if the new capability is nil and it should not update operations that are currently excecuting with the new capability", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg any] groupType:SDLPermissionGroupTypeAny withHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], @(SDLPermissionGroupStatusAllowed), nil])]);
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ expect(testAlertManager.transactionQueue.suspended).to(beFalse());
+
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+ [testAlertManager presentAlert:testAlertView2 withCompletionHandler:nil];
+ expect(testAlertManager.transactionQueue.operationCount).to(equal(2));
+
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(nil);
+ [testAlertManager sdl_displayCapabilityDidUpdate];
+
+ OCMVerifyAllWithDelay(mockSystemCapabilityManager, 0.5);
+
+ expect(testAlertManager.transactionQueue.suspended).to(beTrue());
+ expect(testAlertManager.transactionQueue.operationCount).to(equal(2));
+
+ SDLPresentAlertOperation *presentAlertOp1 = testAlertManager.transactionQueue.operations[0];
+ SDLPresentAlertOperation *presentAlertOp2 = testAlertManager.transactionQueue.operations[1];
+ expect(presentAlertOp1.isExecuting).to(beTrue());
+ expect(presentAlertOp2.isExecuting).to(beFalse());
+ expect(presentAlertOp1.currentWindowCapability).to(equal(testWindowCapability));
+ expect(presentAlertOp2.currentWindowCapability).to(beNil());
+ });
+
+ it(@"should start the queue if the new capability is not nil and update the pending operations with the new capability", ^{
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(nil);
+ OCMExpect([mockPermissionManager subscribeToRPCPermissions:[OCMArg any] groupType:SDLPermissionGroupTypeAny withHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], @(SDLPermissionGroupStatusAllowed), nil])]);
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+
+ expect(testAlertManager.transactionQueue.suspended).to(beTrue());
+
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+ [testAlertManager presentAlert:testAlertView2 withCompletionHandler:nil];
+ expect(testAlertManager.transactionQueue.operationCount).to(equal(2));
+
+ OCMExpect([mockSystemCapabilityManager defaultMainWindowCapability]).andReturn(testWindowCapability);
+ [testAlertManager sdl_displayCapabilityDidUpdate];
+
+ OCMVerifyAllWithDelay(mockSystemCapabilityManager, 0.5);
+
+ expect(testAlertManager.transactionQueue.suspended).toEventually(beFalse());
+ expect(testAlertManager.transactionQueue.operationCount).to(equal(2));
+
+ SDLPresentAlertOperation *presentAlertOp1 = testAlertManager.transactionQueue.operations[0];
+ SDLPresentAlertOperation *presentAlertOp2 = testAlertManager.transactionQueue.operations[1];
+ expect(presentAlertOp1.isExecuting).to(beTrue());
+ expect(presentAlertOp2.isExecuting).to(beFalse());
+ expect(presentAlertOp2.currentWindowCapability).to(equal(testWindowCapability));
+ expect(presentAlertOp1.currentWindowCapability).to(equal(testWindowCapability));
+ });
+ });
+
+ describe(@"generating a cancel id", ^{
+ __block SDLAlertView *testAlertView = nil;
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"alert text" secondaryText:nil tertiaryText:nil timeout:@(5.0) showWaitIndicator:@(NO) audioIndication:nil buttons:nil icon:nil];
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+ });
+
+ it(@"should set the first cancelID correctly", ^{
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+
+ expect(testAlertManager.transactionQueue.operations.count).to(equal(1));
+
+ SDLPresentAlertOperation *testPresentOp = (SDLPresentAlertOperation *)testAlertManager.transactionQueue.operations.firstObject;
+ expect(@(testPresentOp.cancelId)).to(equal(1));
+ });
+
+ it(@"should reset the cancelID correctly once the max has been reached", ^{
+ testAlertManager.nextCancelId = 100;
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+
+ expect(testAlertManager.transactionQueue.operations.count).to(equal(1));
+
+ SDLPresentAlertOperation *testPresentOp = (SDLPresentAlertOperation *)testAlertManager.transactionQueue.operations[0];
+ expect(@(testPresentOp.cancelId)).to(equal(100));
+
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+
+ expect(testAlertManager.transactionQueue.operations.count).to(equal(2));
+
+ SDLPresentAlertOperation *testPresentOp2 = (SDLPresentAlertOperation *)testAlertManager.transactionQueue.operations[1];
+ expect(@(testPresentOp2.cancelId)).to(equal(1));
+ });
+ });
+
+ describe(@"presenting an alert", ^{
+ __block SDLAlertView *testAlertView = nil;
+ __block SDLAlertView *testAlertView2 = nil;
+
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"alert text" secondaryText:nil tertiaryText:nil timeout:@(5.0) showWaitIndicator:@(NO) audioIndication:nil buttons:nil icon:nil];
+ testAlertView2 = [[SDLAlertView alloc] initWithText:@"alert 2 text" secondaryText:nil tertiaryText:nil timeout:@(5.0) showWaitIndicator:@(NO) audioIndication:nil buttons:nil icon:nil];
+ testAlertManager = [[SDLAlertManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
+ [testAlertManager start];
+ });
+
+ it(@"should add the alert operation to the queue", ^{
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+
+ expect(testAlertManager.transactionQueue.operations.count).to(equal(1));
+ expect(testAlertManager.transactionQueue.operations.firstObject).to(beAKindOf([SDLPresentAlertOperation class]));
+ });
+
+ describe(@"when the completion handler is called", ^{
+ __block BOOL completionHandlerCalled = NO;
+ __block NSError *completionHandlerError = nil;
+
+ beforeEach(^{
+ completionHandlerCalled = NO;
+ completionHandlerError = nil;
+
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:^(NSError * _Nullable error) {
+ completionHandlerCalled = YES;
+ completionHandlerError = error;
+ }];
+ });
+
+ context(@"without an error", ^{
+ it(@"should call the handler", ^{
+ SDLPresentAlertOperation *op = testAlertManager.transactionQueue.operations.lastObject;
+ op.internalError = nil;
+ op.completionBlock();
+
+ expect(completionHandlerCalled).to(beTrue());
+ expect(completionHandlerError).to(beNil());
+ });
+ });
+
+ context(@"with an error", ^{
+ __block NSError *testError;
+
+ beforeEach(^{
+ testError = [NSError errorWithDomain:@"com.sdl.testConnectionManager" code:-1 userInfo:nil];
+ });
+
+ it(@"should call the handler with the error", ^{
+ SDLPresentAlertOperation *op = testAlertManager.transactionQueue.operations.lastObject;
+ op.internalError = testError;
+ op.completionBlock();
+
+ expect(completionHandlerCalled).to(beTrue());
+ expect(completionHandlerError).to(equal(testError));
+ });
+ });
+ });
+
+ describe(@"when the manager shuts down during presentation", ^{
+ beforeEach(^{
+ [testAlertManager presentAlert:testAlertView withCompletionHandler:nil];
+ [testAlertManager presentAlert:testAlertView2 withCompletionHandler:nil];
+ });
+
+ it(@"should cancel any pending operations and unsubscribe to capability and permission updates", ^{
+ SDLPresentAlertOperation *presentAlertOp1 = testAlertManager.transactionQueue.operations[0];
+ SDLPresentAlertOperation *presentAlertOp2 = testAlertManager.transactionQueue.operations[1];
+
+ OCMExpect([mockSystemCapabilityManager unsubscribeFromCapabilityType:SDLSystemCapabilityTypeDisplays withObserver:[OCMArg any]]);
+ OCMExpect([mockPermissionManager removeAllObservers]);
+
+ [testAlertManager stop];
+
+ expect(presentAlertOp1.isCancelled).to(beTrue());
+ expect(presentAlertOp2.isCancelled).to(beTrue());
+ expect(testAlertManager.transactionQueue.operationCount).to(equal(0));
+
+ OCMVerifyAll(mockSystemCapabilityManager);
+ OCMVerifyAll(mockPermissionManager);
+ });
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLAlertViewSpec.m b/SmartDeviceLinkTests/SDLAlertViewSpec.m
new file mode 100644
index 000000000..2e5e0a381
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLAlertViewSpec.m
@@ -0,0 +1,307 @@
+//
+// SDLAlertViewSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 11/10/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLAlertView.h"
+#import "SDLAlertAudioData.h"
+#import "SDLArtwork.h"
+#import "SDLSoftButtonObject.h"
+#import "SDLSoftButtonState.h"
+#import "SDLStaticIconName.h"
+#import "SDLTTSChunk.h"
+
+@interface SDLAlertView()
+
+@property (nullable, copy, nonatomic) SDLAlertCanceledHandler canceledHandler;
+
+@end
+
+QuickSpecBegin(SDLAlertViewSpec)
+
+describe(@"An SDLAlertView", ^{
+ __block NSString *testTextField1 = nil;
+ __block NSString *testTextField2 = nil;
+ __block NSString *testTextField3 = nil;
+ __block NSTimeInterval testTimeout = 0;
+ __block SDLAlertAudioData *testAudio = nil;
+ __block BOOL testShowWaitIndicator = NO;
+ __block NSArray<SDLSoftButtonObject *> *testSoftButtons = nil;
+ __block SDLArtwork *testIcon = nil;
+ __block SDLArtwork *testIcon2 = nil;
+
+ beforeEach(^{
+ testTextField1 = @"testTextField1";
+ testTextField2 = @"testTextField2";
+ testTextField3 = @"testTextField3";
+ testAudio = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"test speech synthesizer string"];
+ testSoftButtons = @[[[SDLSoftButtonObject alloc] initWithName:@"test soft button" text:@"test soft button text" artwork:nil handler:nil]];
+
+ NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
+ UIImage *testImage = [[UIImage alloc] initWithContentsOfFile:[testBundle pathForResource:@"testImageJPEG" ofType:@"jpeg"]];
+ testIcon = [SDLArtwork artworkWithImage:testImage asImageFormat:SDLArtworkImageFormatJPG];
+ UIImage *testImage2 = [[UIImage alloc] initWithContentsOfFile:[testBundle pathForResource:@"testImagePNG" ofType:@"png"]];
+ testIcon2 = [SDLArtwork artworkWithImage:testImage2 asImageFormat:SDLArtworkImageFormatPNG];
+ });
+
+ it(@"should get and set correctly", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.text = testTextField1;
+ testAlertView.secondaryText = testTextField2;
+ testAlertView.tertiaryText = testTextField3;
+ testAlertView.timeout = testTimeout;
+ testAlertView.audio = testAudio;
+ testAlertView.showWaitIndicator = testShowWaitIndicator;
+ testAlertView.softButtons = testSoftButtons;
+ testAlertView.icon = testIcon;
+
+ expect(testAlertView.text).to(equal(testTextField1));
+ expect(testAlertView.secondaryText).to(equal(testTextField2));
+ expect(testAlertView.tertiaryText).to(equal(testTextField3));
+ expect(testAlertView.timeout).to(equal(5.0));
+
+ expect(testAlertView.audio == testAudio).to(beFalse());
+ expect(testAlertView.audio.audioData[0].text).to(equal(testAudio.audioData[0].text));
+ expect(testAlertView.audio.playTone).to(equal(testAudio.playTone));
+
+ expect(testAlertView.showWaitIndicator).to(beFalse());
+ expect(testAlertView.softButtons).to(equal(testSoftButtons));
+
+ expect(testAlertView.icon == testIcon).to(beFalse());
+ expect(testAlertView.icon.name).to(equal(testIcon.name));
+ });
+
+ describe(@"initializing", ^{
+ it(@"should initialize correctly with initWithText:buttons:", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] initWithText:testTextField1 buttons:testSoftButtons];
+
+ expect(testAlertView.text).to(equal(testTextField1));
+ expect(testAlertView.secondaryText).to(beNil());
+ expect(testAlertView.tertiaryText).to(beNil());
+ expect(testAlertView.timeout).to(equal(5.0));
+ expect(testAlertView.audio).to(beNil());
+ expect(testAlertView.showWaitIndicator).to(beFalse());
+ expect(testAlertView.softButtons).to(equal(testSoftButtons));
+ expect(testAlertView.icon).to(beNil());
+ });
+
+ it(@"should initialize correctly with initWithText:secondaryText:tertiaryText:timeout: showWaitIndicator:audioIndication:buttons:icon:", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] initWithText:testTextField1 secondaryText:testTextField2 tertiaryText:testTextField3 timeout:@(testTimeout) showWaitIndicator:@(testShowWaitIndicator) audioIndication:testAudio buttons:testSoftButtons icon:testIcon];
+
+ expect(testAlertView.text).to(equal(testTextField1));
+ expect(testAlertView.secondaryText).to(equal(testTextField2));
+ expect(testAlertView.tertiaryText).to(equal(testTextField3));
+ expect(testAlertView.timeout).to(equal(5.0));
+ expect(testAlertView.audio).toNot(beNil());
+
+ expect(testAlertView.audio == testAudio).to(beFalse());
+ expect(testAlertView.audio.audioData[0].text).to(equal(testAudio.audioData[0].text));
+ expect(testAlertView.audio.playTone).to(equal(testAudio.playTone));
+
+ expect(testAlertView.showWaitIndicator).to(beFalse());
+ expect(testAlertView.softButtons).to(equal(testSoftButtons));
+
+ expect(testAlertView.icon == testIcon).to(beFalse());
+ expect(testAlertView.icon.name).to(equal(testIcon.name));
+ });
+
+ it(@"should set a default value for timeout and set nil for all other properties", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] init];
+
+ expect(testAlertView.text).to(beNil());
+ expect(testAlertView.secondaryText).to(beNil());
+ expect(testAlertView.tertiaryText).to(beNil());
+ expect(testAlertView.timeout).to(equal(5.0));
+ expect(testAlertView.audio).to(beNil());
+ expect(testAlertView.showWaitIndicator).to(beFalse());
+ expect(testAlertView.softButtons).to(beNil());
+ expect(testAlertView.icon).to(beNil());
+ });
+ });
+
+ describe(@"setting invalid data", ^{
+ __block NSArray<SDLSoftButtonObject *> *testInvalidSoftButtons = nil;
+
+ beforeEach(^{
+ SDLSoftButtonState *state1 = [[SDLSoftButtonState alloc] initWithStateName:@"state1" text:@"state 1" image:nil];
+ SDLSoftButtonState *state2 = [[SDLSoftButtonState alloc] initWithStateName:@"state2" text:@"state 2" image:nil];
+ SDLSoftButtonObject *testInvalidSoftButton = [[SDLSoftButtonObject alloc] initWithName:@"invalid soft button" states:@[state1, state2] initialStateName:state1.name handler:nil];
+ SDLSoftButtonObject *testValidSoftButton = [[SDLSoftButtonObject alloc] initWithName:@"valid soft button" text:@"state 3" artwork:nil handler:nil];
+ testInvalidSoftButtons = @[testValidSoftButton, testInvalidSoftButton];
+ });
+
+ it(@"should throw an exception if any button has multiple states", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] init];
+
+ expectAction(^{
+ [testAlertView setSoftButtons:testInvalidSoftButtons];
+ }).to(raiseException().named(@"InvalidSoftButtonStates"));
+ });
+
+ it(@"should throw an exception if any button has multiple states when the property is set via a convenience init", ^{
+ expectAction(^{
+ (void)[[SDLAlertView alloc] initWithText:@"test" buttons:testInvalidSoftButtons];
+ }).to(raiseException().named(@"InvalidSoftButtonStates"));
+ });
+ });
+
+ describe(@"setting the default timeout", ^{
+ __block SDLAlertView *testAlertView = nil;
+
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] init];
+ });
+
+ it(@"should return 10 if a value greater than 10 has been set", ^{
+ SDLAlertView.defaultTimeout = 15.0;
+ expect(SDLAlertView.defaultTimeout).to(equal(10.0));
+ expect(testAlertView.timeout).to(equal(10.0));
+ });
+
+ it(@"should return 3 if a value less than 3 has been set", ^{
+ SDLAlertView.defaultTimeout = -2.0;
+ expect(SDLAlertView.defaultTimeout).to(equal(3.0));
+ expect(testAlertView.timeout).to(equal(3.0));
+ });
+
+ it(@"should return the set value if a value between 3 and 10 has been set", ^{
+ SDLAlertView.defaultTimeout = 4.5;
+ expect(SDLAlertView.defaultTimeout).to(equal(4.5));
+ expect(testAlertView.timeout).to(equal(4.5));
+ });
+
+ it(@"should return the set value if it is between 3 and 10", ^{
+ SDLAlertView.defaultTimeout = 3.0;
+ expect(SDLAlertView.defaultTimeout).to(equal(3.0));
+ expect(testAlertView.timeout).to(equal(3.0));
+ });
+ });
+
+ describe(@"setting the timeout", ^{
+ __block SDLAlertView *testAlertView = nil;
+ __block NSTimeInterval testDefaultTimeout = 5.0;
+
+ beforeEach(^{
+ SDLAlertView.defaultTimeout = testDefaultTimeout;
+ testAlertView = [[SDLAlertView alloc] init];
+ });
+
+ it(@"should return the default timeout if it has not been set", ^{
+ expect(testAlertView.timeout).to(equal(SDLAlertView.defaultTimeout));
+ });
+
+ it(@"should return the default timeout if 0 has been set", ^{
+ testAlertView.timeout = 0.0;
+ expect(testAlertView.timeout).to(equal(testDefaultTimeout));
+ });
+
+ it(@"should return 10 if a value greater than 10 has been set", ^{
+ testAlertView.timeout = 15.0;
+ expect(testAlertView.timeout).to(equal(10.0));
+ });
+
+ it(@"should return 3 if a value less than 3 has been set", ^{
+ testAlertView.timeout = 2.25;
+ expect(testAlertView.timeout).to(equal(3.0));
+ });
+
+ it(@"should return the set value if a value between 3 and 10 has been set", ^{
+ testAlertView.timeout = 9.5;
+ expect(testAlertView.timeout).to(equal(9.5));
+ });
+ });
+
+ describe(@"canceling the alert", ^{
+ __block SDLAlertView *testAlertView = nil;
+ __block BOOL canceledHandlerCalled = NO;
+
+ context(@"the cancel handler is set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.canceledHandler = ^{
+ canceledHandlerCalled = YES;
+ };
+ });
+
+ it(@"should call the cancelled handler", ^{
+ [testAlertView cancel];
+ expect(canceledHandlerCalled).to(beTrue());
+ });
+ });
+
+ context(@"the cancel handler is not set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.canceledHandler = nil;
+ });
+
+ it(@"should not crash", ^{
+ [testAlertView cancel];
+ });
+ });
+ });
+
+ describe(@"copying the alert", ^{
+ __block SDLAlertView *testAlertView = nil;
+ __block SDLAlertView *copiedTestAlertView = nil;
+
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:testTextField1 secondaryText:testTextField2 tertiaryText:testTextField3 timeout:@(testTimeout) showWaitIndicator:@(testShowWaitIndicator) audioIndication:testAudio buttons:testSoftButtons icon:testIcon];
+ testAlertView.canceledHandler = ^{};
+ copiedTestAlertView = [testAlertView copy];
+ });
+
+ it(@"should correctly copy the alert view", ^{
+ expect(testAlertView == copiedTestAlertView).to(beFalse());
+
+ expect(copiedTestAlertView.text).to(equal(testAlertView.text));
+ expect(copiedTestAlertView.secondaryText).to(equal(testAlertView.secondaryText));
+ expect(copiedTestAlertView.tertiaryText).to(equal(testAlertView.tertiaryText));
+ expect(copiedTestAlertView.timeout).to(equal(testAlertView.timeout));
+
+ expect(copiedTestAlertView.audio == testAlertView.audio).to(beFalse());
+ expect(copiedTestAlertView.audio.audioData).to(haveCount(1));
+ expect(copiedTestAlertView.audio.audioData[0]).to(equal(testAlertView.audio.audioData[0]));
+ expect(copiedTestAlertView.audio.playTone).to(equal(testAlertView.audio.playTone));
+
+ expect(copiedTestAlertView.showWaitIndicator).to(equal(testAlertView.showWaitIndicator));
+ expect(copiedTestAlertView.softButtons).to(equal(testAlertView.softButtons));
+
+ expect(copiedTestAlertView.icon == testAlertView.icon).to(beFalse());
+ expect(copiedTestAlertView.icon.name).to(equal(testAlertView.icon.name));
+
+ expect((id)copiedTestAlertView.canceledHandler).to(equal((id)testAlertView.canceledHandler));
+ });
+
+ it(@"Should not update the copy if changes are made to the original", ^{
+ testAlertView.text = @"changedText";
+ testAlertView.secondaryText = @"changedSecondaryText";
+ testAlertView.tertiaryText = @"changedTertiaryText";
+ testAlertView.timeout = 45;
+ testAlertView.audio = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"changedAudio"];
+ testAlertView.showWaitIndicator = YES;
+ testAlertView.softButtons = @[];
+ testAlertView.icon = testIcon2;
+ testAlertView.canceledHandler = ^{};
+
+ expect(copiedTestAlertView.text).toNot(equal(testAlertView.text));
+ expect(copiedTestAlertView.secondaryText).toNot(equal(testAlertView.secondaryText));
+ expect(copiedTestAlertView.tertiaryText).toNot(equal(testAlertView.tertiaryText));
+ expect(copiedTestAlertView.timeout).toNot(equal(testAlertView.timeout));
+ expect(copiedTestAlertView.audio).toNot(equal(testAlertView.audio));
+ expect(copiedTestAlertView.showWaitIndicator).toNot(equal(testAlertView.showWaitIndicator));
+ expect(copiedTestAlertView.softButtons).to(haveCount(1));
+ expect(copiedTestAlertView.softButtons).toNot(equal(testAlertView.softButtons));
+ expect(copiedTestAlertView.icon).toNot(equal(testAlertView.icon));
+ expect((id)copiedTestAlertView.canceledHandler).toNot(equal((id)testAlertView.canceledHandler));
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLAudioDataSpec.m b/SmartDeviceLinkTests/SDLAudioDataSpec.m
new file mode 100644
index 000000000..74d46a063
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLAudioDataSpec.m
@@ -0,0 +1,301 @@
+//
+// SDLAudioDataSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 11/9/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLAudioData.h"
+#import "SDLFile.h"
+#import "SDLFileManagerConstants.h"
+#import "SDLTTSChunk.h"
+
+@interface SDLAudioData()
+
+@property (nullable, copy, nonatomic, readonly) NSDictionary<SDLFileName *, SDLFile *> *audioFileData;
+
+@end
+
+QuickSpecBegin(SDLAudioDataSpec)
+
+describe(@"SDLAudioData", ^{
+ __block NSString *testSpeechSynthesizerString = nil;
+ __block SDLFile *testAudioFile1 = nil;
+ __block SDLFile *testAudioFile2 = nil;
+ __block SDLFile *testAudioFile3 = nil;
+
+ beforeEach(^{
+ testSpeechSynthesizerString = @"testSpeechSynthesizerString";
+
+ NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
+ testAudioFile1 = [[SDLFile alloc] initWithFileURL:[testBundle URLForResource:@"testAudio" withExtension:@"mp3"] name:@"testAudioFile1" persistent:YES];
+ testAudioFile2 = [[SDLFile alloc] initWithFileURL:[testBundle URLForResource:@"testAudio" withExtension:@"mp3"] name:@"testAudioFile2" persistent:YES];
+ testAudioFile3 = [[SDLFile alloc] initWithFileURL:[testBundle URLForResource:@"testAudio" withExtension:@"mp3"] name:@"testAudioFile3" persistent:YES];
+ });
+
+ describe(@"Initialization", ^{
+ it(@"Should get correctly when initialized with initWithAudioFile:", ^{
+ SDLAudioData *testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ });
+
+ it(@"Should get correctly when initialized with initWithSpeechSynthesizerString:", ^{
+ SDLAudioData *testAudioData = [[SDLAudioData alloc] initWithSpeechSynthesizerString:testSpeechSynthesizerString];
+
+ expect(testAudioData.audioFileData).to(beEmpty());
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testSpeechSynthesizerString));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesText));
+ });
+
+ it(@"Should get correctly when initialized with initWithPhoneticSpeechSynthesizerString:phoneticType:", ^{
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesLHPlusPhonemes;
+ SDLAudioData *testAudioData = [[SDLAudioData alloc] initWithPhoneticSpeechSynthesizerString:testSpeechSynthesizerString phoneticType:testSpeechCapabilities];
+
+ expect(testAudioData.audioFileData).to(beEmpty());
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testSpeechSynthesizerString));
+ expect(testAudioData.audioData[0].type).to(equal(testSpeechCapabilities));
+ });
+
+ it(@"Should fail if initialized with an invalid phoneticType in initWithPhoneticSpeechSynthesizerString:phoneticType:", ^{
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesSilence;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-value"
+ expectAction(^{ [[SDLAudioData alloc] initWithPhoneticSpeechSynthesizerString:testSpeechSynthesizerString phoneticType:testSpeechCapabilities]; }).to(raiseException().named(@"InvalidTTSSpeechCapabilities"));
+#pragma clang diagnostic pop
+ });
+ });
+
+ describe(@"Adding additional audio data", ^{
+ __block SDLAudioData *testAudioData = nil;
+ __block NSString *testSpeechSynthesizerString1 = @"testSpeechSynthesizerString1";
+ __block NSString *testSpeechSynthesizerString2 = @"testSpeechSynthesizerString2";
+ __block NSString *testSpeechSynthesizerString3 = @"testSpeechSynthesizerString3";
+ __block NSString *testEmptySpeechSynthesizerString = @"";
+
+ context(@"If adding audio files", ^{
+ it(@"Should append the audio file data to the current existing lists if the first added item was an audio file", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addAudioFiles:@[testAudioFile2, testAudioFile3]];
+
+ expect(testAudioData.audioData).to(haveCount(3));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[1].text).to(equal(testAudioFile2.name));
+ expect(testAudioData.audioData[2].text).to(equal(testAudioFile3.name));
+
+ expect(testAudioData.audioFileData).to(haveCount(3));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+ expect(testAudioData.audioFileData[testAudioFile2.name]).to(equal(testAudioFile2));
+ expect(testAudioData.audioFileData[testAudioFile3.name]).to(equal(testAudioFile3));
+ });
+
+ it(@"Should append the audio file data to the current existing lists if the first added item was a prompt", ^{
+ testAudioData = [[SDLAudioData alloc] initWithSpeechSynthesizerString:testSpeechSynthesizerString];
+ [testAudioData addAudioFiles:@[testAudioFile1]];
+
+ expect(testAudioData.audioData).to(haveCount(2));
+ expect(testAudioData.audioData[0].text).to(equal(testSpeechSynthesizerString));
+ expect(testAudioData.audioData[1].text).to(equal(testAudioFile1.name));
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+ });
+
+ it(@"Should replace audio file data with duplicate file names", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addAudioFiles:@[testAudioFile1, testAudioFile2, testAudioFile2]];
+
+ expect(testAudioData.audioData).to(haveCount(4));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[1].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[2].text).to(equal(testAudioFile2.name));
+ expect(testAudioData.audioData[3].text).to(equal(testAudioFile2.name));
+
+ expect(testAudioData.audioFileData).to(haveCount(2));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+ expect(testAudioData.audioFileData[testAudioFile2.name]).to(equal(testAudioFile2));
+ });
+ });
+
+ context(@"If adding speech synthesizer strings", ^{
+ it(@"Should append the additional speech synthesizer strings to the existing audio data", ^{
+ testAudioData = [[SDLAudioData alloc] initWithSpeechSynthesizerString:testSpeechSynthesizerString1];
+ [testAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString2, testSpeechSynthesizerString3]];
+
+ expect(testAudioData.audioFileData).to(beEmpty());
+
+ expect(testAudioData.audioData).to(haveCount(3));
+ expect(testAudioData.audioData[0].text).to(equal(testSpeechSynthesizerString1));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesText));
+ expect(testAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString2));
+ expect(testAudioData.audioData[1].type).to(equal(SDLSpeechCapabilitiesText));
+ expect(testAudioData.audioData[2].text).to(equal(testSpeechSynthesizerString3));
+ expect(testAudioData.audioData[2].type).to(equal(SDLSpeechCapabilitiesText));
+ });
+
+ it(@"Should not append any additional speech synthesizer strings that are empty", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString1, testEmptySpeechSynthesizerString, testSpeechSynthesizerString2]];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(3));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ expect(testAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString1));
+ expect(testAudioData.audioData[1].type).to(equal(SDLSpeechCapabilitiesText));
+ expect(testAudioData.audioData[2].text).to(equal(testSpeechSynthesizerString2));
+ expect(testAudioData.audioData[2].type).to(equal(SDLSpeechCapabilitiesText));
+ });
+
+ it(@"Should not append an array with only empty additional speech synthesizer strings", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addSpeechSynthesizerStrings:@[testEmptySpeechSynthesizerString]];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ });
+
+ it(@"Should not append an empty array of speech synthesizer strings", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addSpeechSynthesizerStrings:@[]];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ });
+ });
+
+ context(@"If adding phonetic speech synthesizer strings", ^{
+ it(@"Should append the additional phonetic speech synthesizer strings to the existing audio data", ^{
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesSAPIPhonemes;
+ testAudioData = [[SDLAudioData alloc] initWithPhoneticSpeechSynthesizerString:testSpeechSynthesizerString1 phoneticType:testSpeechCapabilities];
+ [testAudioData addPhoneticSpeechSynthesizerStrings:@[testSpeechSynthesizerString2] phoneticType:testSpeechCapabilities];
+
+ expect(testAudioData.audioFileData).to(beEmpty());
+
+ expect(testAudioData.audioData).to(haveCount(2));
+ expect(testAudioData.audioData[0].text).to(equal(testSpeechSynthesizerString1));
+ expect(testAudioData.audioData[0].type).to(equal(testSpeechCapabilities));
+ expect(testAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString2));
+ expect(testAudioData.audioData[1].type).to(equal(testSpeechCapabilities));
+ });
+
+ it(@"Should not append any additional phonetic speech synthesizer strings that are empty", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesText;
+ [testAudioData addPhoneticSpeechSynthesizerStrings:@[testSpeechSynthesizerString1, testSpeechSynthesizerString2, testEmptySpeechSynthesizerString] phoneticType:testSpeechCapabilities];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(3));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ expect(testAudioData.audioData[1].text).to(equal(testSpeechSynthesizerString1));
+ expect(testAudioData.audioData[1].type).to(equal(testSpeechCapabilities));
+ expect(testAudioData.audioData[2].text).to(equal(testSpeechSynthesizerString2));
+ expect(testAudioData.audioData[2].type).to(equal(testSpeechCapabilities));
+ });
+
+ it(@"Should not append an array with only empty additional phonetic speech synthesizer strings", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesText;
+ [testAudioData addPhoneticSpeechSynthesizerStrings:@[testEmptySpeechSynthesizerString] phoneticType:testSpeechCapabilities];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ });
+
+ it(@"Should not append an empty array of phonetic speech synthesizer strings", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesText;
+ [testAudioData addPhoneticSpeechSynthesizerStrings:@[] phoneticType:testSpeechCapabilities];
+
+ expect(testAudioData.audioFileData).to(haveCount(1));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+
+ expect(testAudioData.audioData).to(haveCount(1));
+ expect(testAudioData.audioData[0].text).to(equal(testAudioFile1.name));
+ expect(testAudioData.audioData[0].type).to(equal(SDLSpeechCapabilitiesFile));
+ });
+
+ it(@"Should not append additional phonetic speech synthesizer strings with an invalid phonetic type", ^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ SDLSpeechCapabilities testSpeechCapabilities = SDLSpeechCapabilitiesFile;
+
+ expectAction(^{ [testAudioData addPhoneticSpeechSynthesizerStrings:@[testSpeechSynthesizerString1] phoneticType:testSpeechCapabilities]; }).to(raiseException().named(@"InvalidTTSSpeechCapabilities"));
+ });
+ });
+ });
+
+ describe(@"Copying audio data", ^{
+ __block SDLAudioData *testAudioData = nil;
+ __block SDLAudioData *copiedTestAudioData = nil;
+ __block NSString *testSpeechSynthesizerString1 = @"testSpeechSynthesizerString1";
+ __block NSString *testSpeechSynthesizerString2 = @"testSpeechSynthesizerString2";
+ __block NSString *testSpeechSynthesizerString3 = @"testSpeechSynthesizerString3";
+
+ beforeEach(^{
+ testAudioData = [[SDLAudioData alloc] initWithAudioFile:testAudioFile1];
+ [testAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString1, testSpeechSynthesizerString2]];
+
+ copiedTestAudioData = [testAudioData copy];
+ });
+
+ it(@"Should copy correctly", ^{
+ expect(testAudioData == copiedTestAudioData).to(beFalse());
+ expect(testAudioData.audioData).to(equal(copiedTestAudioData.audioData));
+ expect(testAudioData.audioFileData).to(equal(copiedTestAudioData.audioFileData));
+ });
+
+ it(@"Should not update the copy if changes are made to the original", ^{
+ [testAudioData addSpeechSynthesizerStrings:@[testSpeechSynthesizerString3]];
+ [testAudioData addAudioFiles:@[testAudioFile2]];
+
+ expect(testAudioData.audioData).to(haveCount(5));
+ expect(testAudioData.audioData[0].text).to(contain(testAudioFile1.name));
+ expect(testAudioData.audioData[1].text).to(contain(testSpeechSynthesizerString1));
+ expect(testAudioData.audioData[2].text).to(contain(testSpeechSynthesizerString2));
+ expect(testAudioData.audioData[3].text).to(contain(testSpeechSynthesizerString3));
+ expect(testAudioData.audioData[4].text).to(contain(testAudioFile2.name));
+
+ expect(testAudioData.audioFileData).to(haveCount(2));
+ expect(testAudioData.audioFileData[testAudioFile1.name]).to(equal(testAudioFile1));
+ expect(testAudioData.audioFileData[testAudioFile2.name]).to(equal(testAudioFile2));
+
+ expect(copiedTestAudioData.audioData).to(haveCount(3));
+ expect(copiedTestAudioData.audioFileData).to(haveCount(1));
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLEncryptionLifecycleManagerSpec.m b/SmartDeviceLinkTests/SDLEncryptionLifecycleManagerSpec.m
index 15295118b..d1559b136 100644
--- a/SmartDeviceLinkTests/SDLEncryptionLifecycleManagerSpec.m
+++ b/SmartDeviceLinkTests/SDLEncryptionLifecycleManagerSpec.m
@@ -45,6 +45,7 @@ describe(@"the encryption lifecycle manager", ^{
beforeEach(^{
testConnectionManager = [[TestConnectionManager alloc] init];
+ testConnectionManager.systemInfo = [[SDLSystemInfo alloc] initWithMake:@"Make" model:@"Model" trim:@"Trim" modelYear:@"Model Year" softwareVersion:@"1.1.1.1" hardwareVersion:@"2.2.2.2"];
testFakeSecurityManager = [[SDLFakeSecurityManager alloc] init];
SDLEncryptionConfiguration *encryptionConfig = [[SDLEncryptionConfiguration alloc] initWithSecurityManagers:@[testFakeSecurityManager.class] delegate:nil];
@@ -63,122 +64,123 @@ describe(@"the encryption lifecycle manager", ^{
describe(@"when started", ^{
__block BOOL readyHandlerSuccess = NO;
__block NSError *readyHandlerError = nil;
-
__block SDLProtocol *protocolMock = OCMClassMock([SDLProtocol class]);
-
- beforeEach(^{
- readyHandlerSuccess = NO;
- readyHandlerError = nil;
-
- [encryptionLifecycleManager startWithProtocol:protocolMock];
- });
-
- it(@"should not be ready to encrypt", ^{
- expect(encryptionLifecycleManager.isEncryptionReady).to(beFalse());
- });
-
- describe(@"after receiving an RPC Start ACK", ^{
- __block SDLProtocolHeader *testRPCHeader = nil;
- __block SDLProtocolMessage *testRPCMessage = nil;
-
- beforeEach(^{
- [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStarting fromOldState:nil callEnterTransition:YES];
-
- testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testRPCHeader.frameType = SDLFrameTypeSingle;
- testRPCHeader.frameData = SDLFrameInfoStartServiceACK;
- testRPCHeader.encrypted = YES;
- testRPCHeader.serviceType = SDLServiceTypeRPC;
-
- testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
- [encryptionLifecycleManager protocol:protocolMock didReceiveStartServiceACK:testRPCMessage];
- });
-
- it(@"should have set all the right properties", ^{
- expect(encryptionLifecycleManager.isEncryptionReady).to(equal(YES));
- expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateReady));
- });
- });
-
- describe(@"after receiving an RPC Start NAK", ^{
- __block SDLProtocolHeader *testRPCHeader = nil;
- __block SDLProtocolMessage *testRPCMessage = nil;
-
+
+ context(@"when system info doesn't match", ^{
beforeEach(^{
- [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStarting fromOldState:nil callEnterTransition:NO];
-
- testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testRPCHeader.frameType = SDLFrameTypeSingle;
- testRPCHeader.frameData = SDLFrameInfoStartServiceNACK;
- testRPCHeader.encrypted = NO;
- testRPCHeader.serviceType = SDLServiceTypeRPC;
-
- testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
- [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceACK:testRPCMessage];
+ readyHandlerSuccess = NO;
+ readyHandlerError = nil;
+
+ [encryptionLifecycleManager startWithProtocol:protocolMock];
});
-
- it(@"should have set all the right properties", ^{
- expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+
+ it(@"should not be ready to encrypt", ^{
+ OCMVerify([protocolMock setSecurityManager:[OCMArg isNil]]);
+ expect(encryptionLifecycleManager.isEncryptionReady).to(beFalse());
});
});
-
- describe(@"after receiving a RPC end ACK", ^{
- __block SDLProtocolHeader *testRPCHeader = nil;
- __block SDLProtocolMessage *testRPCMessage = nil;
-
+
+ context(@"when security managers are available", ^{
beforeEach(^{
- [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStopped fromOldState:nil callEnterTransition:NO];
-
- testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testRPCHeader.frameType = SDLFrameTypeSingle;
- testRPCHeader.frameData = SDLFrameInfoEndServiceACK;
- testRPCHeader.encrypted = NO;
- testRPCHeader.serviceType = SDLServiceTypeRPC;
-
- testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
- [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceACK:testRPCMessage];
+ testConnectionManager.systemInfo.vehicleType.make = @"SDL";
+ readyHandlerSuccess = NO;
+ readyHandlerError = nil;
+
+ [encryptionLifecycleManager startWithProtocol:protocolMock];
});
-
- it(@"should have set all the right properties", ^{
- expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+
+ it(@"should not be ready to encrypt", ^{
+ OCMVerify([protocolMock setSecurityManager:[OCMArg isNotNil]]);
+ expect(encryptionLifecycleManager.isEncryptionReady).to(beFalse());
});
- });
-
- describe(@"after receiving a RPC end NAK", ^{
- __block SDLProtocolHeader *testRPCHeader = nil;
- __block SDLProtocolMessage *testRPCMessage = nil;
-
- beforeEach(^{
- [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStopped fromOldState:nil callEnterTransition:NO];
-
- testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
- testRPCHeader.frameType = SDLFrameTypeSingle;
- testRPCHeader.frameData = SDLFrameInfoEndServiceNACK;
- testRPCHeader.encrypted = NO;
- testRPCHeader.serviceType = SDLServiceTypeRPC;
-
- testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
- [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceNAK:testRPCMessage];
+
+ describe(@"after receiving an RPC Start ACK", ^{
+ __block SDLProtocolHeader *testRPCHeader = nil;
+ __block SDLProtocolMessage *testRPCMessage = nil;
+
+ beforeEach(^{
+ [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStarting fromOldState:nil callEnterTransition:YES];
+
+ testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testRPCHeader.frameType = SDLFrameTypeSingle;
+ testRPCHeader.frameData = SDLFrameInfoStartServiceACK;
+ testRPCHeader.encrypted = YES;
+ testRPCHeader.serviceType = SDLServiceTypeRPC;
+
+ testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
+ [encryptionLifecycleManager protocol:protocolMock didReceiveStartServiceACK:testRPCMessage];
+ });
+
+ it(@"should have set all the right properties", ^{
+ expect(encryptionLifecycleManager.isEncryptionReady).to(equal(YES));
+ expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateReady));
+ });
});
-
- it(@"should have set all the right properties", ^{
- expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+
+ describe(@"after receiving an RPC Start NAK", ^{
+ __block SDLProtocolHeader *testRPCHeader = nil;
+ __block SDLProtocolMessage *testRPCMessage = nil;
+
+ beforeEach(^{
+ [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStarting fromOldState:nil callEnterTransition:NO];
+
+ testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testRPCHeader.frameType = SDLFrameTypeSingle;
+ testRPCHeader.frameData = SDLFrameInfoStartServiceNACK;
+ testRPCHeader.encrypted = NO;
+ testRPCHeader.serviceType = SDLServiceTypeRPC;
+
+ testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
+ [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceACK:testRPCMessage];
+ });
+
+ it(@"should have set all the right properties", ^{
+ expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+ });
});
- });
- describe(@"when a register app interface response is received", ^{
- beforeEach(^{
- OCMExpect([protocolMock setSecurityManager:[OCMArg any]]);
+ describe(@"after receiving a RPC end ACK", ^{
+ __block SDLProtocolHeader *testRPCHeader = nil;
+ __block SDLProtocolMessage *testRPCMessage = nil;
+
+ beforeEach(^{
+ [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStopped fromOldState:nil callEnterTransition:NO];
+
+ testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testRPCHeader.frameType = SDLFrameTypeSingle;
+ testRPCHeader.frameData = SDLFrameInfoEndServiceACK;
+ testRPCHeader.encrypted = NO;
+ testRPCHeader.serviceType = SDLServiceTypeRPC;
- SDLRegisterAppInterfaceResponse *rair = [[SDLRegisterAppInterfaceResponse alloc] init];
- rair.vehicleType = [[SDLVehicleType alloc] init];
- rair.vehicleType.make = @"SDL";
- SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:nil rpcResponse:rair];
- [[NSNotificationCenter defaultCenter] postNotification:notification];
+ testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
+ [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceACK:testRPCMessage];
+ });
+
+ it(@"should have set all the right properties", ^{
+ expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+ });
});
- it(@"should set the protocol's security manager", ^{
- OCMVerifyAll((id)protocolMock);
+ describe(@"after receiving a RPC end NAK", ^{
+ __block SDLProtocolHeader *testRPCHeader = nil;
+ __block SDLProtocolMessage *testRPCMessage = nil;
+
+ beforeEach(^{
+ [encryptionLifecycleManager.encryptionStateMachine setToState:SDLEncryptionLifecycleManagerStateStopped fromOldState:nil callEnterTransition:NO];
+
+ testRPCHeader = [[SDLV2ProtocolHeader alloc] initWithVersion:5];
+ testRPCHeader.frameType = SDLFrameTypeSingle;
+ testRPCHeader.frameData = SDLFrameInfoEndServiceNACK;
+ testRPCHeader.encrypted = NO;
+ testRPCHeader.serviceType = SDLServiceTypeRPC;
+
+ testRPCMessage = [[SDLV2ProtocolMessage alloc] initWithHeader:testRPCHeader andPayload:nil];
+ [encryptionLifecycleManager protocol:protocolMock didReceiveEndServiceNAK:testRPCMessage];
+ });
+
+ it(@"should have set all the right properties", ^{
+ expect(encryptionLifecycleManager.encryptionStateMachine.currentState).to(equal(SDLEncryptionLifecycleManagerStateStopped));
+ });
});
});
});
diff --git a/SmartDeviceLinkTests/SDLMenuUpdateAlgorithmSpec.m b/SmartDeviceLinkTests/SDLMenuUpdateAlgorithmSpec.m
index 9c554c02c..63eb97f95 100644
--- a/SmartDeviceLinkTests/SDLMenuUpdateAlgorithmSpec.m
+++ b/SmartDeviceLinkTests/SDLMenuUpdateAlgorithmSpec.m
@@ -42,19 +42,19 @@ describe(@"menuUpdateAlgorithm", ^{
// 0 = Delete 1 = Add 2 = Keep
describe(@"compare old and new menu cells", ^{
beforeEach(^{
- oldCell1 = [[SDLMenuCell alloc] initWithTitle:@"Cell 1" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- oldCell2 = [[SDLMenuCell alloc] initWithTitle:@"Cell 2" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- oldCell3 = [[SDLMenuCell alloc] initWithTitle:@"Cell 3" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- oldCell4 = [[SDLMenuCell alloc] initWithTitle:@"Cell 4" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- oldCell5 = [[SDLMenuCell alloc] initWithTitle:@"Cell 5" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- oldCell6 = [[SDLMenuCell alloc] initWithTitle:@"Cell 6" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
-
- newCell1 = [[SDLMenuCell alloc] initWithTitle:@"Cell 1" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- newCell2 = [[SDLMenuCell alloc] initWithTitle:@"Cell 2" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- newCell3 = [[SDLMenuCell alloc] initWithTitle:@"Cell 3" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- newCell4 = [[SDLMenuCell alloc] initWithTitle:@"Cell 4" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- newCell5 = [[SDLMenuCell alloc] initWithTitle:@"Cell 5" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
- newCell6 = [[SDLMenuCell alloc] initWithTitle:@"Cell 6" icon:nil voiceCommands:nil secondaryText:nil tertiaryText:nil secondaryArtwork:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell1 = [[SDLMenuCell alloc] initWithTitle:@"Cell 1" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell2 = [[SDLMenuCell alloc] initWithTitle:@"Cell 2" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell3 = [[SDLMenuCell alloc] initWithTitle:@"Cell 3" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell4 = [[SDLMenuCell alloc] initWithTitle:@"Cell 4" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell5 = [[SDLMenuCell alloc] initWithTitle:@"Cell 5" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ oldCell6 = [[SDLMenuCell alloc] initWithTitle:@"Cell 6" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+
+ newCell1 = [[SDLMenuCell alloc] initWithTitle:@"Cell 1" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ newCell2 = [[SDLMenuCell alloc] initWithTitle:@"Cell 2" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ newCell3 = [[SDLMenuCell alloc] initWithTitle:@"Cell 3" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ newCell4 = [[SDLMenuCell alloc] initWithTitle:@"Cell 4" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ newCell5 = [[SDLMenuCell alloc] initWithTitle:@"Cell 5" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
+ newCell6 = [[SDLMenuCell alloc] initWithTitle:@"Cell 6" secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}];
});
it(@"should have a new menu status of 22221 and an old menu status of 2222 on best run", ^{
diff --git a/SmartDeviceLinkTests/SDLPresentAlertOperationSpec.m b/SmartDeviceLinkTests/SDLPresentAlertOperationSpec.m
new file mode 100644
index 000000000..e9395e86c
--- /dev/null
+++ b/SmartDeviceLinkTests/SDLPresentAlertOperationSpec.m
@@ -0,0 +1,1147 @@
+//
+// SDLPresentAlertOperationSpec.m
+// SmartDeviceLinkTests
+//
+// Created by Nicole on 11/18/20.
+// Copyright © 2020 smartdevicelink. All rights reserved.
+//
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import <OCMock/OCMock.h>
+
+#import "SDLAlert.h"
+#import "SDLAlertResponse.h"
+#import "SDLAlertView.h"
+#import "SDLAlertAudioData.h"
+#import "SDLCancelInteraction.h"
+#import "SDLCancelInteractionResponse.h"
+#import "SDLError.h"
+#import "SDLFileManager.h"
+#import "SDLFunctionID.h"
+#import "SDLGlobals.h"
+#import "SDLImage.h"
+#import "SDLPresentAlertOperation.h"
+#import "SDLPutFile.h"
+#import "SDLWindowCapability.h"
+#import "SDLSoftButton.h"
+#import "SDLSoftButtonCapabilities.h"
+#import "SDLSoftButtonObject.h"
+#import "SDLSoftButtonState.h"
+#import "SDLSystemCapabilityManager.h"
+#import "SDLTTSChunk.h"
+#import "SDLVersion.h"
+#import "SDLWindowCapability.h"
+#import "SDLWindowCapability+ScreenManagerExtensions.h"
+#import "TestConnectionManager.h"
+
+@interface SDLPresentAlertOperation()
+
+@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
+@property (weak, nonatomic) SDLFileManager *fileManager;
+@property (strong, nonatomic, readwrite) SDLAlertView *alertView;
+@property (assign, nonatomic) UInt16 cancelId;
+@property (copy, nonatomic, nullable) NSError *internalError;
+
+- (nullable NSError *)sdl_isValidAlertViewData:(SDLAlertView *)alertView;
+- (SDLAlert *)alertRPC;
+
+@end
+
+QuickSpecBegin(SDLPresentAlertOperationSpec)
+
+describe(@"SDLPresentAlertOperation", ^{
+ __block SDLPresentAlertOperation *testPresentAlertOperation = nil;
+ __block id mockConnectionManager = nil;
+ __block id mockFileManager = nil;
+ __block id mockSystemCapabilityManager = nil;
+ __block id mockCurrentWindowCapability = nil;
+ __block SDLAlertView *testAlertView = nil;
+ __block UInt16 testCancelID = 45;
+ __block BOOL hasCalledOperationCompletionHandler = NO;
+
+ __block SDLAlertAudioData *testAlertAudioData = nil;
+ __block SDLFile *testAudioFile = nil;
+ __block SDLAlertAudioData *testAlertAudioFileData = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton1 = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton2 = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton3 = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton4 = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton5 = nil;
+ __block SDLSoftButtonObject *testAlertSoftButton6 = nil;
+ __block SDLArtwork *testAlertIcon = nil;
+ __block SDLArtwork *testButton1Icon = nil;
+ __block SDLArtwork *testButton2Icon = nil;
+
+ __block SDLVersion *alertAudioFileSupportedSpecVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ __block SDLVersion *alertAudioFileNotSupportedSpecVersion = [SDLVersion versionWithMajor:4 minor:8 patch:0];
+
+ beforeEach(^{
+ mockConnectionManager = OCMProtocolMock(@protocol(SDLConnectionManagerType));
+ mockFileManager = OCMClassMock([SDLFileManager class]);
+ mockSystemCapabilityManager = OCMClassMock([SDLSystemCapabilityManager class]);
+ mockCurrentWindowCapability = OCMClassMock([SDLWindowCapability class]);
+
+ testAlertAudioData = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"test synthesizer string"];
+ NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
+ NSURL *testAudioFileURL = [testBundle URLForResource:@"testAudio" withExtension:@"mp3"];
+ NSString *testAudioFileName = @"testAudioFile";
+ testAudioFile = [[SDLFile alloc] initWithFileURL:testAudioFileURL name:testAudioFileName persistent:YES];
+ testAlertAudioFileData = [[SDLAlertAudioData alloc] initWithAudioFile:testAudioFile];
+
+ UIImage *testButton1Image = [[UIImage alloc] initWithContentsOfFile:[testBundle pathForResource:@"testImageJPEG" ofType:@"jpeg"]];
+ testButton1Icon = [SDLArtwork artworkWithImage:testButton1Image asImageFormat:SDLArtworkImageFormatJPG];
+ UIImage *testButton2Image = [[UIImage alloc] initWithContentsOfFile:[testBundle pathForResource:@"testImagePNG" ofType:@"png"]];
+ testButton2Icon = [SDLArtwork artworkWithImage:testButton2Image asImageFormat:SDLArtworkImageFormatPNG];
+
+ testAlertSoftButton1 = [[SDLSoftButtonObject alloc] initWithName:@"button1" text:@"button1" artwork:testButton1Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+ testAlertSoftButton2 = [[SDLSoftButtonObject alloc] initWithName:@"button2" text:@"button2" artwork:testButton2Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+ testAlertSoftButton3 = [[SDLSoftButtonObject alloc] initWithName:@"button3" text:@"button3" artwork:testButton2Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+ testAlertSoftButton4 = [[SDLSoftButtonObject alloc] initWithName:@"button4" text:@"button4" artwork:testButton2Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+ testAlertSoftButton5 = [[SDLSoftButtonObject alloc] initWithName:@"button5" text:@"button5" artwork:testButton2Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+ testAlertSoftButton6 = [[SDLSoftButtonObject alloc] initWithName:@"button6" text:@"button6" artwork:testButton2Icon handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) {}];
+
+ UIImage *testImage = [[UIImage alloc] initWithContentsOfFile:[testBundle pathForResource:@"testImageJPEG" ofType:@"jpeg"]];
+ testAlertIcon = [SDLArtwork artworkWithImage:testImage asImageFormat:SDLArtworkImageFormatPNG];
+
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ });
+
+ it(@"should be initialized correctly", ^{
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ expect(@(testPresentAlertOperation.queuePriority)).to(equal(@(NSOperationQueuePriorityNormal)));
+ expect(testPresentAlertOperation.connectionManager).to(equal(mockConnectionManager));
+ expect(testPresentAlertOperation.fileManager).to(equal(mockFileManager));
+ expect(testPresentAlertOperation.alertView).toNot(equal(testAlertView));
+ expect(@(testPresentAlertOperation.cancelId)).to(equal(@(testCancelID)));
+ expect(testPresentAlertOperation.currentWindowCapability).to(equal(mockCurrentWindowCapability));
+ expect(testPresentAlertOperation.internalError).to(beNil());
+ });
+
+ describe(@"creating the alert", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:6 minor:0 patch:0];
+ });
+
+ describe(@"setting the text fields", ^{
+ describe(@"with all three text fields set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set all textfields if all textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(equal(testAlertView.secondaryText));
+ expect(testAlert.alertText3).to(equal(testAlertView.tertiaryText));
+ });
+
+ it(@"should set textfields correctly if only two textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(equal([NSString stringWithFormat:@"%@ - %@", testAlertView.secondaryText, testAlertView.tertiaryText]));
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only one textfield is supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(1);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal([NSString stringWithFormat:@"%@ - %@ - %@", testAlertView.text, testAlertView.secondaryText, testAlertView.tertiaryText]));
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+ });
+
+ describe(@"with two text fields set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:nil timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set all textfields if all textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(equal(testAlertView.secondaryText));
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only two textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(equal(testAlertView.secondaryText));
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only one textfield is supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(1);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal([NSString stringWithFormat:@"%@ - %@", testAlertView.text, testAlertView.secondaryText]));
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+ });
+
+ describe(@"with one text field set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:nil tertiaryText:nil timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set all textfields if all textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only two textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only one textfield is supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(1);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+ });
+
+ describe(@"with no text fields set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:nil secondaryText:nil tertiaryText:nil timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set all textfields if all textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(beNil());
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only two textfields are supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(beNil());
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+
+ it(@"should set textfields correctly if only one textfield is supported", ^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(1);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(beNil());
+ expect(testAlert.alertText2).to(beNil());
+ expect(testAlert.alertText3).to(beNil());
+ });
+ });
+
+ describe(@"with a nil currentWindowCapability", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:nil alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should assume all textfields are supported", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertText1).to(equal(testAlertView.text));
+ expect(testAlert.alertText2).to(equal(testAlertView.secondaryText));
+ expect(testAlert.alertText3).to(equal(testAlertView.tertiaryText));
+ });
+ });
+ });
+
+ describe(@"setting the audio data", ^{
+ context(@"only audio prompts set", ^{
+ beforeEach(^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+
+ SDLAlertAudioData *audioData = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"test synthesizer string"];
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:audioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set the tts chunks correctly", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks.count).to(equal(1));
+ expect(testAlert.ttsChunks[0].text).to(equal(testAlertView.audio.audioData.firstObject.text));
+ });
+ });
+
+ context(@"only audio file data set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioFileData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ context(@"the negotiated RPC spec version does not support the audio file feature", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileNotSupportedSpecVersion;
+ });
+
+ it(@"should set the `ttsChunks` to nil (and not an empty array) if only an audio file was set", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks).to(beNil());
+ });
+ });
+
+ context(@"the negotiated RPC spec version supports the audio file feature", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileSupportedSpecVersion;
+ });
+
+ context(@"the module does not support the speech capability of type `file`", ^{
+ beforeEach(^{
+ OCMStub([mockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesSilence]));
+ });
+
+ it(@"should set the `ttsChunks` to nil (and not an empty array) if only an audio file was set", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks).to(beNil());
+ });
+ });
+
+ context(@"the module supports the speech capability of type `file`", ^{
+ beforeEach(^{
+ OCMStub([mockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesFile, SDLSpeechCapabilitiesText]));
+ });
+
+ it(@"should set the tts chunks correctly", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks.count).to(equal(1));
+ expect(testAlert.ttsChunks[0].text).to(equal(testAlertView.audio.audioData.firstObject.text));
+ });
+ });
+ });
+ });
+
+ context(@"both audio prompts and audio file data set", ^{
+ beforeEach(^{
+ SDLAlertAudioData *audioData = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"test synthesizer string"];
+ [audioData addAudioFiles:@[testAudioFile]];
+
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:audioData buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set the tts chunks correctly", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks.count).to(equal(2));
+ expect(testAlert.ttsChunks[0].text).to(equal(testAlertView.audio.audioData[0].text));
+ expect(testAlert.ttsChunks[1].text).to(equal(testAlertView.audio.audioData[1].text));
+ });
+ });
+
+ context(@"no audio data set", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:nil buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set the `ttsChunks` to nil (and not an empty array)", ^{
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.ttsChunks).to(beNil());
+ });
+ });
+ });
+
+ describe(@"setting the icon", ^{
+ beforeEach(^{
+ testAlertView = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:nil buttons:@[testAlertSoftButton1, testAlertSoftButton2] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ });
+
+ it(@"should set the image if icons are supported on the module", ^{
+ OCMStub([mockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertIcon.value).to(equal(testAlertView.icon.name));
+ });
+
+ it(@"should not set the image if icons are not supported on the module", ^{
+ OCMStub([mockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(NO);
+ SDLAlert *testAlert = testPresentAlertOperation.alertRPC;
+ expect(testAlert.alertIcon).to(beNil());
+ });
+ });
+ });
+
+ describe(@"uploading", ^{
+ __block id strictMockFileManager = nil;
+ __block id strictMockSystemCapabilityManager = nil;
+ __block id strictMockCurrentWindowCapability = nil;
+
+ beforeEach(^{
+ strictMockFileManager = OCMStrictClassMock([SDLFileManager class]);
+ strictMockSystemCapabilityManager = OCMStrictClassMock([SDLSystemCapabilityManager class]);
+ strictMockCurrentWindowCapability = OCMStrictClassMock([SDLWindowCapability class]);
+ });
+
+ describe(@"audio files", ^{
+ beforeEach(^{
+ testAlertView.audio = testAlertAudioFileData;
+ testAlertView.softButtons = @[];
+ testAlertView.icon = nil;
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ OCMStub([strictMockFileManager fileNeedsUpload:nil]).andReturn(NO);
+ OCMStub([strictMockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ });
+
+ context(@"the negotiated RPC spec version does not support the audio file feature", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileNotSupportedSpecVersion;
+ OCMStub([strictMockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesFile, SDLSpeechCapabilitiesText]));
+ });
+
+ it(@"should not attempt to upload audio files", ^{
+ OCMReject([strictMockFileManager fileNeedsUpload:testAudioFile]);
+ OCMReject([strictMockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg any] completionHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+ });
+
+ context(@"the negotiated RPC spec version supports the audio file feature", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileSupportedSpecVersion;
+ });
+
+ context(@"the module does not support the speech capability of type `file`", ^{
+ beforeEach(^{
+ OCMStub([strictMockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesText]));
+ });
+
+ it(@"should not attempt to upload audio files", ^{
+ OCMReject([strictMockFileManager fileNeedsUpload:testAudioFile]);
+ OCMReject([strictMockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg any] completionHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+ });
+
+ context(@"the module supports the speech capability of type `file`", ^{
+ beforeEach(^{
+ OCMStub([strictMockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesText, SDLSpeechCapabilitiesFile]));
+ });
+
+ it(@"should not upload the audio file if it has already been uploaded", ^{
+ OCMExpect([strictMockFileManager fileNeedsUpload:testAudioFile]).andReturn(NO);
+ OCMReject([strictMockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg any] completionHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should upload the audio file if it has not yet been uploaded", ^{
+ OCMExpect([strictMockFileManager fileNeedsUpload:testAudioFile]).andReturn(YES);
+ OCMExpect([strictMockFileManager uploadFiles:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLPutFile *> *files = (NSArray<SDLPutFile *> *)value;
+ expect(files.count).to(equal(1));
+ expect(files.firstObject.name).to(equal(testAlertAudioFileData.audioData.firstObject.text));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should re-upload an audio file if `overwrite` has been set to true", ^{
+ testAudioFile.overwrite = YES;
+ OCMStub([strictMockFileManager fileNeedsUpload:testAudioFile]).andReturn(YES);;
+ OCMExpect([strictMockFileManager uploadFiles:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLPutFile *> *files = (NSArray<SDLPutFile *> *)value;
+ expect(files.count).to(equal(1));
+ expect(files.firstObject.name).to(equal(testAlertAudioFileData.audioData.firstObject.text));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+ });
+ });
+ });
+
+ describe(@"image files", ^{
+ beforeEach(^{
+ OCMStub([strictMockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(2);
+ OCMStub([strictMockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesFile, SDLSpeechCapabilitiesText]));
+ });
+
+ it(@"should upload the alert icons and soft button images if they are supported on the module", ^{
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @YES;
+ OCMStub([strictMockCurrentWindowCapability softButtonCapabilities]).andReturn((@[testSoftButtonCapabilities]));
+ OCMStub([strictMockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+
+ OCMExpect([strictMockFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLArtwork *> *files = (NSArray<SDLArtwork *> *)value;
+ expect(files.count).to(equal(3));
+ expect(files[0].name).to(equal(testAlertView.icon.name));
+ expect(files[1].name).to(equal(testAlertView.softButtons[0].currentState.artwork.name));
+ expect(files[2].name).to(equal(testAlertView.softButtons[1].currentState.artwork.name));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should only upload a max of 4 soft button images if soft button images supported on the module", ^{
+ SDLAlertView *testAlertViewWithExtraSoftButtons = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2, testAlertSoftButton3, testAlertSoftButton4, testAlertSoftButton5, testAlertSoftButton6] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertViewWithExtraSoftButtons cancelID:testCancelID];
+
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @YES;
+ OCMStub([strictMockCurrentWindowCapability softButtonCapabilities]).andReturn((@[testSoftButtonCapabilities]));
+ OCMStub([strictMockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+
+ OCMExpect([strictMockFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLArtwork *> *files = (NSArray<SDLArtwork *> *)value;
+ expect(files).to(haveCount(5));
+ expect(files[0].name).to(equal(testAlertViewWithExtraSoftButtons.icon.name));
+ expect(files[1].name).to(equal(testAlertViewWithExtraSoftButtons.softButtons[0].currentState.artwork.name));
+ expect(files[2].name).to(equal(testAlertViewWithExtraSoftButtons.softButtons[1].currentState.artwork.name));
+ expect(files[3].name).to(equal(testAlertViewWithExtraSoftButtons.softButtons[2].currentState.artwork.name));
+ expect(files[4].name).to(equal(testAlertViewWithExtraSoftButtons.softButtons[3].currentState.artwork.name));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should not upload the soft button images if soft button images are not supported on the module", ^{
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @(NO);
+ OCMStub([strictMockCurrentWindowCapability softButtonCapabilities]).andReturn(@[testSoftButtonCapabilities]);
+ OCMStub([strictMockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+
+ OCMExpect([strictMockFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLArtwork *> *files = (NSArray<SDLArtwork *> *)value;
+ expect(files.count).to(equal(1));
+ expect(files[0].name).to(equal(testAlertView.icon.name));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should upload the alert icon if the alert icon is not supported on the module", ^{
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(NO);
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @(YES);
+ OCMStub([strictMockCurrentWindowCapability softButtonCapabilities]).andReturn((@[testSoftButtonCapabilities]));
+ OCMStub([strictMockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+
+ OCMExpect([strictMockFileManager uploadArtworks:[OCMArg checkWithBlock:^BOOL(id value) {
+ NSArray<SDLArtwork *> *files = (NSArray<SDLArtwork *> *)value;
+ expect(files.count).to(equal(2));
+ expect(files[0].name).to(equal(testAlertView.softButtons[0].currentState.artwork.name));
+ expect(files[1].name).to(equal(testAlertView.softButtons[1].currentState.artwork.name));
+ return [value isKindOfClass:[NSArray class]];
+ }] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+
+ it(@"should not upload any images if the alert icon and soft button graphics are not supported on the module", ^{
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:strictMockFileManager systemCapabilityManager:strictMockSystemCapabilityManager currentWindowCapability:strictMockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ OCMStub([strictMockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(NO);
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @NO;
+ OCMStub([strictMockCurrentWindowCapability softButtonCapabilities]).andReturn(@[testSoftButtonCapabilities]);
+ OCMStub([strictMockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+
+ OCMReject([strictMockFileManager uploadArtworks:[OCMArg any] progressHandler:[OCMArg any] completionHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAll(strictMockFileManager);
+ OCMVerifyAll(strictMockSystemCapabilityManager);
+ OCMVerifyAll(strictMockCurrentWindowCapability);
+ });
+ });
+ });
+
+ describe(@"presenting the alert", ^{
+ describe(@"checking if alert data is valid", ^{
+ context(@"the module does not support audio data uploads", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileSupportedSpecVersion;
+ });
+
+ it(@"should be valid if at least the first text field was set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.text = @"test text";
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ NSError *testAlertValidError = [testPresentAlertOperation sdl_isValidAlertViewData:testAlertView];
+ expect(testAlertValidError).to(beNil());
+ });
+
+ it(@"should be valid if at least the second text field was set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.secondaryText = @"test text";
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ NSError *testAlertValidError = [testPresentAlertOperation sdl_isValidAlertViewData:testAlertView];
+ expect(testAlertValidError).to(beNil());
+ });
+
+ it(@"should be valid if at least the audio data was set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.audio = [[SDLAlertAudioData alloc] initWithSpeechSynthesizerString:@"test audio"];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ NSError *testAlertValidError = [testPresentAlertOperation sdl_isValidAlertViewData:testAlertView];
+ expect(testAlertValidError).to(beNil());
+ });
+
+ it(@"should be invalid if the first two text fields or the audio data was not set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.tertiaryText = @"test text";
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ NSError *testAlertValidError = [testPresentAlertOperation sdl_isValidAlertViewData:testAlertView];
+ expect(testAlertValidError).to(equal([NSError sdl_alertManager_alertDataInvalid]));
+ });
+ });
+
+ context(@"the module does not support audio data uploads", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileNotSupportedSpecVersion;
+ });
+
+ it(@"should be invalid if only audio data was set but audio data is not supported on the module", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.audio = [[SDLAlertAudioData alloc] initWithAudioFile:testAudioFile];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ NSError *testAlertValidError = [testPresentAlertOperation sdl_isValidAlertViewData:testAlertView];
+ expect(testAlertValidError).to(equal([NSError sdl_alertManager_alertAudioFileNotSupported]));
+ });
+ });
+ });
+
+ context(@"with invalid data", ^{
+ context(@"the module supports audio data uploads", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileSupportedSpecVersion;
+ });
+
+ it(@"should return an error if invalid data was set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.tertiaryText = @"test text";
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError).to(equal([NSError sdl_alertManager_alertDataInvalid]));
+ expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+ });
+ });
+
+ context(@"the module does not support audio data uploads", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = alertAudioFileNotSupportedSpecVersion;
+ });
+
+ it(@"should return an error if valid audio data was set but the module does not support audio files", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.audio = [[SDLAlertAudioData alloc] initWithAudioFile:testAudioFile];
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError).to(equal([NSError sdl_alertManager_alertAudioFileNotSupported]));
+ expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+ });
+
+ it(@"should return an error if invalid data was set", ^{
+ testAlertView = [[SDLAlertView alloc] init];
+ testAlertView.tertiaryText = @"test text";
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError).to(equal([NSError sdl_alertManager_alertDataInvalid]));
+ expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+ });
+ });
+ });
+
+ context(@"with too many soft buttons", ^{
+ __block SDLAlertView *testAlertViewWithExtraSoftButtons = nil;
+
+ beforeEach(^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ OCMStub([mockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ OCMStub([mockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesText, SDLSpeechCapabilitiesFile]));;
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @YES;
+ OCMStub([mockCurrentWindowCapability softButtonCapabilities]).andReturn(@[testSoftButtonCapabilities]);
+ OCMStub([mockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(NO);
+ OCMStub([mockFileManager uploadArtworks:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+ OCMStub([mockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ SDLVersion *supportedVersion = [SDLVersion versionWithMajor:6 minor:3 patch:0];
+ id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]);
+ OCMStub([globalMock rpcVersion]).andReturn(supportedVersion);
+
+ testAlertViewWithExtraSoftButtons = [[SDLAlertView alloc] initWithText:@"text" secondaryText:@"secondaryText" tertiaryText:@"tertiaryText" timeout:@(4) showWaitIndicator:@(YES) audioIndication:testAlertAudioData buttons:@[testAlertSoftButton1, testAlertSoftButton2, testAlertSoftButton3, testAlertSoftButton4, testAlertSoftButton5, testAlertSoftButton6] icon:testAlertIcon];
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertViewWithExtraSoftButtons cancelID:testCancelID];
+
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+ });
+
+ it(@"should send the alert but only allow 4 soft buttons to be sent", ^{
+ OCMExpect([mockConnectionManager sendConnectionRequest:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLAlert *alertRequest = (SDLAlert *)value;
+ expect(alertRequest.alertText1).to(equal(testAlertView.text));
+ expect(alertRequest.alertText2).to(equal(testAlertView.secondaryText));
+ expect(alertRequest.alertText3).to(equal(testAlertView.tertiaryText));
+ expect(alertRequest.ttsChunks.count).to(equal(1));
+ expect(alertRequest.ttsChunks[0].text).to(equal(testAlertView.audio.audioData.firstObject.text));
+ expect(alertRequest.duration).to(equal(testAlertView.timeout * 1000));
+ expect(alertRequest.playTone).to(equal(testAlertView.audio.playTone));
+ expect(alertRequest.progressIndicator).to(equal(testAlertView.showWaitIndicator));
+ expect(alertRequest.softButtons.count).to(equal(4));
+ expect(alertRequest.softButtons[0].text).to(equal(testAlertViewWithExtraSoftButtons.softButtons[0].currentState.text));
+ expect(alertRequest.softButtons[1].text).to(equal(testAlertViewWithExtraSoftButtons.softButtons[1].currentState.text));
+ expect(alertRequest.softButtons[2].text).to(equal(testAlertViewWithExtraSoftButtons.softButtons[2].currentState.text));
+ expect(alertRequest.softButtons[3].text).to(equal(testAlertViewWithExtraSoftButtons.softButtons[3].currentState.text));
+ expect(alertRequest.softButtons[0].softButtonID).to(equal(10));
+ expect(alertRequest.softButtons[1].softButtonID).to(equal(11));
+ expect(alertRequest.softButtons[2].softButtonID).to(equal(12));
+ expect(alertRequest.softButtons[3].softButtonID).to(equal(13));
+
+ expect(alertRequest.cancelID).to(equal(testCancelID));
+ expect(alertRequest.alertIcon.value).to(equal(testAlertView.icon.name));
+ return [value isKindOfClass:[SDLAlert class]];
+ }] withResponseHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(mockConnectionManager, 1.0);
+ });
+ });
+
+ context(@"with a failed alert icon upload", ^{
+ beforeEach(^{
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ OCMStub([mockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ OCMStub([mockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesText, SDLSpeechCapabilitiesFile]));;
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @YES;
+ OCMStub([mockCurrentWindowCapability softButtonCapabilities]).andReturn(@[testSoftButtonCapabilities]);
+ OCMStub([mockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(YES);
+ OCMStub([mockFileManager uploadArtworks:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:([OCMArg invokeBlockWithArgs: @[testAlertView.icon.name], [NSNull null], nil])]);
+ OCMStub([mockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ SDLVersion *supportedVersion = [SDLVersion versionWithMajor:6 minor:3 patch:0];
+ id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]);
+ OCMStub([globalMock rpcVersion]).andReturn(supportedVersion);
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+ });
+
+ it(@"should send the alert but not set the SDLImage for icon", ^{
+ OCMExpect([mockConnectionManager sendConnectionRequest:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLAlert *alertRequest = (SDLAlert *)value;
+ expect(alertRequest.alertText1).to(equal(testAlertView.text));
+ expect(alertRequest.alertText2).to(equal(testAlertView.secondaryText));
+ expect(alertRequest.alertText3).to(equal(testAlertView.tertiaryText));
+ expect(alertRequest.ttsChunks.count).to(equal(1));
+ expect(alertRequest.ttsChunks[0].text).to(equal(testAlertView.audio.audioData.firstObject.text));
+ expect(alertRequest.duration).to(equal(testAlertView.timeout * 1000));
+ expect(alertRequest.playTone).to(equal(testAlertView.audio.playTone));
+ expect(alertRequest.progressIndicator).to(equal(testAlertView.showWaitIndicator));
+ expect(alertRequest.softButtons.count).to(equal(2));
+ expect(alertRequest.softButtons[0].text).to(equal(testAlertView.softButtons[0].currentState.text));
+ expect(alertRequest.softButtons[1].text).to(equal(testAlertView.softButtons[1].currentState.text));
+ expect(alertRequest.softButtons[0].softButtonID).to(equal(10));
+ expect(alertRequest.softButtons[1].softButtonID).to(equal(11));
+ expect(alertRequest.cancelID).to(equal(testCancelID));
+ expect(alertRequest.alertIcon).to(beNil());
+ return [value isKindOfClass:[SDLAlert class]];
+ }] withResponseHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(mockConnectionManager, 0.5);
+ });
+ });
+
+ context(@"with valid data", ^{
+ __block id strictMockConnectionManager = nil;
+
+ beforeEach(^{
+ strictMockConnectionManager = OCMStrictProtocolMock(@protocol(SDLConnectionManagerType));
+
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+ OCMStub([mockCurrentWindowCapability hasImageFieldOfName:SDLImageFieldNameAlertIcon]).andReturn(YES);
+ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithMajor:5 minor:0 patch:0];
+ OCMStub([mockSystemCapabilityManager speechCapabilities]).andReturn((@[SDLSpeechCapabilitiesText, SDLSpeechCapabilitiesFile]));;
+ SDLSoftButtonCapabilities *testSoftButtonCapabilities = [[SDLSoftButtonCapabilities alloc] init];
+ testSoftButtonCapabilities.imageSupported = @YES;
+ OCMStub([mockCurrentWindowCapability softButtonCapabilities]).andReturn(@[testSoftButtonCapabilities]);
+ OCMStub([mockFileManager fileNeedsUpload:[OCMArg any]]).andReturn(NO);
+ OCMStub([mockFileManager uploadArtworks:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+ OCMStub([mockFileManager uploadFiles:[OCMArg any] progressHandler:[OCMArg invokeBlock] completionHandler:[OCMArg invokeBlock]]);
+
+ SDLVersion *supportedVersion = [SDLVersion versionWithMajor:6 minor:3 patch:0];
+ id globalMock = OCMPartialMock([SDLGlobals sharedGlobals]);
+ OCMStub([globalMock rpcVersion]).andReturn(supportedVersion);
+
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:strictMockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testAlertView cancelID:testCancelID];
+
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+ });
+
+ it(@"should send the alert if the operation has not been cancelled", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLAlert *alertRequest = (SDLAlert *)value;
+ expect(alertRequest.alertText1).to(equal(testAlertView.text));
+ expect(alertRequest.alertText2).to(equal(testAlertView.secondaryText));
+ expect(alertRequest.alertText3).to(equal(testAlertView.tertiaryText));
+ expect(alertRequest.ttsChunks.count).to(equal(1));
+ expect(alertRequest.ttsChunks[0].text).to(equal(testAlertView.audio.audioData.firstObject.text));
+ expect(alertRequest.duration).to(equal(testAlertView.timeout * 1000));
+ expect(alertRequest.playTone).to(equal(testAlertView.audio.playTone));
+ expect(alertRequest.progressIndicator).to(equal(testAlertView.showWaitIndicator));
+ expect(alertRequest.softButtons.count).to(equal(2));
+ expect(alertRequest.softButtons[0].text).to(equal(testAlertView.softButtons[0].currentState.text));
+ expect(alertRequest.softButtons[1].text).to(equal(testAlertView.softButtons[1].currentState.text));
+ expect(alertRequest.softButtons[0].softButtonID).to(equal(10));
+ expect(alertRequest.softButtons[1].softButtonID).to(equal(11));
+ expect(alertRequest.cancelID).to(equal(testCancelID));
+ expect(alertRequest.alertIcon.value).to(equal(testAlertView.icon.name));
+ return [value isKindOfClass:[SDLAlert class]];
+ }] withResponseHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ it(@"should not send the alert if the operation has been cancelled", ^{
+ [testPresentAlertOperation cancel];
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError).to(beNil());
+ expect(hasCalledOperationCompletionHandler).to(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ describe(@"Getting a response from the module", ^{
+ __block SDLAlertResponse *response = nil;
+
+ it(@"should call the completion handler and finish the operation after a successful alert response", ^{
+ response = [[SDLAlertResponse alloc] init];
+ response.tryAgainTime = nil;
+ response.success = @YES;
+ response.resultCode = SDLResultSuccess;
+
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], response, [NSNull null], nil])]);
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError).toEventually(beNil());
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ it(@"should save the error, call the completion handler and finish the operation after an unsuccessful alert response", ^{
+ response = [[SDLAlertResponse alloc] init];
+ response.tryAgainTime = @5;
+ response.success = @NO;
+ response.resultCode = SDLResultAborted;
+ NSError *defaultError = [NSError errorWithDomain:@"com.sdl.testConnectionManager" code:-1 userInfo:nil];
+
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], response, defaultError, nil])]);
+
+ [testPresentAlertOperation start];
+
+ expect(testPresentAlertOperation.internalError.userInfo[@"tryAgainTime"]).toEventually(equal(response.tryAgainTime));
+ expect(testPresentAlertOperation.internalError.userInfo[@"error"]).toEventually(equal(defaultError));
+ expect(hasCalledOperationCompletionHandler).toEventually(beTrue());
+ expect(testPresentAlertOperation.isFinished).toEventually(beTrue());
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+ });
+ });
+ });
+
+ describe(@"canceling the alert", ^{
+ __block SDLAlertView *testCancelAlertView = nil;
+ __block SDLVersion *cancelInteractionSupportedSpecVersion = [SDLVersion versionWithMajor:6 minor:0 patch:0];
+ __block SDLVersion *cancelInteractionNotSupportedSpecVersion = [SDLVersion versionWithMajor:5 minor:10 patch:0];
+ __block id strictMockConnectionManager = nil;
+
+ beforeEach(^{
+ testCancelAlertView = [[SDLAlertView alloc] init];
+ testCancelAlertView.text = @"Alert view to be canceled";
+
+ OCMStub([mockCurrentWindowCapability maxNumberOfAlertFieldLines]).andReturn(3);
+
+ strictMockConnectionManager = OCMStrictProtocolMock(@protocol(SDLConnectionManagerType));
+ testPresentAlertOperation = [[SDLPresentAlertOperation alloc] initWithConnectionManager:strictMockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager currentWindowCapability:mockCurrentWindowCapability alertView:testCancelAlertView cancelID:testCancelID];
+ testPresentAlertOperation.completionBlock = ^{
+ hasCalledOperationCompletionHandler = YES;
+ };
+ });
+
+ context(@"Module supports the CancelInteration RPC", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = cancelInteractionSupportedSpecVersion;
+ });
+
+ describe(@"If the operation is executing", ^{
+ it(@"should attempt to send a cancel interaction", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg checkWithBlock:^BOOL(id value) {
+ return [value isKindOfClass:[SDLAlert class]];
+ }] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ expect(testPresentAlertOperation.isExecuting).to(beTrue());
+ expect(testPresentAlertOperation.isFinished).to(beFalse());
+ expect(testPresentAlertOperation.isCancelled).to(beFalse());
+
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg checkWithBlock:^BOOL(id value) {
+ SDLCancelInteraction *cancelRequest = (SDLCancelInteraction *)value;
+ expect(cancelRequest).to(beAnInstanceOf([SDLCancelInteraction class]));
+ expect(cancelRequest.cancelID).to(equal(testCancelID));
+ expect(cancelRequest.functionID).to(equal([SDLFunctionID.sharedInstance functionIdForName:SDLRPCFunctionNameAlert]));
+ return [value isKindOfClass:[SDLCancelInteraction class]];
+ }] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ context(@"If the cancel interaction was successful", ^{
+ it(@"should not save an error", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+
+ SDLCancelInteractionResponse *testResponse = [[SDLCancelInteractionResponse alloc] init];
+ testResponse.success = @YES;
+ testResponse.resultCode = SDLResultSuccess;
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], testResponse, [NSNull null], nil])]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 1.0);
+ expect(testPresentAlertOperation.error).to(beNil());
+ });
+ });
+
+ context(@"If the cancel interaction was not successful", ^{
+ it(@"should save an error", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 1.0);
+
+ SDLCancelInteractionResponse *testResponse = [[SDLCancelInteractionResponse alloc] init];
+ testResponse.success = @NO;
+ testResponse.resultCode = SDLResultAborted;
+ NSError *defaultError = [NSError errorWithDomain:@"com.sdl.testConnectionManager" code:-1 userInfo:nil];
+
+ OCMStub([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:([OCMArg invokeBlockWithArgs:[OCMArg any], testResponse, defaultError, nil])]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 1.0);
+ expect(testPresentAlertOperation.error).to(equal(defaultError));
+ });
+ });
+ });
+
+ describe(@"If the operation has already finished", ^{
+ beforeEach(^{
+ [testPresentAlertOperation finishOperation];
+ });
+
+ it(@"should not attempt to send a cancel interaction", ^{
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+ });
+
+ describe(@"If the started operation has been canceled", ^{
+ it(@"should not attempt to send a cancel interaction", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+
+ [testPresentAlertOperation cancel];
+
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+ });
+
+ context(@"If the operation has not started", ^{
+ it(@"should not attempt to send a cancel interaction", ^{
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ context(@"Once the operation has started after being canceled", ^{
+ it(@"should not attempt to send a cancel interaction", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+
+ [testPresentAlertOperation cancel];
+
+ OCMReject([mockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+ [testCancelAlertView cancel];
+
+ OCMReject([mockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+ });
+ });
+ });
+
+ context(@"Module does not support the CancelInteration RPC", ^{
+ beforeEach(^{
+ [SDLGlobals sharedGlobals].rpcVersion = cancelInteractionNotSupportedSpecVersion;
+ });
+
+ it(@"should not attempt to send a cancel interaction if the operation is executing", ^{
+ OCMExpect([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLAlert.class] withResponseHandler:[OCMArg any]]);
+ [testPresentAlertOperation start];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+
+ it(@"should cancel the operation if it has not yet been run", ^{
+ OCMReject([strictMockConnectionManager sendConnectionRequest:[OCMArg isKindOfClass:SDLCancelInteraction.class] withResponseHandler:[OCMArg any]]);
+
+ [testCancelAlertView cancel];
+
+ expect(testPresentAlertOperation.isCancelled).to(beTrue());
+
+ OCMVerifyAllWithDelay(strictMockConnectionManager, 0.5);
+ });
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/SDLScreenManagerSpec.m b/SmartDeviceLinkTests/SDLScreenManagerSpec.m
index 9f137a5b2..5982109ce 100644
--- a/SmartDeviceLinkTests/SDLScreenManagerSpec.m
+++ b/SmartDeviceLinkTests/SDLScreenManagerSpec.m
@@ -2,11 +2,13 @@
#import <Nimble/Nimble.h>
#import <OCMock/OCMock.h>
+#import "SDLAlertManager.h"
#import "SDLFileManager.h"
#import "SDLHMILevel.h"
#import "SDLGlobals.h"
#import "SDLMenuCell.h"
#import "SDLMenuManager.h"
+#import "SDLPermissionManager.h"
#import "SDLScreenManager.h"
#import "SDLShow.h"
#import "SDLSoftButtonManager.h"
@@ -18,6 +20,16 @@
#import "SDLVersion.h"
#import "TestConnectionManager.h"
+@interface SDLAlertManager()
+
+@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
+@property (weak, nonatomic) SDLFileManager *fileManager;
+@property (weak, nonatomic) SDLSystemCapabilityManager *systemCapabilityManager;
+@property (weak, nonatomic, nullable) SDLPermissionManager *permissionManager;
+@property (strong, nonatomic) NSOperationQueue *transactionQueue;
+
+@end
+
@interface SDLSoftButtonManager()
@property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager;
@@ -41,6 +53,7 @@
@property (strong, nonatomic) SDLTextAndGraphicManager *textAndGraphicManager;
@property (strong, nonatomic) SDLSoftButtonManager *softButtonManager;
@property (strong, nonatomic) SDLMenuManager *menuManager;
+@property (strong, nonatomic) SDLAlertManager *alertManager;
@end
@@ -50,6 +63,7 @@ describe(@"screen manager", ^{
__block TestConnectionManager *mockConnectionManager = nil;
__block SDLFileManager *mockFileManager = nil;
__block SDLSystemCapabilityManager *mockSystemCapabilityManager = nil;
+ __block SDLPermissionManager *mockPermissionManager = nil;
__block SDLScreenManager *testScreenManager = nil;
__block NSString *testString1 = @"test1";
@@ -77,8 +91,9 @@ describe(@"screen manager", ^{
mockConnectionManager = [[TestConnectionManager alloc] init];
mockFileManager = OCMClassMock([SDLFileManager class]);
mockSystemCapabilityManager = OCMClassMock([SDLSystemCapabilityManager class]);
+ mockPermissionManager = OCMClassMock([SDLPermissionManager class]);
- testScreenManager = [[SDLScreenManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager];
+ testScreenManager = [[SDLScreenManager alloc] initWithConnectionManager:mockConnectionManager fileManager:mockFileManager systemCapabilityManager:mockSystemCapabilityManager permissionManager:mockPermissionManager];
});
// should set up the sub-managers correctly
@@ -87,6 +102,10 @@ describe(@"screen manager", ^{
expect(testScreenManager.textAndGraphicManager.fileManager).to(equal(mockFileManager));
expect(testScreenManager.softButtonManager.connectionManager).to(equal(mockConnectionManager));
expect(testScreenManager.softButtonManager.fileManager).to(equal(mockFileManager));
+ expect(testScreenManager.alertManager.connectionManager).to(equal(mockConnectionManager));
+ expect(testScreenManager.alertManager.fileManager).to(equal(mockFileManager));
+ expect(testScreenManager.alertManager.systemCapabilityManager).to(equal(mockSystemCapabilityManager));
+ expect(testScreenManager.alertManager.permissionManager).to(equal(mockPermissionManager));
});
// batching updates
@@ -170,6 +189,17 @@ describe(@"screen manager", ^{
expect(testScreenManager.textAndGraphicManager.transactionQueue.operationCount).to(equal(1));
});
});
+
+ // presenting an alert
+ describe(@"presenting an alert", ^{
+ it(@"should pass the call to the alert manager", ^{
+ SDLAlertView *testAlertView = [[SDLAlertView alloc] initWithText:@"Test" buttons:@[[[SDLSoftButtonObject alloc] initWithName:@"Test Button" text:@"Test Button" artwork:nil handler:nil]]];
+
+ [testScreenManager presentAlert:testAlertView withCompletionHandler:nil];
+
+ expect(testScreenManager.alertManager.transactionQueue.operationCount).to(equal(1));
+ });
+ });
});
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.h b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.h
index d3dd50a19..3f91c72ba 100644
--- a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.h
+++ b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.h
@@ -16,6 +16,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface TestConnectionManager : NSObject <SDLConnectionManagerType>
+@property (strong, nonatomic, nullable) SDLSystemInfo *systemInfo;
+
@property (copy, nonatomic, readonly) NSError *defaultError;
/**
diff --git a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m
index 4774f8d09..525ad3052 100644
--- a/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m
+++ b/SmartDeviceLinkTests/TestUtilities/TestConnectionManager.m
@@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
_receivedRequestObjects = [NSMutableArray<TestConnectionRequestObject *> array];
_multipleCompletionBlocks = [NSMutableArray array];
+ _systemInfo = [[SDLSystemInfo alloc] initWithMake:@"Livio" model:@"Is" trim:@"Awesome" modelYear:@"2021" softwareVersion:@"1.1.1.1" hardwareVersion:@"2.2.2.2"];
return self;
}
diff --git a/generator/test/test_functions.py b/generator/test/test_functions.py
index d2b885e21..ad4dcc6cb 100644
--- a/generator/test/test_functions.py
+++ b/generator/test/test_functions.py
@@ -68,7 +68,8 @@ class TestFunctionsProducer(TestCase):
structs = {
'SoftButton': Struct(name='SoftButton', members={
'image': Param(name='image', param_type=String(), since='1.0.0', description=['image description']),
- 'ignore': Param(name='ignore', param_type=Struct(name='ignore'))}),
+ 'dayColorScheme': Param(name='dayColorScheme', param_type=Struct(name='TemplateColorScheme', description=[
+ '\nA color scheme for all display layout templates.\n']))}),
'PresetBankCapabilities': Struct(name='PresetBankCapabilities', members={
'availableHdChannelsAvailable': Param(name='availableHdChannelsAvailable', param_type=Boolean(),
since='2.0.0',
@@ -89,11 +90,8 @@ class TestFunctionsProducer(TestCase):
self.producer.common_names(description=['availableHDChannelsAvailable description'],
since='2.0.0', name='AvailableHdChannelsAvailable',
origin='availableHdChannelsAvailable'),
- self.producer.common_names(description=[], name='Ignore', origin='ignore', since=None),
+ self.producer.common_names(description=[], name='DayColorScheme', origin='dayColorScheme', since=None),
self.producer.common_names(description=['image description'], name='Image', origin='image', since='1.0.0'),
- self.producer.common_names(description=[], name='PresetBankCapabilities', origin='PresetBankCapabilities',
- since=None),
- self.producer.common_names(description=[], name='SoftButton', origin='SoftButton', since=None),
self.producer.common_names(description=['syncMsgVersion description'], name='SdlMsgVersion',
origin='syncMsgVersion', since='3.5.0')]
actual = self.producer.get_simple_params(functions, structs)
diff --git a/generator/transformers/functions_producer.py b/generator/transformers/functions_producer.py
index 73091fe12..eaf84bf55 100644
--- a/generator/transformers/functions_producer.py
+++ b/generator/transformers/functions_producer.py
@@ -88,17 +88,15 @@ class FunctionsProducer(InterfaceProducerCommon):
"""
origin = element.name
name = self._replace_sync(element.name)
- # if isinstance(element.param_type, (Integer, Float, Boolean, String)):
return {name: self.common_names(**{
'name': self.title(name),
'origin': origin,
'description': self.extract_description(element.description),
'since': element.since})}
- # return OrderedDict()
def get_simple_params(self, functions: dict, structs: dict) -> dict:
"""
- Standalone method used for preparing SDLRPCParameterNames collection ready to be applied to Jinja2 template
+ Creates a list of all parameter names used in functions and structs. This list is used by a Jinja2 template to generate the SDLRPCParameterNames class.
:param functions: collection with all functions from initial Model
:param structs: collection with all structs from initial Model
:return: collection with transformed element ready to be applied to Jinja2 template
@@ -110,8 +108,8 @@ class FunctionsProducer(InterfaceProducerCommon):
render.update(self.evaluate(param))
for struct in structs.values():
- render.update(self.evaluate(struct))
for param in struct.members.values():
render.update(self.evaluate(param))
+
unique = dict(zip(list(map(lambda l: l.name, render.values())), render.values()))
return {'params': sorted(unique.values(), key=lambda a: a.name)}