From 74fbee0559a4f57713c4c81c0effe2e21355cac0 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Fri, 12 Jul 2019 14:15:22 -0400 Subject: [PATCH 01/11] Add SDLMenuLayout RPC Updates --- SmartDeviceLink-iOS.podspec | 1 + SmartDeviceLink-iOS.xcodeproj/project.pbxproj | 12 ++++++-- SmartDeviceLink.podspec | 1 + SmartDeviceLink/SDLAddSubMenu.h | 13 +++++++-- SmartDeviceLink/SDLAddSubMenu.m | 8 ++++++ SmartDeviceLink/SDLDisplayCapabilities.h | 8 ++++++ SmartDeviceLink/SDLDisplayCapabilities.m | 8 ++++++ SmartDeviceLink/SDLMenuLayout.h | 25 +++++++++++++++++ SmartDeviceLink/SDLMenuLayout.m | 12 ++++++++ SmartDeviceLink/SDLRPCParameterNames.h | 2 ++ SmartDeviceLink/SDLRPCParameterNames.m | 2 ++ SmartDeviceLink/SDLSetGlobalProperties.h | 28 +++++++++++++++++-- SmartDeviceLink/SDLSetGlobalProperties.m | 17 +++++++++-- SmartDeviceLink/SmartDeviceLink.h | 1 + 14 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 SmartDeviceLink/SDLMenuLayout.h create mode 100644 SmartDeviceLink/SDLMenuLayout.m diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec index 18cb88576..bdeeac6e0 100644 --- a/SmartDeviceLink-iOS.podspec +++ b/SmartDeviceLink-iOS.podspec @@ -207,6 +207,7 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLMediaServiceManifest.h', 'SmartDeviceLink/SDLMediaType.h', 'SmartDeviceLink/SDLMenuCell.h', +'SmartDeviceLink/SDLMenuLayout.h', 'SmartDeviceLink/SDLMenuManagerConstants.h', 'SmartDeviceLink/SDLMenuParams.h', 'SmartDeviceLink/SDLMetadataTags.h', diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj index 077bc10b7..37f4181f6 100644 --- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj +++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj @@ -1007,6 +1007,8 @@ 5D75960D22972F830013207C /* TestSystemCapabilityObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D75960C22972F830013207C /* TestSystemCapabilityObserver.m */; }; 5D75961122972FCA0013207C /* SDLSystemCapabilityObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D75960F22972FCA0013207C /* SDLSystemCapabilityObserver.h */; }; 5D75961222972FCA0013207C /* SDLSystemCapabilityObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D75961022972FCA0013207C /* SDLSystemCapabilityObserver.m */; }; + 5D76750E22D8FB3700E8D71A /* SDLMenuLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76750C22D8FB3700E8D71A /* SDLMenuLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D76750F22D8FB3700E8D71A /* SDLMenuLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */; }; 5D76E31C1D3805FF00647CFA /* SDLLockScreenManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */; }; 5D76E3211D39742300647CFA /* SDLViewControllerPresentable.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */; }; 5D76E3241D39767000647CFA /* SDLLockScreenPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */; }; @@ -2668,6 +2670,8 @@ 5D75960C22972F830013207C /* TestSystemCapabilityObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TestSystemCapabilityObserver.m; path = DevAPISpecs/TestSystemCapabilityObserver.m; sourceTree = ""; }; 5D75960F22972FCA0013207C /* SDLSystemCapabilityObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLSystemCapabilityObserver.h; sourceTree = ""; }; 5D75961022972FCA0013207C /* SDLSystemCapabilityObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityObserver.m; sourceTree = ""; }; + 5D76750C22D8FB3700E8D71A /* SDLMenuLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLMenuLayout.h; sourceTree = ""; }; + 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuLayout.m; sourceTree = ""; }; 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLockScreenManagerSpec.m; path = DevAPISpecs/SDLLockScreenManagerSpec.m; sourceTree = ""; }; 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLViewControllerPresentable.h; sourceTree = ""; }; 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLLockScreenPresenter.h; sourceTree = ""; }; @@ -4688,10 +4692,12 @@ 5D61FB0A1A84238A00846EE7 /* SDLMediaClockFormat.m */, 88E6F1A5220E1588006156F9 /* SDLMediaType.h */, 88E6F1A6220E1588006156F9 /* SDLMediaType.m */, - 1E5AD0461F1F773E0029B8AF /* SDLModuleType.h */, - 1E5AD0471F1F773E0029B8AF /* SDLModuleType.m */, + 5D76750C22D8FB3700E8D71A /* SDLMenuLayout.h */, + 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */, 8BBEA6041F324165003EEA26 /* SDLMetadataType.h */, 8BBEA6051F324165003EEA26 /* SDLMetadataType.m */, + 1E5AD0461F1F773E0029B8AF /* SDLModuleType.h */, + 1E5AD0471F1F773E0029B8AF /* SDLModuleType.m */, 88B58DC422204AF10011B063 /* SDLNavigationAction.h */, 88B58DC522204AF10011B063 /* SDLNavigationAction.m */, 88B58DBE222045320011B063 /* SDLNavigationJunction.h */, @@ -6450,6 +6456,7 @@ 5D61FC511A84238C00846EE7 /* SDLButtonCapabilities.h in Headers */, 5D61FDE91A84238C00846EE7 /* SDLUnsubscribeButtonResponse.h in Headers */, 5D61FCD51A84238C00846EE7 /* SDLImageType.h in Headers */, + 5D76750E22D8FB3700E8D71A /* SDLMenuLayout.h in Headers */, 8803DCEF22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h in Headers */, 5D61FC2F1A84238C00846EE7 /* SDLAddCommandResponse.h in Headers */, 5D0C2A0020D9479B008B56CD /* SDLStreamingVideoLifecycleManager.h in Headers */, @@ -7305,6 +7312,7 @@ 5D61FDDE1A84238C00846EE7 /* SDLTTSChunk.m in Sources */, 5D61FD9E1A84238C00846EE7 /* SDLSliderResponse.m in Sources */, 1EAA47462035623B000FE74B /* SDLLightControlData.m in Sources */, + 5D76750F22D8FB3700E8D71A /* SDLMenuLayout.m in Sources */, 5D61FC5C1A84238C00846EE7 /* SDLChangeRegistration.m in Sources */, 5D1665C91CF8CA3D00CC4CA1 /* SDLPermissionFilter.m in Sources */, 5D61FDBA1A84238C00846EE7 /* SDLSyncPDataResponse.m in Sources */, diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec index 97fe847b5..bcae5b65b 100644 --- a/SmartDeviceLink.podspec +++ b/SmartDeviceLink.podspec @@ -208,6 +208,7 @@ sdefault.public_header_files = [ 'SmartDeviceLink/SDLMediaServiceManifest.h', 'SmartDeviceLink/SDLMediaType.h', 'SmartDeviceLink/SDLMenuCell.h', +'SmartDeviceLink/SDLMenuLayout.h', 'SmartDeviceLink/SDLMenuManagerConstants.h', 'SmartDeviceLink/SDLMenuParams.h', 'SmartDeviceLink/SDLMetadataTags.h', diff --git a/SmartDeviceLink/SDLAddSubMenu.h b/SmartDeviceLink/SDLAddSubMenu.h index bd5537c2d..edc8babc5 100644 --- a/SmartDeviceLink/SDLAddSubMenu.h +++ b/SmartDeviceLink/SDLAddSubMenu.h @@ -3,6 +3,8 @@ #import "SDLRPCRequest.h" +#import "SDLMenuLayout.h" + @class SDLImage; /** @@ -25,9 +27,11 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName; -- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName position:(UInt8)position __deprecated_msg(("Use initWithId:menuName:menuIcon:position: instead")); +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName position:(UInt8)position __deprecated_msg("Use initWithId:menuName:menuLayout:menuIcon:position: instead"); + +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuIcon:(nullable SDLImage *)icon position:(UInt8)position __deprecated_msg("Use initWithId:menuName:menuLayout:menuIcon:position: instead"); -- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuIcon:(nullable SDLImage *)icon position:(UInt8)position; +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuLayout:(nullable SDLMenuLayout)menuLayout menuIcon:(nullable SDLImage *)icon position:(UInt8)position; /** * a Menu ID that identifies a sub menu @@ -68,6 +72,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (strong, nonatomic, nullable) SDLImage *menuIcon; +/** + The sub-menu layout. See available menu layouts on DisplayCapabilities.menuLayoutsAvailable. Defaults to LIST. + */ +@property (strong, nonatomic, nullable) SDLMenuLayout menuLayout; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAddSubMenu.m b/SmartDeviceLink/SDLAddSubMenu.m index 48ea43c8a..5b5faae95 100644 --- a/SmartDeviceLink/SDLAddSubMenu.m +++ b/SmartDeviceLink/SDLAddSubMenu.m @@ -80,6 +80,14 @@ - (nullable SDLImage *)menuIcon { return [self.parameters sdl_objectForName:SDLRPCParameterNameMenuIcon ofClass:[SDLImage class] error:nil]; } +- (void)setMenuLayout:(nullable SDLMenuLayout)menuLayout { + [self.parameters sdl_setObject:menuLayout forName:SDLRPCParameterNameMenuLayout]; +} + +- (nullable SDLMenuLayout)menuLayout { + return [self.parameters sdl_enumForName:SDLRPCParameterNameMenuLayout error:nil]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLDisplayCapabilities.h b/SmartDeviceLink/SDLDisplayCapabilities.h index b278ef3a2..c9cbe1598 100644 --- a/SmartDeviceLink/SDLDisplayCapabilities.h +++ b/SmartDeviceLink/SDLDisplayCapabilities.h @@ -5,6 +5,7 @@ #import "SDLDisplayType.h" #import "SDLMediaClockFormat.h" +#import "SDLMenuLayout.h" @class SDLImageField; @class SDLScreenParams; @@ -97,6 +98,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nullable, strong, nonatomic) NSNumber *numCustomPresetsAvailable; +/** + An array of available menu layouts. If this parameter is not provided, only the `LIST` layout is assumed to be available. + + Optional, array of 1 to 100, see SDLMenuLayout + */ +@property (nullable, strong, nonatomic) NSArray *menuLayoutsAvailable; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLDisplayCapabilities.m b/SmartDeviceLink/SDLDisplayCapabilities.m index b85208a83..e9362e754 100644 --- a/SmartDeviceLink/SDLDisplayCapabilities.m +++ b/SmartDeviceLink/SDLDisplayCapabilities.m @@ -89,6 +89,14 @@ - (void)setNumCustomPresetsAvailable:(nullable NSNumber *)numCustomPrese return [self.store sdl_objectForName:SDLRPCParameterNameNumberCustomPresetsAvailable ofClass:NSNumber.class error:nil]; } +- (void)setMenuLayoutsAvailable:(nullable NSArray *)menuLayoutsAvailable { + [self.store sdl_setObject:menuLayoutsAvailable forName:SDLRPCParameterNameMenuLayoutsAvailable]; +} + +- (nullable NSArray *)menuLayoutsAvailable { + return [self.store sdl_enumsForName:SDLRPCParameterNameMenuLayoutsAvailable error:nil]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLMenuLayout.h b/SmartDeviceLink/SDLMenuLayout.h new file mode 100644 index 000000000..ee55a0b44 --- /dev/null +++ b/SmartDeviceLink/SDLMenuLayout.h @@ -0,0 +1,25 @@ +// +// SDLMenuLayout.h +// SmartDeviceLink +// +// Created by Joel Fischer on 7/12/19. +// Copyright © 2019 smartdevicelink. All rights reserved. +// + +#import "SDLEnum.h" + +/** + * Enum for each type of video streaming protocol, used in VideoStreamingFormat + */ +typedef SDLEnum SDLMenuLayout SDL_SWIFT_ENUM; + +/** + * STREAMABLE, the current app is allowed to stream video + */ +extern SDLMenuLayout const SDLMenuLayoutList; + +/** + * NOT_STREAMABLE, the current app is not allowed to stream video + */ +extern SDLMenuLayout const SDLMenuLayoutTiles; + diff --git a/SmartDeviceLink/SDLMenuLayout.m b/SmartDeviceLink/SDLMenuLayout.m new file mode 100644 index 000000000..8b1b95b38 --- /dev/null +++ b/SmartDeviceLink/SDLMenuLayout.m @@ -0,0 +1,12 @@ +// +// SDLMenuLayout.m +// SmartDeviceLink +// +// Created by Joel Fischer on 7/12/19. +// Copyright © 2019 smartdevicelink. All rights reserved. +// + +#import "SDLMenuLayout.h" + +SDLMenuLayout const SDLMenuLayoutList = @"LIST"; +SDLMenuLayout const SDLMenuLayoutTiles = @"TILES"; diff --git a/SmartDeviceLink/SDLRPCParameterNames.h b/SmartDeviceLink/SDLRPCParameterNames.h index fc0f17ddf..b6fa2ad45 100644 --- a/SmartDeviceLink/SDLRPCParameterNames.h +++ b/SmartDeviceLink/SDLRPCParameterNames.h @@ -358,6 +358,8 @@ extern SDLRPCParameterName const SDLRPCParameterNameMediaType; extern SDLRPCParameterName const SDLRPCParameterNameMemory; extern SDLRPCParameterName const SDLRPCParameterNameMenuIcon; extern SDLRPCParameterName const SDLRPCParameterNameMenuId; +extern SDLRPCParameterName const SDLRPCParameterNameMenuLayout; +extern SDLRPCParameterName const SDLRPCParameterNameMenuLayoutsAvailable; extern SDLRPCParameterName const SDLRPCParameterNameMenuName; extern SDLRPCParameterName const SDLRPCParameterNameMenuParams; extern SDLRPCParameterName const SDLRPCParameterNameMenuTitle; diff --git a/SmartDeviceLink/SDLRPCParameterNames.m b/SmartDeviceLink/SDLRPCParameterNames.m index 30236acb4..939424a62 100644 --- a/SmartDeviceLink/SDLRPCParameterNames.m +++ b/SmartDeviceLink/SDLRPCParameterNames.m @@ -352,6 +352,8 @@ SDLRPCParameterName const SDLRPCParameterNameMemoryAvailable = @"memoryAvailable"; SDLRPCParameterName const SDLRPCParameterNameMenuIcon = @"menuIcon"; SDLRPCParameterName const SDLRPCParameterNameMenuId = @"menuID"; +SDLRPCParameterName const SDLRPCParameterNameMenuLayout = @"menuLayout"; +SDLRPCParameterName const SDLRPCParameterNameMenuLayoutsAvailable = @"menuLayoutsAvailable"; SDLRPCParameterName const SDLRPCParameterNameMenuName = @"menuName"; SDLRPCParameterName const SDLRPCParameterNameMenuParams = @"menuParams"; SDLRPCParameterName const SDLRPCParameterNameMenuTitle = @"menuTitle"; diff --git a/SmartDeviceLink/SDLSetGlobalProperties.h b/SmartDeviceLink/SDLSetGlobalProperties.h index 7b3370d9b..4fbe5c679 100644 --- a/SmartDeviceLink/SDLSetGlobalProperties.h +++ b/SmartDeviceLink/SDLSetGlobalProperties.h @@ -3,6 +3,8 @@ #import "SDLRPCRequest.h" +#import "SDLMenuLayout.h" + @class SDLImage; @class SDLKeyboardProperties; @class SDLTTSChunk; @@ -26,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @param timeoutText A string that will be turned into TTS chunks for the timeout prompt @return The SetGlobalProperties RPC */ -- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText; +- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText __deprecated_msg("Use initWithHelpText:timeoutText:vrHelpTitle:vrHelp:menuTitle:menuIcon:keyboardProperties:menuLayout: instead"); /** Initialize SetGlobalProperties with help text, timeout text, help title, and help items @@ -37,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN @param vrHelp The items of the help interface prompt @return The SetGlobalProperties RPC */ -- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp; +- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp __deprecated_msg("Use initWithHelpText:timeoutText:vrHelpTitle:vrHelp:menuTitle:menuIcon:keyboardProperties:menuLayout: instead"); /** Initialize SetGlobalProperties with all possible items @@ -51,7 +53,22 @@ NS_ASSUME_NONNULL_BEGIN @param keyboardProperties The properties of a keyboard prompt @return The SetGlobalProperties RPC */ -- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp menuTitle:(nullable NSString *)menuTitle menuIcon:(nullable SDLImage *)menuIcon keyboardProperties:(nullable SDLKeyboardProperties *)keyboardProperties; +- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp menuTitle:(nullable NSString *)menuTitle menuIcon:(nullable SDLImage *)menuIcon keyboardProperties:(nullable SDLKeyboardProperties *)keyboardProperties __deprecated_msg("Use initWithHelpText:timeoutText:vrHelpTitle:vrHelp:menuTitle:menuIcon:keyboardProperties:menuLayout: instead"); + +/** + Initialize SetGlobalProperties with all possible items + + @param helpText A string that will be turned into TTS chunks for the help prompt + @param timeoutText A string that will be turned into TTS chunks for the timeout prompt + @param vrHelpTitle The title of the help interface prompt + @param vrHelp The items of the help interface prompt + @param menuTitle The title of the menu button + @param menuIcon The icon on the menu button + @param keyboardProperties The properties of a keyboard prompt + @param menuLayout The layout of the top-level main menu + @return The SetGlobalProperties RPC + */ +- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp menuTitle:(nullable NSString *)menuTitle menuIcon:(nullable SDLImage *)menuIcon keyboardProperties:(nullable SDLKeyboardProperties *)keyboardProperties menuLayout:(nullable SDLMenuLayout)menuLayout; /** Help prompt for when the user asks for help with an interface prompt @@ -104,6 +121,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (strong, nonatomic, nullable) SDLKeyboardProperties *keyboardProperties; +/** + The main menu layout. See available menu layouts on DisplayCapabilities.menuLayoutsAvailable. Defaults to LIST. + */ +@property (strong, nonatomic, nullable) SDLMenuLayout menuLayout; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLSetGlobalProperties.m b/SmartDeviceLink/SDLSetGlobalProperties.m index 69f06d5d5..c8d08c723 100644 --- a/SmartDeviceLink/SDLSetGlobalProperties.m +++ b/SmartDeviceLink/SDLSetGlobalProperties.m @@ -26,14 +26,18 @@ - (instancetype)init { #pragma clang diagnostic pop - (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText { - return [self initWithHelpText:helpText timeoutText:timeoutText vrHelpTitle:nil vrHelp:nil]; + return [self initWithHelpText:helpText timeoutText:timeoutText vrHelpTitle:nil vrHelp:nil menuTitle:nil menuIcon:nil keyboardProperties:nil menuLayout:nil]; } - (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp { - return [self initWithHelpText:helpText timeoutText:timeoutText vrHelpTitle:vrHelpTitle vrHelp:vrHelp menuTitle:nil menuIcon:nil keyboardProperties:nil]; + return [self initWithHelpText:helpText timeoutText:timeoutText vrHelpTitle:vrHelpTitle vrHelp:vrHelp menuTitle:nil menuIcon:nil keyboardProperties:nil menuLayout:nil]; } - (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp menuTitle:(nullable NSString *)menuTitle menuIcon:(nullable SDLImage *)menuIcon keyboardProperties:(nullable SDLKeyboardProperties *)keyboardProperties { + return [self initWithHelpText:helpText timeoutText:timeoutText vrHelpTitle:vrHelpTitle vrHelp:vrHelp menuTitle:menuTitle menuIcon:menuIcon keyboardProperties:keyboardProperties menuLayout:nil]; +} + +- (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(nullable NSString *)timeoutText vrHelpTitle:(nullable NSString *)vrHelpTitle vrHelp:(nullable NSArray *)vrHelp menuTitle:(nullable NSString *)menuTitle menuIcon:(nullable SDLImage *)menuIcon keyboardProperties:(nullable SDLKeyboardProperties *)keyboardProperties menuLayout:(nullable SDLMenuLayout)menuLayout { self = [self init]; if (!self) { return nil; @@ -46,6 +50,7 @@ - (instancetype)initWithHelpText:(nullable NSString *)helpText timeoutText:(null self.menuTitle = menuTitle; self.menuIcon = menuIcon; self.keyboardProperties = keyboardProperties; + self.menuLayout = menuLayout; return self; } @@ -106,6 +111,14 @@ - (nullable SDLKeyboardProperties *)keyboardProperties { return [self.parameters sdl_objectForName:SDLRPCParameterNameKeyboardProperties ofClass:SDLKeyboardProperties.class error:nil]; } +- (void)setMenuLayout:(nullable SDLMenuLayout)menuLayout { + [self.parameters sdl_setObject:menuLayout forName:SDLRPCParameterNameMenuLayout]; +} + +- (nullable SDLMenuLayout)menuLayout { + return [self.parameters sdl_enumForName:SDLRPCParameterNameMenuLayout error:nil]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h index 3b884804f..59b0b092d 100644 --- a/SmartDeviceLink/SmartDeviceLink.h +++ b/SmartDeviceLink/SmartDeviceLink.h @@ -312,6 +312,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[]; #import "SDLMassageZone.h" #import "SDLMediaClockFormat.h" #import "SDLMediaType.h" +#import "SDLMenuLayout.h" #import "SDLMenuManagerConstants.h" #import "SDLMetadataType.h" #import "SDLModuleType.h" From 3b5bca98e1b18828fe9c446e75388778e618d2e4 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Fri, 12 Jul 2019 15:29:44 -0400 Subject: [PATCH 02/11] Menu manager and example app updates --- Example Apps/Example ObjC/MenuManager.m | 6 ++-- .../Example ObjC/VehicleDataManager.m | 2 +- Example Apps/Example Swift/MenuManager.swift | 6 ++-- .../Example Swift/VehicleDataManager.swift | 2 +- SmartDeviceLink-iOS.podspec | 1 + SmartDeviceLink-iOS.xcodeproj/project.pbxproj | 16 ++++++++++ SmartDeviceLink.podspec | 1 + SmartDeviceLink/SDLAddSubMenu.m | 31 +++++++++++-------- SmartDeviceLink/SDLMenuCell.h | 20 +++++++++++- SmartDeviceLink/SDLMenuCell.m | 12 +++++-- SmartDeviceLink/SDLMenuConfiguration.h | 29 +++++++++++++++++ SmartDeviceLink/SDLMenuConfiguration.m | 27 ++++++++++++++++ SmartDeviceLink/SDLMenuManager.h | 4 +++ SmartDeviceLink/SDLMenuManager.m | 18 ++++++++++- SmartDeviceLink/SDLScreenManager.h | 6 ++++ SmartDeviceLink/SDLScreenManager.m | 8 +++++ SmartDeviceLink/SmartDeviceLink.h | 1 + 17 files changed, 164 insertions(+), 26 deletions(-) create mode 100644 SmartDeviceLink/SDLMenuConfiguration.h create mode 100644 SmartDeviceLink/SDLMenuConfiguration.m diff --git a/Example Apps/Example ObjC/MenuManager.m b/Example Apps/Example ObjC/MenuManager.m index b0b8c2138..7b626aef9 100644 --- a/Example Apps/Example ObjC/MenuManager.m +++ b/Example Apps/Example ObjC/MenuManager.m @@ -56,7 +56,7 @@ + (SDLMenuCell *)sdlex_menuCellGetAllVehicleDataWithManager:(SDLManager *)manage [submenuItems addObject:cell]; } - return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:submenuItems]; + return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName submenuLayout:SDLMenuLayoutTiles icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:submenuItems]; } + (NSArray *)sdlex_allVehicleDataTypes { @@ -115,7 +115,7 @@ + (SDLMenuCell *)sdlex_menuCellChangeTemplateWithManager:(SDLManager *)manager { }]; [submenuItems addObject:cell2]; - return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName icon:nil subCells:[submenuItems copy]]; + return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName submenuLayout:SDLMenuLayoutList icon:nil subCells:[submenuItems copy]]; } + (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager { @@ -127,7 +127,7 @@ + (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager { [submenuItems addObject:cell]; } - return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:[submenuItems copy]]; + return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName submenuLayout:SDLMenuLayoutList icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:[submenuItems copy]]; } #pragma mark - Voice Commands diff --git a/Example Apps/Example ObjC/VehicleDataManager.m b/Example Apps/Example ObjC/VehicleDataManager.m index cc2ee46fa..fd82569d4 100644 --- a/Example Apps/Example ObjC/VehicleDataManager.m +++ b/Example Apps/Example ObjC/VehicleDataManager.m @@ -142,7 +142,7 @@ + (void)getAllVehicleDataWithManager:(SDLManager *)manager triggerSource:(SDLTri } SDLLogD(@"App has permission to access vehicle data. Requesting vehicle data..."); - SDLGetVehicleData *getAllVehicleData = [[SDLGetVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:YES beltStatus:YES bodyInformation:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES electronicParkBrakeStatus:YES emergencyEvent:YES engineOilLife:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:YES fuelRange:YES gps:YES headLampStatus:YES instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES turnSignal:YES vin:YES wiperStatus:YES]; + SDLGetVehicleData *getAllVehicleData = [[SDLGetVehicleData alloc] initWithAccelerationPedalPosition:YES airbagStatus:YES beltStatus:YES bodyInformation:YES cloudAppVehicleID:YES clusterModeStatus:YES deviceStatus:YES driverBraking:YES eCallInfo:YES electronicParkBrakeStatus:YES emergencyEvent:YES engineOilLife:YES engineTorque:YES externalTemperature:YES fuelLevel:YES fuelLevelState:YES fuelRange:YES gps:YES headLampStatus:YES instantFuelConsumption:YES myKey:YES odometer:YES prndl:YES rpm:YES speed:YES steeringWheelAngle:YES tirePressure:YES turnSignal:YES vin:YES wiperStatus:YES]; [manager sendRequest:getAllVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { if (error || ![response isKindOfClass:SDLGetVehicleDataResponse.class]) { diff --git a/Example Apps/Example Swift/MenuManager.swift b/Example Apps/Example Swift/MenuManager.swift index c5171510d..7d93fa308 100644 --- a/Example Apps/Example Swift/MenuManager.swift +++ b/Example Apps/Example Swift/MenuManager.swift @@ -65,7 +65,7 @@ private extension MenuManager { }) } - return SDLMenuCell(title: ACGetAllVehicleDataMenuName, icon: SDLArtwork(image: UIImage(named: CarBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), subCells: submenuItems) + return SDLMenuCell(title: ACGetAllVehicleDataMenuName, submenuLayout: .tiles, icon: SDLArtwork(image: UIImage(named: CarBWIconImageName)!.withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), subCells: submenuItems) } /// A list of all possible vehicle data types @@ -149,7 +149,7 @@ private extension MenuManager { } })) - return SDLMenuCell(title: ACSubmenuTemplateMenuName, icon: nil, subCells: submenuItems) + return SDLMenuCell(title: ACSubmenuTemplateMenuName, submenuLayout: .list, icon: nil, subCells: submenuItems) } /// Menu item that opens a submenu when selected @@ -172,7 +172,7 @@ private extension MenuManager { })) } - return SDLMenuCell(title: ACSubmenuMenuName, icon: SDLArtwork(image: #imageLiteral(resourceName: "choice_set").withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), subCells: submenuItems) + return SDLMenuCell(title: ACSubmenuMenuName, submenuLayout: .list, icon: SDLArtwork(image: #imageLiteral(resourceName: "choice_set").withRenderingMode(.alwaysTemplate), persistent: true, as: .PNG), subCells: submenuItems) } } diff --git a/Example Apps/Example Swift/VehicleDataManager.swift b/Example Apps/Example Swift/VehicleDataManager.swift index 1d78edd42..34ac4352c 100644 --- a/Example Apps/Example Swift/VehicleDataManager.swift +++ b/Example Apps/Example Swift/VehicleDataManager.swift @@ -111,7 +111,7 @@ extension VehicleDataManager { guard hasPermissionToAccessVehicleData(with: manager) else { return } SDLLog.d("App has permission to access vehicle data. Requesting all vehicle data...") - let getAllVehicleData = SDLGetVehicleData(accelerationPedalPosition: true, airbagStatus: true, beltStatus: true, bodyInformation: true, clusterModeStatus: true, deviceStatus: true, driverBraking: true, eCallInfo: true, electronicParkBrakeStatus: true, emergencyEvent: true, engineOilLife: true, engineTorque: true, externalTemperature: true, fuelLevel: true, fuelLevelState: true, fuelRange: true, gps: true, headLampStatus: true, instantFuelConsumption: true, myKey: true, odometer: true, prndl: true, rpm: true, speed: true, steeringWheelAngle: true, tirePressure: true, turnSignal: true, vin: true, wiperStatus: true) + let getAllVehicleData = SDLGetVehicleData(accelerationPedalPosition: true, airbagStatus: true, beltStatus: true, bodyInformation: true, cloudAppVehicleID: true, clusterModeStatus: true, deviceStatus: true, driverBraking: true, eCallInfo: true, electronicParkBrakeStatus: true, emergencyEvent: true, engineOilLife: true, engineTorque: true, externalTemperature: true, fuelLevel: true, fuelLevelState: true, fuelRange: true, gps: true, headLampStatus: true, instantFuelConsumption: true, myKey: true, odometer: true, prndl: true, rpm: true, speed: true, steeringWheelAngle: true, tirePressure: true, turnSignal: true, vin: true, wiperStatus: true) manager.send(request: getAllVehicleData) { (request, response, error) in guard didAccessVehicleDataSuccessfully(with: manager, response: response, error: error) else { return } diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec index bdeeac6e0..b51b523f6 100644 --- a/SmartDeviceLink-iOS.podspec +++ b/SmartDeviceLink-iOS.podspec @@ -207,6 +207,7 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLMediaServiceManifest.h', 'SmartDeviceLink/SDLMediaType.h', 'SmartDeviceLink/SDLMenuCell.h', +'SmartDeviceLink/SDLMenuConfiguration.h', 'SmartDeviceLink/SDLMenuLayout.h', 'SmartDeviceLink/SDLMenuManagerConstants.h', 'SmartDeviceLink/SDLMenuParams.h', diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj index 37f4181f6..b017c5190 100644 --- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj +++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj @@ -1009,6 +1009,8 @@ 5D75961222972FCA0013207C /* SDLSystemCapabilityObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D75961022972FCA0013207C /* SDLSystemCapabilityObserver.m */; }; 5D76750E22D8FB3700E8D71A /* SDLMenuLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76750C22D8FB3700E8D71A /* SDLMenuLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D76750F22D8FB3700E8D71A /* SDLMenuLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */; }; + 5D76751322D9088F00E8D71A /* SDLMenuConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76751122D9088F00E8D71A /* SDLMenuConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D76751422D9088F00E8D71A /* SDLMenuConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76751222D9088F00E8D71A /* SDLMenuConfiguration.m */; }; 5D76E31C1D3805FF00647CFA /* SDLLockScreenManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */; }; 5D76E3211D39742300647CFA /* SDLViewControllerPresentable.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */; }; 5D76E3241D39767000647CFA /* SDLLockScreenPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */; }; @@ -2672,6 +2674,8 @@ 5D75961022972FCA0013207C /* SDLSystemCapabilityObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSystemCapabilityObserver.m; sourceTree = ""; }; 5D76750C22D8FB3700E8D71A /* SDLMenuLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLMenuLayout.h; sourceTree = ""; }; 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuLayout.m; sourceTree = ""; }; + 5D76751122D9088F00E8D71A /* SDLMenuConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLMenuConfiguration.h; sourceTree = ""; }; + 5D76751222D9088F00E8D71A /* SDLMenuConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuConfiguration.m; sourceTree = ""; }; 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLockScreenManagerSpec.m; path = DevAPISpecs/SDLLockScreenManagerSpec.m; sourceTree = ""; }; 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLViewControllerPresentable.h; sourceTree = ""; }; 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLLockScreenPresenter.h; sourceTree = ""; }; @@ -3860,6 +3864,7 @@ 5D339CE5207C0651000CC364 /* Menu */ = { isa = PBXGroup; children = ( + 5D76751022D907F500E8D71A /* Configuration */, 755F175E229F14F70041B9CB /* Dynamic Menu Update Utilities */, 5D339CEC207C08AB000CC364 /* Cells */, 5D339CF1207C0ACE000CC364 /* SDLMenuManager.h */, @@ -5146,6 +5151,15 @@ name = Utilities; sourceTree = ""; }; + 5D76751022D907F500E8D71A /* Configuration */ = { + isa = PBXGroup; + children = ( + 5D76751122D9088F00E8D71A /* SDLMenuConfiguration.h */, + 5D76751222D9088F00E8D71A /* SDLMenuConfiguration.m */, + ); + name = Configuration; + sourceTree = ""; + }; 5D76E31A1D3805E600647CFA /* LockScreen */ = { isa = PBXGroup; children = ( @@ -6473,6 +6487,7 @@ 5D61FD7B1A84238C00846EE7 /* SDLScrollableMessage.h in Headers */, DA9F7E931DCC04E400ACAE48 /* SDLUnsubscribeWayPoints.h in Headers */, 5D61FD3D1A84238C00846EE7 /* SDLPrimaryAudioSource.h in Headers */, + 5D76751322D9088F00E8D71A /* SDLMenuConfiguration.h in Headers */, DAC5725C1D10B81E0004288B /* SDLTouch.h in Headers */, 5D6F7A2E1BC5650B0070BF37 /* SDLLifecycleConfiguration.h in Headers */, 5D61FCCD1A84238C00846EE7 /* SDLImage.h in Headers */, @@ -7270,6 +7285,7 @@ 5D92935F20B33FF700FCC775 /* SDLChoiceSet.m in Sources */, 8855F9E4220CB04000A5C897 /* SDLOnAppServiceData.m in Sources */, 5D61FC321A84238C00846EE7 /* SDLAddSubMenu.m in Sources */, + 5D76751422D9088F00E8D71A /* SDLMenuConfiguration.m in Sources */, 5D61FDF61A84238C00846EE7 /* SDLV1ProtocolHeader.m in Sources */, EE798CA620561218008EDE8E /* SDLSecondaryTransportManager.m in Sources */, 88B58DC1222045320011B063 /* SDLNavigationJunction.m in Sources */, diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec index bcae5b65b..6bfec845f 100644 --- a/SmartDeviceLink.podspec +++ b/SmartDeviceLink.podspec @@ -208,6 +208,7 @@ sdefault.public_header_files = [ 'SmartDeviceLink/SDLMediaServiceManifest.h', 'SmartDeviceLink/SDLMediaType.h', 'SmartDeviceLink/SDLMenuCell.h', +'SmartDeviceLink/SDLMenuConfiguration.h', 'SmartDeviceLink/SDLMenuLayout.h', 'SmartDeviceLink/SDLMenuManagerConstants.h', 'SmartDeviceLink/SDLMenuParams.h', diff --git a/SmartDeviceLink/SDLAddSubMenu.m b/SmartDeviceLink/SDLAddSubMenu.m index 5b5faae95..649a10a31 100644 --- a/SmartDeviceLink/SDLAddSubMenu.m +++ b/SmartDeviceLink/SDLAddSubMenu.m @@ -20,28 +20,33 @@ - (instancetype)init { } #pragma clang diagnostic pop -- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuIcon:(nullable SDLImage *)icon position:(UInt8)position { - self = [self initWithId:menuId menuName:menuName]; - if (!self) { return nil; } +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName { + self = [self init]; + if (!self) { + return nil; + } - self.position = @(position); - self.menuIcon = icon; + self.menuID = @(menuId); + self.menuName = menuName; return self; } - (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName position:(UInt8)position { - return [self initWithId:menuId menuName:menuName menuIcon:nil position:position]; + return [self initWithId:menuId menuName:menuName menuLayout:nil menuIcon:nil position:position]; } -- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName { - self = [self init]; - if (!self) { - return nil; - } +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuIcon:(nullable SDLImage *)icon position:(UInt8)position { + return [self initWithId:menuId menuName:menuName menuLayout:nil menuIcon:icon position:position]; +} - self.menuID = @(menuId); - self.menuName = menuName; +- (instancetype)initWithId:(UInt32)menuId menuName:(NSString *)menuName menuLayout:(nullable SDLMenuLayout)menuLayout menuIcon:(nullable SDLImage *)icon position:(UInt8)position { + self = [self initWithId:menuId menuName:menuName]; + if (!self) { return nil; } + + self.position = @(position); + self.menuIcon = icon; + self.menuLayout = menuLayout; return self; } diff --git a/SmartDeviceLink/SDLMenuCell.h b/SmartDeviceLink/SDLMenuCell.h index 1c9c8dcbc..1bb1602b6 100644 --- a/SmartDeviceLink/SDLMenuCell.h +++ b/SmartDeviceLink/SDLMenuCell.h @@ -8,6 +8,7 @@ #import +#import "SDLMenuLayout.h" #import "SDLTriggerSource.h" @class SDLArtwork; @@ -43,6 +44,11 @@ typedef void(^SDLMenuCellSelectionHandler)(SDLTriggerSource triggerSource); */ @property (copy, nonatomic, readonly, nullable) NSArray *subCells; +/** + The layout in which the `subCells` will be displayed. + */ +@property (strong, nonatomic, readonly, nullable) SDLMenuLayout submenuLayout; + /** Create a menu cell that has no subcells. @@ -71,7 +77,19 @@ 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 subCells:(NSArray *)subCells; +- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells __deprecated_msg("Use initWithTitle:icon:layout:subcells: instead"); + +/** + 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 layout The layout that the subCells will be layed out in if that submenu is entered + @param icon The cell's image + @param subCells The subcells that will appear when the cell is selected + @return The menu cell + */ +- (instancetype)initWithTitle:(NSString *)title submenuLayout:(nullable SDLMenuLayout)layout icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells; + @end diff --git a/SmartDeviceLink/SDLMenuCell.m b/SmartDeviceLink/SDLMenuCell.m index 81ba056bf..126ecc168 100644 --- a/SmartDeviceLink/SDLMenuCell.m +++ b/SmartDeviceLink/SDLMenuCell.m @@ -37,14 +37,19 @@ - (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon } - (instancetype)initWithTitle:(NSString *)title subCells:(NSArray *)subCells { - return [self initWithTitle:title icon:nil subCells:subCells]; + return [self initWithTitle:title submenuLayout:nil icon:nil subCells:subCells]; } - (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells { + return [self initWithTitle:title submenuLayout:nil icon:nil subCells:subCells]; +} + +- (instancetype)initWithTitle:(NSString *)title submenuLayout:(nullable SDLMenuLayout)layout icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells { self = [super init]; if (!self) { return nil; } _title = title; + _submenuLayout = layout; _icon = icon; _subCells = subCells; @@ -55,7 +60,7 @@ - (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon } - (NSString *)description { - return [NSString stringWithFormat:@"SDLMenuCell: %u-\"%@\", artworkName: %@, voice commands: %lu, isSubcell: %@, hasSubcells: %@", (unsigned int)_cellId, _title, _icon.name, (unsigned long)_voiceCommands.count, (_parentCellId != UINT32_MAX ? @"YES" : @"NO"), (_subCells.count > 0 ? @"YES" : @"NO")]; + return [NSString stringWithFormat:@"SDLMenuCell: %u-\"%@\", artworkName: %@, voice commands: %lu, isSubcell: %@, hasSubcells: %@, submenuLayout: %@", (unsigned int)_cellId, _title, _icon.name, (unsigned long)_voiceCommands.count, (_parentCellId != UINT32_MAX ? @"YES" : @"NO"), (_subCells.count > 0 ? @"YES" : @"NO"), _submenuLayout]; } #pragma mark - Object Equality @@ -69,7 +74,8 @@ - (NSUInteger)hash { return NSUIntRotateCell(self.title.hash, NSUIntBitCell / 2) ^ NSUIntRotateCell(self.icon.name.hash, NSUIntBitCell / 3) ^ NSUIntRotateCell(self.voiceCommands.hash, NSUIntBitCell / 4) - ^ NSUIntRotateCell(self.subCells.count !=0, NSUIntBitCell / 5 ); + ^ NSUIntRotateCell(self.subCells.count !=0, NSUIntBitCell / 5) + ^ NSUIntRotateCell(self.submenuLayout.hash, NSUIntBitCell / 6); } - (BOOL)isEqual:(id)object { diff --git a/SmartDeviceLink/SDLMenuConfiguration.h b/SmartDeviceLink/SDLMenuConfiguration.h new file mode 100644 index 000000000..819c40f82 --- /dev/null +++ b/SmartDeviceLink/SDLMenuConfiguration.h @@ -0,0 +1,29 @@ +// +// SDLMenuConfiguration.h +// SmartDeviceLink +// +// Created by Joel Fischer on 7/12/19. +// Copyright © 2019 smartdevicelink. All rights reserved. +// + +#import "SDLMenuLayout.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SDLMenuConfiguration : NSObject + +/** + * Changes the default main menu layout. Defaults to `SDLMenuLayoutList`. + */ +@property (strong, nonatomic, readonly) SDLMenuLayout mainMenuLayout; + +/** + * Changes the default submenu layout. To change this for an individual submenu, set the `menuLayout` property on the `SDLMenuCell` initializer for creating a cell with sub-cells. Defaults to `SDLMenuLayoutList`. + */ +@property (strong, nonatomic, readonly) SDLMenuLayout defaultSubmenuLayout; + +- (instancetype)initWithMainMenuLayout:(SDLMenuLayout)mainMenuLayout defaultSubmenuLayout:(SDLMenuLayout)defaultSubmenuLayout; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLMenuConfiguration.m b/SmartDeviceLink/SDLMenuConfiguration.m new file mode 100644 index 000000000..57befe2d1 --- /dev/null +++ b/SmartDeviceLink/SDLMenuConfiguration.m @@ -0,0 +1,27 @@ +// +// SDLMenuConfiguration.m +// SmartDeviceLink +// +// Created by Joel Fischer on 7/12/19. +// Copyright © 2019 smartdevicelink. All rights reserved. +// + +#import "SDLMenuConfiguration.h" + +@implementation SDLMenuConfiguration + +- (instancetype)init { + return [self initWithMainMenuLayout:SDLMenuLayoutList defaultSubmenuLayout:SDLMenuLayoutList]; +} + +- (instancetype)initWithMainMenuLayout:(SDLMenuLayout)mainMenuLayout defaultSubmenuLayout:(SDLMenuLayout)defaultSubmenuLayout { + self = [super init]; + if (!self) { return nil; } + + _mainMenuLayout = mainMenuLayout; + _defaultSubmenuLayout = defaultSubmenuLayout; + + return self; +} + +@end diff --git a/SmartDeviceLink/SDLMenuManager.h b/SmartDeviceLink/SDLMenuManager.h index f559b6fb8..a9b253559 100644 --- a/SmartDeviceLink/SDLMenuManager.h +++ b/SmartDeviceLink/SDLMenuManager.h @@ -11,6 +11,7 @@ @class SDLFileManager; @class SDLMenuCell; +@class SDLMenuConfiguration; @class SDLVoiceCommand; @protocol SDLConnectionManagerType; @@ -33,9 +34,12 @@ typedef void(^SDLMenuUpdateCompletionHandler)(NSError *__nullable error); */ - (void)stop; +@property (strong, nonatomic) SDLMenuConfiguration *menuConfiguration; + @property (copy, nonatomic) NSArray *menuCells; @property (assign, nonatomic) SDLDynamicMenuUpdatesMode dynamicMenuUpdatesMode; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 734e1fc00..dc1f144b2 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -21,6 +21,7 @@ #import "SDLImage.h" #import "SDLLogMacros.h" #import "SDLMenuCell.h" +#import "SDLMenuConfiguration.h" #import "SDLMenuParams.h" #import "SDLDynamicMenuUpdateRunScore.h" #import "SDLDynamicMenuUpdateAlgorithm.h" @@ -30,6 +31,7 @@ #import "SDLRPCNotificationNotification.h" #import "SDLRPCResponseNotification.h" #import "SDLSetDisplayLayoutResponse.h" +#import "SDLSetGlobalProperties.h" #import "SDLScreenManager.h" #import "SDLVoiceCommand.h" @@ -71,6 +73,7 @@ - (instancetype)init { if (!self) { return nil; } _lastMenuId = MenuCellIdMin; + _menuConfiguration = [[SDLMenuConfiguration alloc] init]; _menuCells = @[]; _oldMenuCells = @[]; _dynamicMenuUpdatesMode = SDLDynamicMenuUpdatesModeOnWithCompatibility; @@ -109,6 +112,18 @@ - (void)stop { #pragma mark - Setters +- (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { + _menuConfiguration = menuConfiguration; + + SDLSetGlobalProperties *setGlobalsRPC = [[SDLSetGlobalProperties alloc] init]; + setGlobalsRPC.menuLayout = menuConfiguration.mainMenuLayout; + [self.connectionManager sendConnectionRequest:setGlobalsRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (error != nil) { + SDLLogW(@"Could not set main menu configuration: %@", error); + } + }]; +} + - (void)setMenuCells:(NSArray *)menuCells { if (self.currentHMILevel == nil || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone] @@ -556,7 +571,8 @@ - (SDLAddCommand *)sdl_commandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL) - (SDLAddSubMenu *)sdl_subMenuCommandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL)shouldHaveArtwork position:(UInt16)position { SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? cell.icon.imageRPC : nil; - return [[SDLAddSubMenu alloc] initWithId:cell.cellId menuName:cell.title menuIcon:icon position:(UInt8)position]; + SDLMenuLayout submenuLayout = cell.submenuLayout ?: self.menuConfiguration.defaultSubmenuLayout; + return [[SDLAddSubMenu alloc] initWithId:cell.cellId menuName:cell.title menuLayout:submenuLayout menuIcon:icon position:(UInt8)position]; } #pragma mark - Calling handlers diff --git a/SmartDeviceLink/SDLScreenManager.h b/SmartDeviceLink/SDLScreenManager.h index 1bdb67db4..25ba0d131 100644 --- a/SmartDeviceLink/SDLScreenManager.h +++ b/SmartDeviceLink/SDLScreenManager.h @@ -19,6 +19,7 @@ @class SDLFileManager; @class SDLKeyboardProperties; @class SDLMenuCell; +@class SDLMenuConfiguration; @class SDLSoftButtonObject; @class SDLVoiceCommand; @@ -115,6 +116,11 @@ typedef void(^SDLPreloadChoiceCompletionHandler)(NSError *__nullable error); #pragma mark Menu +/** + The configuration of the menu. Alter this to change the layout of the menu or sub-menus. If this is set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be updated. + */ +@property (strong, nonatomic) SDLMenuConfiguration *menuConfiguration; + /** The current list of menu cells displayed in the app's menu. */ diff --git a/SmartDeviceLink/SDLScreenManager.m b/SmartDeviceLink/SDLScreenManager.m index f93ac21a1..c6533a588 100644 --- a/SmartDeviceLink/SDLScreenManager.m +++ b/SmartDeviceLink/SDLScreenManager.m @@ -130,6 +130,10 @@ - (void)setSoftButtonObjects:(NSArray *)softButtonObjects self.softButtonManager.softButtonObjects = softButtonObjects; } +- (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { + self.menuManager.menuConfiguration = menuConfiguration; +} + - (void)setMenu:(NSArray *)menu { self.menuManager.menuCells = menu; } @@ -208,6 +212,10 @@ - (nullable SDLMetadataType)textField4Type { return _softButtonManager.softButtonObjects; } +- (SDLMenuConfiguration *)menuConfiguration { + return _menuManager.menuConfiguration; +} + - (NSArray *)menu { return _menuManager.menuCells; } diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h index 59b0b092d..2c0e8778e 100644 --- a/SmartDeviceLink/SmartDeviceLink.h +++ b/SmartDeviceLink/SmartDeviceLink.h @@ -412,6 +412,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[]; #import "SDLSoftButtonState.h" #import "SDLMenuCell.h" +#import "SDLMenuConfiguration.h" #import "SDLVoiceCommand.h" #import "SDLChoiceCell.h" From b4ea75569fd0490ce5bd9f371fe23a38e37735aa Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Fri, 12 Jul 2019 16:16:06 -0400 Subject: [PATCH 03/11] Add a bunch of tests --- SmartDeviceLink-iOS.xcodeproj/project.pbxproj | 8 ++++++ .../DevAPISpecs/SDLMenuCellSpec.m | 24 +++++++++++++--- .../DevAPISpecs/SDLMenuConfigurationSpec.m | 28 +++++++++++++++++++ .../RPCSpecs/EnumSpecs/SDLMenuLayoutSpec.m | 15 ++++++++++ .../RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m | 21 +++++++++++++- .../StructSpecs/SDLDisplayCapabilitiesSpec.m | 12 ++++++-- 6 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 SmartDeviceLinkTests/DevAPISpecs/SDLMenuConfigurationSpec.m create mode 100644 SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMenuLayoutSpec.m diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj index b017c5190..528d4940a 100644 --- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj +++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj @@ -1011,6 +1011,8 @@ 5D76750F22D8FB3700E8D71A /* SDLMenuLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */; }; 5D76751322D9088F00E8D71A /* SDLMenuConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76751122D9088F00E8D71A /* SDLMenuConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D76751422D9088F00E8D71A /* SDLMenuConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76751222D9088F00E8D71A /* SDLMenuConfiguration.m */; }; + 5D76751622D920FD00E8D71A /* SDLMenuConfigurationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76751522D920FD00E8D71A /* SDLMenuConfigurationSpec.m */; }; + 5D76751822D921CB00E8D71A /* SDLMenuLayoutSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76751722D921CB00E8D71A /* SDLMenuLayoutSpec.m */; }; 5D76E31C1D3805FF00647CFA /* SDLLockScreenManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */; }; 5D76E3211D39742300647CFA /* SDLViewControllerPresentable.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */; }; 5D76E3241D39767000647CFA /* SDLLockScreenPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */; }; @@ -2676,6 +2678,8 @@ 5D76750D22D8FB3700E8D71A /* SDLMenuLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuLayout.m; sourceTree = ""; }; 5D76751122D9088F00E8D71A /* SDLMenuConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLMenuConfiguration.h; sourceTree = ""; }; 5D76751222D9088F00E8D71A /* SDLMenuConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuConfiguration.m; sourceTree = ""; }; + 5D76751522D920FD00E8D71A /* SDLMenuConfigurationSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLMenuConfigurationSpec.m; path = DevAPISpecs/SDLMenuConfigurationSpec.m; sourceTree = ""; }; + 5D76751722D921CB00E8D71A /* SDLMenuLayoutSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLMenuLayoutSpec.m; sourceTree = ""; }; 5D76E31B1D3805FF00647CFA /* SDLLockScreenManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLLockScreenManagerSpec.m; path = DevAPISpecs/SDLLockScreenManagerSpec.m; sourceTree = ""; }; 5D76E3201D39742300647CFA /* SDLViewControllerPresentable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLViewControllerPresentable.h; sourceTree = ""; }; 5D76E3221D39767000647CFA /* SDLLockScreenPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLLockScreenPresenter.h; sourceTree = ""; }; @@ -3326,6 +3330,7 @@ 1EB59CC9202DC8E300343A61 /* SDLMassageZoneSpec.m */, 162E82061A9BDE8A00906325 /* SDLMediaClockFormatSpec.m */, 88E6F1A9220E1720006156F9 /* SDLMediaTypeSpec.m */, + 5D76751722D921CB00E8D71A /* SDLMenuLayoutSpec.m */, 8BBEA6081F324832003EEA26 /* SDLMetadataTypeSpec.m */, 1EB59CC7202DC86A00343A61 /* SDLModuleTypeSpec.m */, 88B58DC822204C9E0011B063 /* SDLNavigationActionSpec.m */, @@ -5869,6 +5874,7 @@ 5DAB5F5220989A8300A020C8 /* SDLVoiceCommandSpec.m */, 752ECDB8228C42E100D945F4 /* SDLMenuRunScoreSpec.m */, 752ECDBA228C532600D945F4 /* SDLMenuUpdateAlgorithmSpec.m */, + 5D76751522D920FD00E8D71A /* SDLMenuConfigurationSpec.m */, ); name = Menu; sourceTree = ""; @@ -7508,11 +7514,13 @@ 162E82FD1A9BDE8B00906325 /* SDLSystemContextSpec.m in Sources */, 162E82E21A9BDE8B00906325 /* SDLIgnitionStableStatusSpec.m in Sources */, 162E82EE1A9BDE8B00906325 /* SDLMediaClockFormatSpec.m in Sources */, + 5D76751822D921CB00E8D71A /* SDLMenuLayoutSpec.m in Sources */, 5DA026901AD44EE700019F86 /* SDLDialNumberResponseSpec.m in Sources */, 162E83901A9BDE8B00906325 /* SDLTireStatusSpec.m in Sources */, 162E82E01A9BDE8B00906325 /* SDLHMILevelSpec.m in Sources */, 88F65133220C6DC300CAF321 /* SDLWeatherAlertSpec.m in Sources */, 5DC09EDA1F2F7FEC00F4AB1D /* SDLControlFramePayloadNakSpec.m in Sources */, + 5D76751622D920FD00E8D71A /* SDLMenuConfigurationSpec.m in Sources */, 1EB59CCE202DC97900343A61 /* SDLMassageCushionSpec.m in Sources */, 162E83041A9BDE8B00906325 /* SDLUpdateModeSpec.m in Sources */, 8855F9E0220C93B700A5C897 /* SDLWeatherDataSpec.m in Sources */, diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m index ee6f61278..b23b5ced6 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m @@ -9,6 +9,7 @@ describe(@"a menu cell", ^{ __block SDLMenuCell *testCell = nil; __block SDLMenuCell *testCell2 = nil; + __block SDLMenuLayout testLayout = SDLMenuLayoutList; describe(@"initializing", ^{ __block NSString *someTitle = nil; @@ -43,29 +44,44 @@ expect(testCell.icon).to(beNil()); expect(testCell.voiceCommands).to(beNil()); expect(testCell.subCells).to(equal(someSubcells)); + expect(testCell.submenuLayout).to(beNil()); #pragma clang diagnostic pop }); it(@"should initialize properly as a submenu item with icon", ^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" testCell = [[SDLMenuCell alloc] initWithTitle:someTitle icon:someArtwork subCells:someSubcells]; expect(testCell.title).to(equal(someTitle)); expect(testCell.icon).to(equal(someArtwork)); expect(testCell.voiceCommands).to(beNil()); expect(testCell.subCells).to(equal(someSubcells)); + expect(testCell.submenuLayout).to(beNil()); +#pragma clang diagnostic pop + }); + + it(@"should initialize properly as a submenu item with icon and layout", ^{ + testCell = [[SDLMenuCell alloc] initWithTitle:someTitle submenuLayout:testLayout icon:someArtwork subCells:someSubcells]; + + expect(testCell.title).to(equal(someTitle)); + expect(testCell.icon).to(equal(someArtwork)); + expect(testCell.voiceCommands).to(beNil()); + expect(testCell.subCells).to(equal(someSubcells)); + expect(testCell.submenuLayout).to(equal(testLayout)); }); }); describe(@"check cell eqality", ^{ it(@"should compare cells and return true if cells equal", ^{ - testCell = [[SDLMenuCell alloc] initWithTitle:@"Title" icon:nil subCells:@[]]; - testCell2 = [[SDLMenuCell alloc] initWithTitle:@"Title" icon:nil subCells:@[]]; + testCell = [[SDLMenuCell alloc] initWithTitle:@"Title" submenuLayout:testLayout icon:nil subCells:@[]]; + testCell2 = [[SDLMenuCell alloc] initWithTitle:@"Title" submenuLayout:testLayout icon:nil 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 subCells:@[]]; - testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" icon:nil subCells:@[]]; + testCell = [[SDLMenuCell alloc] initWithTitle:@"True" submenuLayout:testLayout icon:nil subCells:@[]]; + testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" submenuLayout:testLayout icon:nil subCells:@[]]; expect([testCell isEqual:testCell2]).to(equal(false)); }); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuConfigurationSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuConfigurationSpec.m new file mode 100644 index 000000000..3c8f5190c --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuConfigurationSpec.m @@ -0,0 +1,28 @@ +#import +#import + +#import "SDLMenuConfiguration.h" + +QuickSpecBegin(SDLMenuConfigurationSpec) + +describe(@"a menu configuration", ^{ + __block SDLMenuConfiguration *testConfiguration = nil; + + describe(@"initializing", ^{ + it(@"should initialize properly with no variables", ^{ + testConfiguration = [[SDLMenuConfiguration alloc] init]; + + expect(testConfiguration.mainMenuLayout).to(equal(SDLMenuLayoutList)); + expect(testConfiguration.defaultSubmenuLayout).to(equal(SDLMenuLayoutList)); + }); + + it(@"should initialize properly when set", ^{ + testConfiguration = [[SDLMenuConfiguration alloc] initWithMainMenuLayout:SDLMenuLayoutTiles defaultSubmenuLayout:SDLMenuLayoutTiles]; + + expect(testConfiguration.mainMenuLayout).to(equal(SDLMenuLayoutTiles)); + expect(testConfiguration.defaultSubmenuLayout).to(equal(SDLMenuLayoutTiles)); + }); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMenuLayoutSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMenuLayoutSpec.m new file mode 100644 index 000000000..ce2b079a6 --- /dev/null +++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMenuLayoutSpec.m @@ -0,0 +1,15 @@ +#import +#import + +#import "SDLMenuLayout.h" + +QuickSpecBegin(SDLMenuLayoutSpec) + +describe(@"Individual Enum Value Tests", ^{ + it(@"Should match internal values", ^{ + expect(SDLMenuLayoutList).to(equal(@"LIST")); + expect(SDLMenuLayoutTiles).to(equal(@"TILES")); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m index 2efd1eee2..5c5e98547 100644 --- a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m +++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLAddSubMenuSpec.m @@ -20,6 +20,7 @@ __block UInt8 position = 27; __block NSString *menuName = @"Welcome to the menu"; __block SDLImage *image = nil; + __block SDLMenuLayout testLayout = SDLMenuLayoutList; beforeEach(^{ image = [[SDLImage alloc] initWithName:@"Test" isTemplate:false]; @@ -47,12 +48,25 @@ }); it(@"should correctly initialize with initWithId:menuName:menuIcon:position:", ^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SDLAddSubMenu *testRequest = [[SDLAddSubMenu alloc] initWithId:menuId menuName:menuName menuIcon:image position:position]; expect(testRequest.menuID).to(equal(@(menuId))); expect(testRequest.position).to(equal(@(position))); expect(testRequest.menuName).to(equal(menuName)); expect(testRequest.menuIcon).to(equal(image)); +#pragma clang diagnostic pop + }); + + it(@"should correctly initialize with initWithId:menuName:menuLayout:menuIcon:position:", ^{ + SDLAddSubMenu *testRequest = [[SDLAddSubMenu alloc] initWithId:menuId menuName:menuName menuLayout:testLayout menuIcon:image position:position]; + + expect(testRequest.menuID).to(equal(@(menuId))); + expect(testRequest.position).to(equal(@(position))); + expect(testRequest.menuName).to(equal(menuName)); + expect(testRequest.menuIcon).to(equal(image)); + expect(testRequest.menuLayout).to(equal(testLayout)); }); it(@"Should set and get correctly", ^ { @@ -62,11 +76,13 @@ testRequest.position = @27; testRequest.menuName = @"Welcome to the menu"; testRequest.menuIcon = image; + testRequest.menuLayout = testLayout; expect(testRequest.menuID).to(equal(@(menuId))); expect(testRequest.position).to(equal(@(position))); expect(testRequest.menuName).to(equal(menuName)); expect(testRequest.menuIcon).to(equal(image)); + expect(testRequest.menuLayout).to(equal(testLayout)); }); it(@"Should get correctly when initialized", ^ { @@ -77,7 +93,8 @@ SDLRPCParameterNameMenuName:@"Welcome to the menu", SDLRPCParameterNameMenuIcon: @{ SDLRPCParameterNameValue: @"Test" - } + }, + SDLRPCParameterNameMenuLayout: testLayout }, SDLRPCParameterNameOperationName:SDLRPCFunctionNameAddSubMenu}} mutableCopy]; #pragma clang diagnostic push @@ -89,6 +106,7 @@ expect(testRequest.position).to(equal(@(position))); expect(testRequest.menuName).to(equal(menuName)); expect(testRequest.menuIcon.value).to(equal(@"Test")); + expect(testRequest.menuLayout).to(equal(testLayout)); }); it(@"Should return nil if not set", ^ { @@ -98,6 +116,7 @@ expect(testRequest.position).to(beNil()); expect(testRequest.menuName).to(beNil()); expect(testRequest.menuIcon).to(beNil()); + expect(testRequest.menuLayout).to(beNil()); }); }); diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m index ab19ae425..fee0a20f0 100644 --- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m +++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m @@ -27,6 +27,8 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" describe(@"Getter/Setter Tests", ^ { + __block NSArray *testLayout = @[SDLMenuLayoutTiles]; + it(@"Should set and get correctly", ^ { SDLDisplayCapabilities* testStruct = [[SDLDisplayCapabilities alloc] init]; @@ -39,6 +41,7 @@ testStruct.templatesAvailable = [@[@"String", @"String", @"String"] mutableCopy]; testStruct.screenParams = screenParams; testStruct.numCustomPresetsAvailable = @43; + testStruct.menuLayoutsAvailable = testLayout; expect(testStruct.displayType).to(equal(SDLDisplayTypeGen26DMA)); expect(testStruct.displayName).to(equal(@"test")); @@ -49,10 +52,11 @@ expect(testStruct.templatesAvailable).to(equal([@[@"String", @"String", @"String"] mutableCopy])); expect(testStruct.screenParams).to(equal(screenParams)); expect(testStruct.numCustomPresetsAvailable).to(equal(@43)); + expect(testStruct.menuLayoutsAvailable).to(equal(testLayout)); }); it(@"Should get correctly when initialized", ^ { - NSMutableDictionary* dict = [@{SDLRPCParameterNameDisplayType:SDLDisplayTypeGen26DMA, + NSMutableDictionary* dict = @{SDLRPCParameterNameDisplayType:SDLDisplayTypeGen26DMA, SDLRPCParameterNameDisplayName: @"test", SDLRPCParameterNameTextFields:[@[textField] mutableCopy], SDLRPCParameterNameImageFields:[@[imageField] mutableCopy], @@ -60,7 +64,9 @@ SDLRPCParameterNameGraphicSupported:@YES, SDLRPCParameterNameTemplatesAvailable:[@[@"String", @"String", @"String"] mutableCopy], SDLRPCParameterNameScreenParams:screenParams, - SDLRPCParameterNameNumberCustomPresetsAvailable:@43} mutableCopy]; + SDLRPCParameterNameNumberCustomPresetsAvailable:@43, + SDLRPCParameterNameMenuLayoutsAvailable: testLayout + }; SDLDisplayCapabilities* testStruct = [[SDLDisplayCapabilities alloc] initWithDictionary:dict]; expect(testStruct.displayType).to(equal(SDLDisplayTypeGen26DMA)); @@ -72,6 +78,7 @@ expect(testStruct.templatesAvailable).to(equal([@[@"String", @"String", @"String"] mutableCopy])); expect(testStruct.screenParams).to(equal(screenParams)); expect(testStruct.numCustomPresetsAvailable).to(equal(@43)); + expect(testStruct.menuLayoutsAvailable).to(equal(testLayout)); }); it(@"Should return nil if not set", ^ { @@ -86,6 +93,7 @@ expect(testStruct.templatesAvailable).to(beNil()); expect(testStruct.screenParams).to(beNil()); expect(testStruct.numCustomPresetsAvailable).to(beNil()); + expect(testStruct.menuLayoutsAvailable).to(beNil()); }); }); From 4ed7407a7b79e9e0aeb0947a1d2366b1b12b2eef Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Mon, 15 Jul 2019 11:14:49 -0400 Subject: [PATCH 04/11] Updating menu configuration add additional checks Add menu manager tests --- SmartDeviceLink/SDLMenuConfiguration.h | 7 ++ SmartDeviceLink/SDLMenuManager.m | 22 +++- SmartDeviceLink/SDLScreenManager.h | 6 +- .../DevAPISpecs/SDLMenuManagerSpec.m | 101 ++++++++++++------ 4 files changed, 100 insertions(+), 36 deletions(-) diff --git a/SmartDeviceLink/SDLMenuConfiguration.h b/SmartDeviceLink/SDLMenuConfiguration.h index 819c40f82..6aefdb2f4 100644 --- a/SmartDeviceLink/SDLMenuConfiguration.h +++ b/SmartDeviceLink/SDLMenuConfiguration.h @@ -22,6 +22,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (strong, nonatomic, readonly) SDLMenuLayout defaultSubmenuLayout; +/** + Initialize a new menu configuration with a main menu layout and a default submenu layout which can be overriden per-submenu if desired. + + @param mainMenuLayout The new main menu layout + @param defaultSubmenuLayout The new default submenu layout + @return The menu configuration + */ - (instancetype)initWithMainMenuLayout:(SDLMenuLayout)mainMenuLayout defaultSubmenuLayout:(SDLMenuLayout)defaultSubmenuLayout; @end diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index dc1f144b2..ee8ecf725 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -18,6 +18,7 @@ #import "SDLDisplayCapabilities+ShowManagerExtensions.h" #import "SDLError.h" #import "SDLFileManager.h" +#import "SDLGlobals.h" #import "SDLImage.h" #import "SDLLogMacros.h" #import "SDLMenuCell.h" @@ -33,6 +34,7 @@ #import "SDLSetDisplayLayoutResponse.h" #import "SDLSetGlobalProperties.h" #import "SDLScreenManager.h" +#import "SDLVersion.h" #import "SDLVoiceCommand.h" NS_ASSUME_NONNULL_BEGIN @@ -113,14 +115,30 @@ - (void)stop { #pragma mark - Setters - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { - _menuConfiguration = menuConfiguration; + if ([[SDLGlobals sharedGlobals].rpcVersion isLessThanVersion:[SDLVersion versionWithMajor:6 minor:0 patch:0]]) { + SDLLogW(@"Menu configurations is only supported on head units with RPC spec version 6.0.0 or later. Currently connected head unit RPC spec version is %@", [SDLGlobals sharedGlobals].rpcVersion); + return; + } + + if (self.currentHMILevel == nil + || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone] + || [self.currentSystemContext isEqualToEnum:SDLSystemContextMenu]) { + SDLLogE(@"Could not set main menu configuration, HMI level: %@, required: 'Not-NONE', system context: %@, required: 'Not MENU'", self.currentHMILevel, self.currentSystemContext); + return; + } SDLSetGlobalProperties *setGlobalsRPC = [[SDLSetGlobalProperties alloc] init]; setGlobalsRPC.menuLayout = menuConfiguration.mainMenuLayout; + + __weak typeof(self) weakself = self; [self.connectionManager sendConnectionRequest:setGlobalsRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + __strong typeof(weakself) strongself = weakself; if (error != nil) { - SDLLogW(@"Could not set main menu configuration: %@", error); + SDLLogE(@"Could not set main menu configuration: %@", error); + return; } + + strongself->_menuConfiguration = menuConfiguration; }]; } diff --git a/SmartDeviceLink/SDLScreenManager.h b/SmartDeviceLink/SDLScreenManager.h index 25ba0d131..5c1bcaf2f 100644 --- a/SmartDeviceLink/SDLScreenManager.h +++ b/SmartDeviceLink/SDLScreenManager.h @@ -117,7 +117,11 @@ typedef void(^SDLPreloadChoiceCompletionHandler)(NSError *__nullable error); #pragma mark Menu /** - The configuration of the menu. Alter this to change the layout of the menu or sub-menus. If this is set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be updated. + The configuration of the menu. Alter this to change the layout of the menu or sub-menus. If this is set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be automatically updated; you will have to send a new menu to see the new submenu layout. + + Setting this parameter will send a message to the remote system. If that message is rejected, your new value will not be set and an error log will be emmitted. + + This only works on head units supporting RPC spec version 6.0 and newer. If the connected head unit does not support this feature, a warning log will be emmitted. */ @property (strong, nonatomic) SDLMenuConfiguration *menuConfiguration; diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m index 2b96e74b0..54c5bb959 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m @@ -2,32 +2,10 @@ #import #import -#import "SDLAddCommand.h" -#import "SDLAddSubMenu.h" -#import "SDLDeleteCommand.h" -#import "SDLDeleteSubMenu.h" -#import "SDLDisplayCapabilities.h" -#import "SDLDisplayType.h" -#import "SDLFileManager.h" -#import "SDLHMILevel.h" -#import "SDLImage.h" -#import "SDLImageField.h" -#import "SDLImageFieldName.h" -#import "SDLMediaClockFormat.h" -#import "SDLMenuCell.h" +#import +#import "SDLGlobals.h" #import "SDLMenuManager.h" -#import "SDLMenuManagerConstants.h" -#import "SDLOnCommand.h" -#import "SDLOnHMIStatus.h" -#import "SDLRegisterAppInterfaceResponse.h" -#import "SDLRPCNotificationNotification.h" -#import "SDLRPCParameterNames.h" -#import "SDLRPCResponseNotification.h" -#import "SDLSetDisplayLayoutResponse.h" -#import "SDLScreenManager.h" -#import "SDLScreenParams.h" -#import "SDLSystemContext.h" -#import "SDLTextField.h" + #import "TestConnectionManager.h" @@ -75,6 +53,8 @@ @interface SDLMenuManager() __block SDLMenuCell *submenuCell = nil; __block SDLMenuCell *submenuImageCell = nil; + __block SDLMenuConfiguration *testMenuConfiguration = nil; + beforeEach(^{ testArtwork = [[SDLArtwork alloc] initWithData:[@"Test data" dataUsingEncoding:NSUTF8StringEncoding] name:@"some artwork name" fileExtension:@"png" persistent:NO]; testArtwork2 = [[SDLArtwork alloc] initWithData:[@"Test data 2" dataUsingEncoding:NSUTF8StringEncoding] name:@"some artwork name 2" fileExtension:@"png" persistent:NO]; @@ -82,9 +62,11 @@ @interface SDLMenuManager() textOnlyCell = [[SDLMenuCell alloc] initWithTitle:@"Test 1" icon:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" icon:nil subCells:@[textOnlyCell, textAndImageCell]]; - submenuImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 4" icon:testArtwork2 subCells:@[textOnlyCell]]; + submenuImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 4" submenuLayout:SDLMenuLayoutTiles icon:testArtwork2 subCells:@[textOnlyCell]]; textOnlyCell2 = [[SDLMenuCell alloc] initWithTitle:@"Test 5" icon:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; + testMenuConfiguration = [[SDLMenuConfiguration alloc] initWithMainMenuLayout:SDLMenuLayoutTiles defaultSubmenuLayout:SDLMenuLayoutList]; + mockConnectionManager = [[TestConnectionManager alloc] init]; mockFileManager = OCMClassMock([SDLFileManager class]); @@ -103,6 +85,7 @@ @interface SDLMenuManager() expect(testManager.lastMenuId).to(equal(1)); expect(testManager.oldMenuCells).to(beEmpty()); expect(testManager.waitingUpdateMenuCells).to(beNil()); + expect(testManager.menuConfiguration).toNot(beNil()); }); describe(@"updating menu cells before HMI is ready", ^{ @@ -135,10 +118,16 @@ @interface SDLMenuManager() context(@"when no HMI level has been received", ^{ beforeEach(^{ testManager.currentHMILevel = nil; - testManager.menuCells = @[textOnlyCell]; }); - it(@"should not update", ^{ + it(@"should not update the menu configuration", ^{ + testManager.menuConfiguration = testMenuConfiguration; + expect(mockConnectionManager.receivedRequests).to(beEmpty()); + expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + }); + + it(@"should not update the menu cells", ^{ + testManager.menuCells = @[textOnlyCell]; expect(mockConnectionManager.receivedRequests).to(beEmpty()); }); }); @@ -147,10 +136,16 @@ @interface SDLMenuManager() beforeEach(^{ testManager.currentHMILevel = SDLHMILevelFull; testManager.currentSystemContext = SDLSystemContextMenu; - testManager.menuCells = @[textOnlyCell]; }); - it(@"should not update", ^{ + it(@"should not update the menu configuration", ^{ + testManager.menuConfiguration = testMenuConfiguration; + expect(mockConnectionManager.receivedRequests).to(beEmpty()); + expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + }); + + it(@"should not update the menu cells", ^{ + testManager.menuCells = @[textOnlyCell]; expect(mockConnectionManager.receivedRequests).to(beEmpty()); }); @@ -171,7 +166,7 @@ @interface SDLMenuManager() }); }); - describe(@"Notificaiton Responses", ^{ + describe(@"Notification Responses", ^{ it(@"should set display capabilities when SDLDidReceiveSetDisplayLayoutResponse is received", ^{ testDisplayCapabilities = [[SDLDisplayCapabilities alloc] init]; @@ -593,7 +588,7 @@ @interface SDLMenuManager() testTriggerSource = triggerSource; }]; - SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" icon:nil subCells:@[cellWithHandler]]; + SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" submenuLayout:SDLMenuLayoutTiles icon:nil subCells:@[cellWithHandler]]; testManager.menuCells = @[submenuCell]; }); @@ -612,7 +607,46 @@ @interface SDLMenuManager() }); }); - context(@"On disconnects", ^{ + describe(@"updating the menu configuration", ^{ + beforeEach(^{ + testManager.currentHMILevel = SDLHMILevelFull; + testManager.currentSystemContext = SDLSystemContextMain; + }); + + context(@"if the connection RPC version is less than 6.0.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithString:@"5.0.0"]; + }); + + it(@"should fail to send a SetGlobalProperties RPC update", ^{ + testManager.menuConfiguration = testMenuConfiguration; + + expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + expect(mockConnectionManager.receivedRequests).to(haveCount(0)); + }); + }); + + context(@"if the connection RPC version is greater than or equal to 6.0.0", ^{ + beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithString:@"6.0.0"]; + }); + + it(@"should send a SetGlobalProperties RPC update", ^{ + testManager.menuConfiguration = testMenuConfiguration; + + expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + expect(mockConnectionManager.receivedRequests).to(haveCount(1)); + + SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; + response.success = @YES; + [mockConnectionManager respondToLastRequestWithResponse:response]; + + expect(testManager.menuConfiguration).to(equal(testMenuConfiguration)); + }); + }); + }); + + context(@"when the manager stops", ^{ beforeEach(^{ [testManager stop]; }); @@ -630,6 +664,7 @@ @interface SDLMenuManager() expect(testManager.lastMenuId).to(equal(1)); expect(testManager.oldMenuCells).to(beEmpty()); expect(testManager.waitingUpdateMenuCells).to(beEmpty()); + expect(testManager.menuConfiguration).toNot(beNil()); }); }); From 07af4979045e00b5f7490274d1cdc648a056d1f5 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 14 Aug 2019 16:28:09 -0400 Subject: [PATCH 05/11] Add additional checks before setting the menu configuration --- SmartDeviceLink/SDLMenuManager.m | 24 ++++++++++++++++++------ SmartDeviceLink/SDLScreenManager.h | 6 ++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 8103d88ef..0afeef786 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -119,15 +119,23 @@ - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { if ([[SDLGlobals sharedGlobals].rpcVersion isLessThanVersion:[SDLVersion versionWithMajor:6 minor:0 patch:0]]) { SDLLogW(@"Menu configurations is only supported on head units with RPC spec version 6.0.0 or later. Currently connected head unit RPC spec version is %@", [SDLGlobals sharedGlobals].rpcVersion); return; - } - - if (self.currentHMILevel == nil + } else if (self.displayCapabilities.menuLayoutsAvailable == nil) { + SDLLogW(@"Could not set the main menu configuration. Which menu layouts can be used is not available"); + return; + } else if (![self.displayCapabilities.menuLayoutsAvailable containsObject:menuConfiguration.mainMenuLayout] + || ![self.displayCapabilities.menuLayoutsAvailable containsObject:menuConfiguration.defaultSubmenuLayout]) { + SDLLogE(@"One or more of the set menu layouts are not available on this system. The menu configuration will not be set. Available menu layouts: %@, set menu layouts: %@", self.displayCapabilities.menuLayoutsAvailable, menuConfiguration); + return; + } else if (self.currentHMILevel == nil || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone] || [self.currentSystemContext isEqualToEnum:SDLSystemContextMenu]) { SDLLogE(@"Could not set main menu configuration, HMI level: %@, required: 'Not-NONE', system context: %@, required: 'Not MENU'", self.currentHMILevel, self.currentSystemContext); return; } + SDLMenuConfiguration *oldConfig = self.menuConfiguration; + self.menuConfiguration = menuConfiguration; + SDLSetGlobalProperties *setGlobalsRPC = [[SDLSetGlobalProperties alloc] init]; setGlobalsRPC.menuLayout = menuConfiguration.mainMenuLayout; @@ -136,10 +144,9 @@ - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { __strong typeof(weakself) strongself = weakself; if (error != nil) { SDLLogE(@"Could not set main menu configuration: %@", error); + strongself.menuConfiguration = oldConfig; return; } - - strongself->_menuConfiguration = menuConfiguration; }]; } @@ -590,7 +597,12 @@ - (SDLAddCommand *)sdl_commandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL) - (SDLAddSubMenu *)sdl_subMenuCommandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL)shouldHaveArtwork position:(UInt16)position { SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? cell.icon.imageRPC : nil; - SDLMenuLayout submenuLayout = cell.submenuLayout ?: self.menuConfiguration.defaultSubmenuLayout; + + SDLMenuLayout submenuLayout = nil; + if (!cell.submenuLayout || ![self.displayCapabilities.menuLayoutsAvailable containsObject:cell.submenuLayout]) { + submenuLayout = self.menuConfiguration.defaultSubmenuLayout; + } + return [[SDLAddSubMenu alloc] initWithId:cell.cellId menuName:cell.title menuLayout:submenuLayout menuIcon:icon position:(UInt8)position]; } diff --git a/SmartDeviceLink/SDLScreenManager.h b/SmartDeviceLink/SDLScreenManager.h index ec5729d8e..05d19067d 100644 --- a/SmartDeviceLink/SDLScreenManager.h +++ b/SmartDeviceLink/SDLScreenManager.h @@ -124,9 +124,11 @@ typedef void(^SDLPreloadChoiceCompletionHandler)(NSError *__nullable error); /** The configuration of the menu. Alter this to change the layout of the menu or sub-menus. If this is set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be automatically updated; you will have to send a new menu to see the new submenu layout. - Setting this parameter will send a message to the remote system. If that message is rejected, your new value will not be set and an error log will be emmitted. + If set menu layouts don't match available menu layouts in DisplayCapabilities, this will emit an error and return without setting the values. - This only works on head units supporting RPC spec version 6.0 and newer. If the connected head unit does not support this feature, a warning log will be emmitted. + Setting this parameter will send a message to the remote system. This value will be set immediately, but if that message is rejected, the original value will be re-set and an error log will be emmitted. + + This only works on head units supporting RPC spec version 6.0 and newer. If the connected head unit does not support this feature, a warning log will be emmitted and nothing will be set. */ @property (strong, nonatomic) SDLMenuConfiguration *menuConfiguration; From b1453341b8960da6f8965d406b86316657e06d8d Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Thu, 15 Aug 2019 13:29:02 -0400 Subject: [PATCH 06/11] Apply suggestions from code review Co-Authored-By: NicoleYarroch --- SmartDeviceLink/SDLScreenManager.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SmartDeviceLink/SDLScreenManager.h b/SmartDeviceLink/SDLScreenManager.h index 05d19067d..16af28aab 100644 --- a/SmartDeviceLink/SDLScreenManager.h +++ b/SmartDeviceLink/SDLScreenManager.h @@ -122,13 +122,13 @@ typedef void(^SDLPreloadChoiceCompletionHandler)(NSError *__nullable error); #pragma mark Menu /** - The configuration of the menu. Alter this to change the layout of the menu or sub-menus. If this is set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be automatically updated; you will have to send a new menu to see the new submenu layout. + Configures the layout of the menu and sub-menus. If set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be automatically updated; you will have to send a new menu to see the new submenu layout. - If set menu layouts don't match available menu layouts in DisplayCapabilities, this will emit an error and return without setting the values. + If set menu layouts don't match available menu layouts in DisplayCapabilities, an error log will be emitted and the layout will not be set. - Setting this parameter will send a message to the remote system. This value will be set immediately, but if that message is rejected, the original value will be re-set and an error log will be emmitted. + Setting this parameter will send a message to the remote system. This value will be set immediately, but if that message is rejected, the original value will be re-set and an error log will be emitted. - This only works on head units supporting RPC spec version 6.0 and newer. If the connected head unit does not support this feature, a warning log will be emmitted and nothing will be set. + This only works on head units supporting RPC spec version 6.0 and newer. If the connected head unit does not support this feature, a warning log will be emitted and nothing will be set. */ @property (strong, nonatomic) SDLMenuConfiguration *menuConfiguration; From c67f71f4bacf434c69a5bfaa2190646a579368e4 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 27 Aug 2019 14:51:19 -0400 Subject: [PATCH 07/11] Fix menu configuration bugs --- SmartDeviceLink/SDLMenuConfiguration.m | 4 ++++ SmartDeviceLink/SDLMenuManager.m | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/SmartDeviceLink/SDLMenuConfiguration.m b/SmartDeviceLink/SDLMenuConfiguration.m index 57befe2d1..2049c83bf 100644 --- a/SmartDeviceLink/SDLMenuConfiguration.m +++ b/SmartDeviceLink/SDLMenuConfiguration.m @@ -24,4 +24,8 @@ - (instancetype)initWithMainMenuLayout:(SDLMenuLayout)mainMenuLayout defaultSubm return self; } +- (NSString *)description { + return [NSString stringWithFormat:@"Menu configuration, main menu layout: %@, submenu default layout: %@", _mainMenuLayout, _defaultSubmenuLayout]; +} + @end diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 0afeef786..089984b6d 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -133,8 +133,8 @@ - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { return; } - SDLMenuConfiguration *oldConfig = self.menuConfiguration; - self.menuConfiguration = menuConfiguration; + SDLMenuConfiguration *oldConfig = _menuConfiguration; + _menuConfiguration = menuConfiguration; SDLSetGlobalProperties *setGlobalsRPC = [[SDLSetGlobalProperties alloc] init]; setGlobalsRPC.menuLayout = menuConfiguration.mainMenuLayout; @@ -599,7 +599,9 @@ - (SDLAddSubMenu *)sdl_subMenuCommandForMenuCell:(SDLMenuCell *)cell withArtwork SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? cell.icon.imageRPC : nil; SDLMenuLayout submenuLayout = nil; - if (!cell.submenuLayout || ![self.displayCapabilities.menuLayoutsAvailable containsObject:cell.submenuLayout]) { + if (cell.submenuLayout && [self.displayCapabilities.menuLayoutsAvailable containsObject:cell.submenuLayout]) { + submenuLayout = cell.submenuLayout; + } else { submenuLayout = self.menuConfiguration.defaultSubmenuLayout; } From 88838ed16ac3826cd6a2ada345c50e16d2469884 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 4 Sep 2019 11:39:19 -0400 Subject: [PATCH 08/11] Fix tests, reorder menu cell initializer parameters, fix documentation, and altering layout while in the menu --- Example Apps/Example ObjC/MenuManager.m | 6 ++-- SmartDeviceLink/SDLMenuCell.h | 4 +-- SmartDeviceLink/SDLMenuCell.m | 6 ++-- SmartDeviceLink/SDLMenuLayout.h | 4 +-- SmartDeviceLink/SDLMenuManager.m | 3 +- SmartDeviceLink/SDLSetGlobalProperties.h | 2 +- .../DevAPISpecs/SDLMenuCellSpec.m | 10 +++--- .../DevAPISpecs/SDLMenuManagerSpec.m | 33 +++++-------------- 8 files changed, 25 insertions(+), 43 deletions(-) diff --git a/Example Apps/Example ObjC/MenuManager.m b/Example Apps/Example ObjC/MenuManager.m index aa209a785..00e58f00a 100644 --- a/Example Apps/Example ObjC/MenuManager.m +++ b/Example Apps/Example ObjC/MenuManager.m @@ -58,7 +58,7 @@ + (SDLMenuCell *)sdlex_menuCellGetAllVehicleDataWithManager:(SDLManager *)manage [submenuItems addObject:cell]; } - return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName submenuLayout:SDLMenuLayoutTiles icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:submenuItems]; + return [[SDLMenuCell alloc] initWithTitle:ACGetAllVehicleDataMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] submenuLayout:SDLMenuLayoutTiles subCells:submenuItems]; } + (NSArray *)sdlex_allVehicleDataTypes { @@ -117,7 +117,7 @@ + (SDLMenuCell *)sdlex_menuCellChangeTemplateWithManager:(SDLManager *)manager { }]; [submenuItems addObject:cell2]; - return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName submenuLayout:SDLMenuLayoutList icon:nil subCells:[submenuItems copy]]; + return [[SDLMenuCell alloc] initWithTitle:ACSubmenuTemplateMenuName icon:nil submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy]]; } + (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager { @@ -129,7 +129,7 @@ + (SDLMenuCell *)sdlex_menuCellWithSubmenuWithManager:(SDLManager *)manager { [submenuItems addObject:cell]; } - return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName submenuLayout:SDLMenuLayoutList icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] subCells:[submenuItems copy]]; + return [[SDLMenuCell alloc] initWithTitle:ACSubmenuMenuName icon:[SDLArtwork artworkWithImage:[[UIImage imageNamed:MenuBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG] submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy]]; } + (SDLMenuCell *)sdlex_sliderMenuCellWithManager:(SDLManager *)manager { diff --git a/SmartDeviceLink/SDLMenuCell.h b/SmartDeviceLink/SDLMenuCell.h index 1bb1602b6..5d5d1ea2b 100644 --- a/SmartDeviceLink/SDLMenuCell.h +++ b/SmartDeviceLink/SDLMenuCell.h @@ -83,12 +83,12 @@ typedef void(^SDLMenuCellSelectionHandler)(SDLTriggerSource triggerSource); 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 layout The layout that the subCells will be layed out in if that submenu is entered @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 @return The menu cell */ -- (instancetype)initWithTitle:(NSString *)title submenuLayout:(nullable SDLMenuLayout)layout icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells; +- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray *)subCells; @end diff --git a/SmartDeviceLink/SDLMenuCell.m b/SmartDeviceLink/SDLMenuCell.m index 126ecc168..67281cb21 100644 --- a/SmartDeviceLink/SDLMenuCell.m +++ b/SmartDeviceLink/SDLMenuCell.m @@ -37,14 +37,14 @@ - (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon } - (instancetype)initWithTitle:(NSString *)title subCells:(NSArray *)subCells { - return [self initWithTitle:title submenuLayout:nil icon:nil subCells:subCells]; + return [self initWithTitle:title icon:nil submenuLayout:nil subCells:subCells]; } - (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells { - return [self initWithTitle:title submenuLayout:nil icon:nil subCells:subCells]; + return [self initWithTitle:title icon:icon submenuLayout:nil subCells:subCells]; } -- (instancetype)initWithTitle:(NSString *)title submenuLayout:(nullable SDLMenuLayout)layout icon:(nullable SDLArtwork *)icon subCells:(NSArray *)subCells { +- (instancetype)initWithTitle:(NSString *)title icon:(nullable SDLArtwork *)icon submenuLayout:(nullable SDLMenuLayout)layout subCells:(NSArray *)subCells { self = [super init]; if (!self) { return nil; } diff --git a/SmartDeviceLink/SDLMenuLayout.h b/SmartDeviceLink/SDLMenuLayout.h index ee55a0b44..e2fe8e40a 100644 --- a/SmartDeviceLink/SDLMenuLayout.h +++ b/SmartDeviceLink/SDLMenuLayout.h @@ -14,12 +14,12 @@ typedef SDLEnum SDLMenuLayout SDL_SWIFT_ENUM; /** - * STREAMABLE, the current app is allowed to stream video + * The menu should be laid out in a scrollable list format with one menu cell below the previous, each is stretched across the view */ extern SDLMenuLayout const SDLMenuLayoutList; /** - * NOT_STREAMABLE, the current app is not allowed to stream video + * The menu should be laid out in a scrollable tiles format with each menu cell laid out in a square-ish format next to each other horizontally */ extern SDLMenuLayout const SDLMenuLayoutTiles; diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 089984b6d..ff4294540 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -127,8 +127,7 @@ - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { SDLLogE(@"One or more of the set menu layouts are not available on this system. The menu configuration will not be set. Available menu layouts: %@, set menu layouts: %@", self.displayCapabilities.menuLayoutsAvailable, menuConfiguration); return; } else if (self.currentHMILevel == nil - || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone] - || [self.currentSystemContext isEqualToEnum:SDLSystemContextMenu]) { + || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone]) { SDLLogE(@"Could not set main menu configuration, HMI level: %@, required: 'Not-NONE', system context: %@, required: 'Not MENU'", self.currentHMILevel, self.currentSystemContext); return; } diff --git a/SmartDeviceLink/SDLSetGlobalProperties.h b/SmartDeviceLink/SDLSetGlobalProperties.h index 4fbe5c679..10f8a35a2 100644 --- a/SmartDeviceLink/SDLSetGlobalProperties.h +++ b/SmartDeviceLink/SDLSetGlobalProperties.h @@ -122,7 +122,7 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic, nullable) SDLKeyboardProperties *keyboardProperties; /** - The main menu layout. See available menu layouts on DisplayCapabilities.menuLayoutsAvailable. Defaults to LIST. + The main menu layout. If this is sent while a menu is already on-screen, the head unit will change the display to the new layout type. See available menu layouts on DisplayCapabilities.menuLayoutsAvailable. Defaults to the head unit default. */ @property (strong, nonatomic, nullable) SDLMenuLayout menuLayout; diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m index b23b5ced6..ab8b281fd 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuCellSpec.m @@ -62,7 +62,7 @@ }); it(@"should initialize properly as a submenu item with icon and layout", ^{ - testCell = [[SDLMenuCell alloc] initWithTitle:someTitle submenuLayout:testLayout icon:someArtwork subCells:someSubcells]; + testCell = [[SDLMenuCell alloc] initWithTitle:someTitle icon:someArtwork submenuLayout:testLayout subCells:someSubcells]; expect(testCell.title).to(equal(someTitle)); expect(testCell.icon).to(equal(someArtwork)); @@ -73,15 +73,15 @@ }); describe(@"check cell eqality", ^{ it(@"should compare cells and return true if cells equal", ^{ - testCell = [[SDLMenuCell alloc] initWithTitle:@"Title" submenuLayout:testLayout icon:nil subCells:@[]]; - testCell2 = [[SDLMenuCell alloc] initWithTitle:@"Title" submenuLayout:testLayout icon:nil subCells:@[]]; + testCell = [[SDLMenuCell alloc] initWithTitle:@"Title" icon:nil submenuLayout:testLayout subCells:@[]]; + testCell2 = [[SDLMenuCell alloc] initWithTitle:@"Title" icon:nil 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" submenuLayout:testLayout icon:nil subCells:@[]]; - testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" submenuLayout:testLayout icon:nil subCells:@[]]; + testCell = [[SDLMenuCell alloc] initWithTitle:@"True" icon:nil submenuLayout:testLayout subCells:@[]]; + testCell2 = [[SDLMenuCell alloc] initWithTitle:@"False" icon:nil submenuLayout:testLayout subCells:@[]]; expect([testCell isEqual:testCell2]).to(equal(false)); }); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m index 73b17fec7..922efdbd5 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m @@ -61,8 +61,8 @@ @interface SDLMenuManager() textOnlyCell = [[SDLMenuCell alloc] initWithTitle:@"Test 1" icon:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; textAndImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 2" icon:testArtwork voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; - submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" icon:nil subCells:@[textOnlyCell, textAndImageCell]]; - submenuImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 4" submenuLayout:SDLMenuLayoutTiles icon:testArtwork2 subCells:@[textOnlyCell]]; + submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Test 3" icon:nil submenuLayout:nil subCells:@[textOnlyCell, textAndImageCell]]; + submenuImageCell = [[SDLMenuCell alloc] initWithTitle:@"Test 4" icon:testArtwork2 submenuLayout:SDLMenuLayoutTiles subCells:@[textOnlyCell]]; textOnlyCell2 = [[SDLMenuCell alloc] initWithTitle:@"Test 5" icon:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {}]; testMenuConfiguration = [[SDLMenuConfiguration alloc] initWithMainMenuLayout:SDLMenuLayoutTiles defaultSubmenuLayout:SDLMenuLayoutList]; @@ -134,35 +134,16 @@ @interface SDLMenuManager() context(@"when in the menu", ^{ beforeEach(^{ + [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithString:@"6.0.0"]; testManager.currentHMILevel = SDLHMILevelFull; testManager.currentSystemContext = SDLSystemContextMenu; }); - it(@"should not update the menu configuration", ^{ + it(@"should update the menu configuration", ^{ testManager.menuConfiguration = testMenuConfiguration; expect(mockConnectionManager.receivedRequests).to(beEmpty()); expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); }); - - it(@"should not update the menu cells", ^{ - testManager.menuCells = @[textOnlyCell]; - expect(mockConnectionManager.receivedRequests).to(beEmpty()); - }); - - describe(@"when exiting the menu", ^{ - beforeEach(^{ - SDLOnHMIStatus *onHMIStatus = [[SDLOnHMIStatus alloc] init]; - onHMIStatus.hmiLevel = SDLHMILevelFull; - onHMIStatus.systemContext = SDLSystemContextMain; - - SDLRPCNotificationNotification *testSystemContextNotification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:onHMIStatus]; - [[NSNotificationCenter defaultCenter] postNotification:testSystemContextNotification]; - }); - - it(@"should update", ^{ - expect(mockConnectionManager.receivedRequests).toNot(beEmpty()); - }); - }); }); }); @@ -588,7 +569,7 @@ @interface SDLMenuManager() testTriggerSource = triggerSource; }]; - SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" submenuLayout:SDLMenuLayoutTiles icon:nil subCells:@[cellWithHandler]]; + SDLMenuCell *submenuCell = [[SDLMenuCell alloc] initWithTitle:@"Submenu" icon:nil submenuLayout:SDLMenuLayoutTiles subCells:@[cellWithHandler]]; testManager.menuCells = @[submenuCell]; }); @@ -629,12 +610,14 @@ @interface SDLMenuManager() context(@"if the connection RPC version is greater than or equal to 6.0.0", ^{ beforeEach(^{ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithString:@"6.0.0"]; + testManager.displayCapabilities = [[SDLDisplayCapabilities alloc] init]; + testManager.displayCapabilities.menuLayoutsAvailable = @[SDLMenuLayoutList, SDLMenuLayoutTiles]; }); it(@"should send a SetGlobalProperties RPC update", ^{ testManager.menuConfiguration = testMenuConfiguration; - expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + expect(testManager.menuConfiguration).to(equal(testMenuConfiguration)); expect(mockConnectionManager.receivedRequests).to(haveCount(1)); SDLSetGlobalPropertiesResponse *response = [[SDLSetGlobalPropertiesResponse alloc] init]; From 3f37df30878f6322561e06c0a39527022c9fbcd4 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 4 Sep 2019 12:00:45 -0400 Subject: [PATCH 09/11] Move `menuLayoutsAvailable` to `SDLWindowCapability` --- SmartDeviceLink/SDLDisplayCapabilities.h | 8 -------- SmartDeviceLink/SDLDisplayCapabilities.m | 8 -------- SmartDeviceLink/SDLWindowCapability.h | 8 ++++++++ SmartDeviceLink/SDLWindowCapability.m | 8 ++++++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/SmartDeviceLink/SDLDisplayCapabilities.h b/SmartDeviceLink/SDLDisplayCapabilities.h index ed856ccdf..b5644379f 100644 --- a/SmartDeviceLink/SDLDisplayCapabilities.h +++ b/SmartDeviceLink/SDLDisplayCapabilities.h @@ -5,7 +5,6 @@ #import "SDLDisplayType.h" #import "SDLMediaClockFormat.h" -#import "SDLMenuLayout.h" @class SDLImageField; @class SDLScreenParams; @@ -98,13 +97,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nullable, strong, nonatomic) NSNumber *numCustomPresetsAvailable; -/** - An array of available menu layouts. If this parameter is not provided, only the `LIST` layout is assumed to be available. - - Optional, array of 1 to 100, see SDLMenuLayout - */ -@property (nullable, strong, nonatomic) NSArray *menuLayoutsAvailable; - @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLDisplayCapabilities.m b/SmartDeviceLink/SDLDisplayCapabilities.m index e9362e754..b85208a83 100644 --- a/SmartDeviceLink/SDLDisplayCapabilities.m +++ b/SmartDeviceLink/SDLDisplayCapabilities.m @@ -89,14 +89,6 @@ - (void)setNumCustomPresetsAvailable:(nullable NSNumber *)numCustomPrese return [self.store sdl_objectForName:SDLRPCParameterNameNumberCustomPresetsAvailable ofClass:NSNumber.class error:nil]; } -- (void)setMenuLayoutsAvailable:(nullable NSArray *)menuLayoutsAvailable { - [self.store sdl_setObject:menuLayoutsAvailable forName:SDLRPCParameterNameMenuLayoutsAvailable]; -} - -- (nullable NSArray *)menuLayoutsAvailable { - return [self.store sdl_enumsForName:SDLRPCParameterNameMenuLayoutsAvailable error:nil]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLWindowCapability.h b/SmartDeviceLink/SDLWindowCapability.h index b569f0020..a68eb0127 100644 --- a/SmartDeviceLink/SDLWindowCapability.h +++ b/SmartDeviceLink/SDLWindowCapability.h @@ -4,6 +4,7 @@ #import "SDLRPCStruct.h" #import "SDLImageType.h" +#import "SDLMenuLayout.h" @class SDLTextField; @class SDLImageField; @@ -76,6 +77,13 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nullable, strong, nonatomic) NSArray *softButtonCapabilities; +/** + An array of available menu layouts. If this parameter is not provided, only the `LIST` layout is assumed to be available. + + Optional, array of 1 to 100, see SDLMenuLayout + */ +@property (nullable, strong, nonatomic) NSArray *menuLayoutsAvailable; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLWindowCapability.m b/SmartDeviceLink/SDLWindowCapability.m index 3e30a2b4c..fc52b3efb 100644 --- a/SmartDeviceLink/SDLWindowCapability.m +++ b/SmartDeviceLink/SDLWindowCapability.m @@ -70,4 +70,12 @@ - (void)setSoftButtonCapabilities:(nullable NSArray return [self.store sdl_objectsForName:SDLRPCParameterNameSoftButtonCapabilities ofClass:SDLSoftButtonCapabilities.class error:nil]; } +- (void)setMenuLayoutsAvailable:(nullable NSArray *)menuLayoutsAvailable { + [self.store sdl_setObject:menuLayoutsAvailable forName:SDLRPCParameterNameMenuLayoutsAvailable]; +} + +- (nullable NSArray *)menuLayoutsAvailable { + return [self.store sdl_enumsForName:SDLRPCParameterNameMenuLayoutsAvailable error:nil]; +} + @end From 6b1c0e5d6bd92adc8852803e15de29800d0a3517 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Fri, 4 Oct 2019 15:21:24 -0400 Subject: [PATCH 10/11] Use updated system capability manager displays --- SmartDeviceLink/SDLMenuManager.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/SmartDeviceLink/SDLMenuManager.m b/SmartDeviceLink/SDLMenuManager.m index 9d368ea2b..aa3a1e22f 100644 --- a/SmartDeviceLink/SDLMenuManager.m +++ b/SmartDeviceLink/SDLMenuManager.m @@ -53,6 +53,7 @@ @interface SDLMenuCell() @interface SDLMenuManager() +// Dependencies @property (weak, nonatomic) id connectionManager; @property (weak, nonatomic) SDLFileManager *fileManager; @property (weak, nonatomic) SDLSystemCapabilityManager *systemCapabilityManager; @@ -118,15 +119,17 @@ - (void)stop { #pragma mark - Setters - (void)setMenuConfiguration:(SDLMenuConfiguration *)menuConfiguration { + NSArray *layoutsAvailable = self.systemCapabilityManager.defaultMainWindowCapability.menuLayoutsAvailable; + if ([[SDLGlobals sharedGlobals].rpcVersion isLessThanVersion:[SDLVersion versionWithMajor:6 minor:0 patch:0]]) { SDLLogW(@"Menu configurations is only supported on head units with RPC spec version 6.0.0 or later. Currently connected head unit RPC spec version is %@", [SDLGlobals sharedGlobals].rpcVersion); return; - } else if (self.displayCapabilities.menuLayoutsAvailable == nil) { + } else if (layoutsAvailable == nil) { SDLLogW(@"Could not set the main menu configuration. Which menu layouts can be used is not available"); return; - } else if (![self.displayCapabilities.menuLayoutsAvailable containsObject:menuConfiguration.mainMenuLayout] - || ![self.displayCapabilities.menuLayoutsAvailable containsObject:menuConfiguration.defaultSubmenuLayout]) { - SDLLogE(@"One or more of the set menu layouts are not available on this system. The menu configuration will not be set. Available menu layouts: %@, set menu layouts: %@", self.displayCapabilities.menuLayoutsAvailable, menuConfiguration); + } else if (![layoutsAvailable containsObject:menuConfiguration.mainMenuLayout] + || ![layoutsAvailable containsObject:menuConfiguration.defaultSubmenuLayout]) { + SDLLogE(@"One or more of the set menu layouts are not available on this system. The menu configuration will not be set. Available menu layouts: %@, set menu layouts: %@", layoutsAvailable, menuConfiguration); return; } else if (self.currentHMILevel == nil || [self.currentHMILevel isEqualToEnum:SDLHMILevelNone]) { @@ -600,7 +603,7 @@ - (SDLAddSubMenu *)sdl_subMenuCommandForMenuCell:(SDLMenuCell *)cell withArtwork SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? cell.icon.imageRPC : nil; SDLMenuLayout submenuLayout = nil; - if (cell.submenuLayout && [self.displayCapabilities.menuLayoutsAvailable containsObject:cell.submenuLayout]) { + if (cell.submenuLayout && [self.systemCapabilityManager.defaultMainWindowCapability.menuLayoutsAvailable containsObject:cell.submenuLayout]) { submenuLayout = cell.submenuLayout; } else { submenuLayout = self.menuConfiguration.defaultSubmenuLayout; From bea63601ac45b2956da49d257913885df1368a05 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 9 Oct 2019 14:03:19 -0400 Subject: [PATCH 11/11] Fix tests and documentation around menuLayoutsAvailable --- SmartDeviceLink/SDLAddSubMenu.h | 2 +- SmartDeviceLink/SDLScreenManager.h | 2 +- SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m | 9 ++++----- .../RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m | 9 +-------- .../RPCSpecs/StructSpecs/SDLDisplayCapabilitySpec.m | 1 - .../RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m | 3 ++- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/SmartDeviceLink/SDLAddSubMenu.h b/SmartDeviceLink/SDLAddSubMenu.h index edc8babc5..338ecd645 100644 --- a/SmartDeviceLink/SDLAddSubMenu.h +++ b/SmartDeviceLink/SDLAddSubMenu.h @@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic, nullable) SDLImage *menuIcon; /** - The sub-menu layout. See available menu layouts on DisplayCapabilities.menuLayoutsAvailable. Defaults to LIST. + The sub-menu layout. See available menu layouts on SDLWindowCapability.menuLayoutsAvailable. Defaults to LIST. */ @property (strong, nonatomic, nullable) SDLMenuLayout menuLayout; diff --git a/SmartDeviceLink/SDLScreenManager.h b/SmartDeviceLink/SDLScreenManager.h index 8275d79a0..0df4c21a6 100644 --- a/SmartDeviceLink/SDLScreenManager.h +++ b/SmartDeviceLink/SDLScreenManager.h @@ -126,7 +126,7 @@ typedef void(^SDLPreloadChoiceCompletionHandler)(NSError *__nullable error); /** Configures the layout of the menu and sub-menus. If set after a menu already exists, the existing main menu layout will be updated, _HOWEVER_ sub-menus will not be automatically updated; you will have to send a new menu to see the new submenu layout. - If set menu layouts don't match available menu layouts in DisplayCapabilities, an error log will be emitted and the layout will not be set. + If set menu layouts don't match available menu layouts in WindowCapability, an error log will be emitted and the layout will not be set. Setting this parameter will send a message to the remote system. This value will be set immediately, but if that message is rejected, the original value will be re-set and an error log will be emitted. diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m index 5913be833..815105331 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLMenuManagerSpec.m @@ -78,6 +78,7 @@ @interface SDLMenuManager() windowCapability.windowID = @(SDLPredefinedWindowsDefaultWindow); windowCapability.imageFields = @[commandIconField]; windowCapability.imageTypeSupported = @[SDLImageTypeDynamic, SDLImageTypeStatic]; + windowCapability.menuLayoutsAvailable = @[SDLMenuLayoutList, SDLMenuLayoutTiles]; SDLDisplayCapability *displayCapability = [[SDLDisplayCapability alloc] initWithDisplayName:SDLDisplayTypeGeneric]; displayCapability.windowCapabilities = @[windowCapability]; @@ -152,10 +153,10 @@ @interface SDLMenuManager() testManager.currentSystemContext = SDLSystemContextMenu; }); - it(@"should update the menu configuration", ^{ + fit(@"should update the menu configuration", ^{ testManager.menuConfiguration = testMenuConfiguration; - expect(mockConnectionManager.receivedRequests).to(beEmpty()); - expect(testManager.menuConfiguration).toNot(equal(testMenuConfiguration)); + expect(mockConnectionManager.receivedRequests).toNot(beEmpty()); + expect(testManager.menuConfiguration).to(equal(testMenuConfiguration)); }); }); }); @@ -583,8 +584,6 @@ @interface SDLMenuManager() context(@"if the connection RPC version is greater than or equal to 6.0.0", ^{ beforeEach(^{ [SDLGlobals sharedGlobals].rpcVersion = [SDLVersion versionWithString:@"6.0.0"]; - testManager.displayCapabilities = [[SDLDisplayCapabilities alloc] init]; - testManager.displayCapabilities.menuLayoutsAvailable = @[SDLMenuLayoutList, SDLMenuLayoutTiles]; }); it(@"should send a SetGlobalProperties RPC update", ^{ diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m index fee0a20f0..6e89c7461 100644 --- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m +++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitiesSpec.m @@ -27,8 +27,6 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" describe(@"Getter/Setter Tests", ^ { - __block NSArray *testLayout = @[SDLMenuLayoutTiles]; - it(@"Should set and get correctly", ^ { SDLDisplayCapabilities* testStruct = [[SDLDisplayCapabilities alloc] init]; @@ -41,8 +39,7 @@ testStruct.templatesAvailable = [@[@"String", @"String", @"String"] mutableCopy]; testStruct.screenParams = screenParams; testStruct.numCustomPresetsAvailable = @43; - testStruct.menuLayoutsAvailable = testLayout; - + expect(testStruct.displayType).to(equal(SDLDisplayTypeGen26DMA)); expect(testStruct.displayName).to(equal(@"test")); expect(testStruct.textFields).to(equal([@[textField] mutableCopy])); @@ -52,7 +49,6 @@ expect(testStruct.templatesAvailable).to(equal([@[@"String", @"String", @"String"] mutableCopy])); expect(testStruct.screenParams).to(equal(screenParams)); expect(testStruct.numCustomPresetsAvailable).to(equal(@43)); - expect(testStruct.menuLayoutsAvailable).to(equal(testLayout)); }); it(@"Should get correctly when initialized", ^ { @@ -65,7 +61,6 @@ SDLRPCParameterNameTemplatesAvailable:[@[@"String", @"String", @"String"] mutableCopy], SDLRPCParameterNameScreenParams:screenParams, SDLRPCParameterNameNumberCustomPresetsAvailable:@43, - SDLRPCParameterNameMenuLayoutsAvailable: testLayout }; SDLDisplayCapabilities* testStruct = [[SDLDisplayCapabilities alloc] initWithDictionary:dict]; @@ -78,7 +73,6 @@ expect(testStruct.templatesAvailable).to(equal([@[@"String", @"String", @"String"] mutableCopy])); expect(testStruct.screenParams).to(equal(screenParams)); expect(testStruct.numCustomPresetsAvailable).to(equal(@43)); - expect(testStruct.menuLayoutsAvailable).to(equal(testLayout)); }); it(@"Should return nil if not set", ^ { @@ -93,7 +87,6 @@ expect(testStruct.templatesAvailable).to(beNil()); expect(testStruct.screenParams).to(beNil()); expect(testStruct.numCustomPresetsAvailable).to(beNil()); - expect(testStruct.menuLayoutsAvailable).to(beNil()); }); }); diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitySpec.m index 4cd68a799..1d0aad819 100644 --- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitySpec.m +++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLDisplayCapabilitySpec.m @@ -63,7 +63,6 @@ testWindowCapability.imageTypeSupported = @[testImageType]; testWindowCapability.buttonCapabilities = @[testButtonCapabilities]; testWindowCapability.softButtonCapabilities = @[testSoftButtonscapabilities]; - }); diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m index 0589337ce..94eecde90 100644 --- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m +++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLWindowCapabilitySpec.m @@ -17,7 +17,6 @@ QuickSpecBegin(SDLWindowCapabilitySpec) describe(@"Getter/Setter Tests", ^ { - __block SDLTextField* testTextField = nil; __block SDLImageField *testImageField = nil; __block SDLButtonCapabilities *testButtonCapabilities = nil; @@ -55,6 +54,7 @@ testStruct.imageTypeSupported = @[testImageType]; testStruct.buttonCapabilities = @[testButtonCapabilities]; testStruct.softButtonCapabilities = @[testSoftButtonscapabilities]; + testStruct.menuLayoutsAvailable = @[SDLMenuLayoutTiles]; expect(testStruct.windowID).to(equal(@444)); expect(testStruct.textFields.firstObject.name).to(equal(SDLTextFieldNameTertiaryText)); @@ -65,6 +65,7 @@ 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(@[SDLMenuLayoutTiles])); }); });