Skip to content

Commit

Permalink
Merge pull request #2111 from smartdevicelink/develop
Browse files Browse the repository at this point in the history
v7.6.0 Release
  • Loading branch information
jacobrau-livio authored Oct 26, 2022
2 parents 3869a30 + b234b1b commit a26dbc2
Show file tree
Hide file tree
Showing 45 changed files with 2,679 additions and 209 deletions.
10 changes: 5 additions & 5 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ We use [Gitflow](http://nvie.com/posts/a-successful-git-branching-model/) as our

### Pull Requests
* Please follow the repository's for all code and documentation.
* All feature branches should be based on `develop` and have the format `feature/issue-#num-branch_name`.
* Minor bug fixes, that is bug fixes that do not change, add, or remove any public API, should be based on `develop` and have the format `bugfix/issue-#num-branch_name`, unless they are slated for a hotfix release, in which case they should be based on `master`.
* All pull requests should implement a single feature or fix a single bug related to an open issue. Pull Requests that involve multiple changes (it is our discretion what precisely this means) will be rejected with a reason.
* All feature branches should be based on `develop` and have the format `feature/branch_name`.
* Minor bug fixes, that is bug fixes that do not change, add, or remove any public API, should be based on `master` and have the format `hotfix/branch_name`.
* All pull requests should implement a single feature or fix a single bug. Pull Requests that involve multiple changes (it is our discretion what precisely this means) will be rejected with a reason.
* All commits should separated into logical units, i.e. unrelated changes should be in different commits within a pull request.
* Work in progress pull requests should be Draft PRs. When you believe the pull request is ready to merge, mark them as ready for review to make them an open PR and @mention the appropriate SDL team to schedule a review.
* All new code *must* include unit tests. Bug fixes should have a test that failed previously and now passes. All new features should have test coverage. If your code does not have tests, or regresses old tests, it will be rejected.
* Work in progress pull requests should have "[WIP]" in front of the Pull Request title. When you believe the pull request is ready to merge, remove this tag and @mention the appropriate SDL team to schedule a review.
* All new code *must* include unit tests. Bug fixes should have a test that fails previously and now passes. All new features should be covered. If your code does not have tests, or regresses old tests, it will be rejected.
* Make sure you fill out all sections of the PR template. A great example of a [pull request can be found here](https://github.com/smartdevicelink/sdl_ios/pull/1688).

### Contributor's License Agreement (CLA)
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
# Changelog
## 7.6.0
* Supports [SDL RPC Spec 8.0.0](https://github.com/smartdevicelink/rpc_spec/releases/tag/8.0.0) and [SDL Protocol Spec 5.4.1](https://github.com/smartdevicelink/protocol_spec/releases/tag/5.4.1).

### Testing
* Xcode 14.0
* iOS 15.7 / iOS 16.0
* Core:
* Manticore (Core v8.1.0, Generic HMI v0.12.0)
* Ford Sync 3.4 (19353_DEVTEST)
* Ford Sync 3.0 (17276_DEVTEST)
* Ford Sync 4.0 (20016_DEVTEST)
* Core v8.2.0-RC with sdl_hmi v5.8.0-RC and generic_hmi v0.13.0-RC

### Bug Fixes
* SDLProtocol message parsing should use a state machine (https://github.com/smartdevicelink/sdl_ios/issues/17)
* Default cellID value passed in during openSubMenu method call (https://github.com/smartdevicelink/sdl_ios/issues/1633)
* SDLTouchManagerDelegate's didReceivePinchInView is never called in the codebase (https://github.com/smartdevicelink/sdl_ios/issues/1637)
* Setting bad data in one T&G field then good data quickly in another can lead to the good data failing (https://github.com/smartdevicelink/sdl_ios/issues/1781)
* SystemCapabilityManager screenParams nil, mediaClockFormats empty, and windowID nil when they shouldn't be (https://github.com/smartdevicelink/sdl_ios/issues/2105)
* Alert images that are flagged for overwrite fail to display (https://github.com/smartdevicelink/sdl_ios/issues/2109)
* Fix iAP write data range error (https://github.com/smartdevicelink/sdl_ios/issues/2112)

### Other
* Use a script to include public header files based on project settings (https://github.com/smartdevicelink/sdl_ios/issues/179)
* Missing a remote control example in example app (https://github.com/smartdevicelink/sdl_ios/issues/2101)
* Release Script Bugs (https://github.com/smartdevicelink/sdl_ios/issues/2098)

## 7.5.0
* Supports [SDL RPC Spec 8.0.0](https://github.com/smartdevicelink/rpc_spec/releases/tag/8.0.0) and [SDL Protocol Spec 5.4.1](https://github.com/smartdevicelink/protocol_spec/releases/tag/5.4.1).

Expand Down
3 changes: 2 additions & 1 deletion Example Apps/Example ObjC/MenuManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>

@class PerformInteractionManager;
@class RemoteControlManager;
@class SDLManager;
@class SDLMenuCell;
@class SDLVoiceCommand;
Expand All @@ -17,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface MenuManager : NSObject

+ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager performManager:(PerformInteractionManager *)performManager;
+ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager performManager:(PerformInteractionManager *)performManager remoteManager:(RemoteControlManager *)remoteManager;
+ (NSArray<SDLVoiceCommand *> *)allVoiceMenuItemsWithManager:(SDLManager *)manager;

@end
Expand Down
55 changes: 51 additions & 4 deletions Example Apps/Example ObjC/MenuManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,24 @@
//

#import "MenuManager.h"

#import "AlertManager.h"
#import "AudioManager.h"
#import "AppConstants.h"
#import "PerformInteractionManager.h"
#import "RPCPermissionsManager.h"
#import "SmartDeviceLink.h"
#import "VehicleDataManager.h"
#import "RemoteControlManager.h"

NS_ASSUME_NONNULL_BEGIN

@implementation MenuManager

+ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager performManager:(PerformInteractionManager *)performManager {
+ (NSArray<SDLMenuCell *> *)allMenuItemsWithManager:(SDLManager *)manager performManager:(PerformInteractionManager *)performManager remoteManager:(RemoteControlManager *)remoteControlManager {
return @[[self sdlex_menuCellSpeakNameWithManager:manager],
[self sdlex_menuCellGetAllVehicleDataWithManager:manager],
[self sdlex_menuCellRemoteWithManager:manager remoteManager:remoteControlManager],
[self sdlex_menuCellShowPerformInteractionWithManager:manager performManager:performManager],
[self sdlex_sliderMenuCellWithManager:manager],
[self sdlex_scrollableMessageMenuCellWithManager:manager],
Expand Down Expand Up @@ -91,7 +94,7 @@ + (SDLMenuCell *)sdlex_menuCellDialNumberWithManager:(SDLManager *)manager {

+ (SDLMenuCell *)sdlex_menuCellChangeTemplateWithManager:(SDLManager *)manager {

/// Lets give an example of 2 templates
// Lets give an example of 2 templates
NSMutableArray *submenuItems = [NSMutableArray array];
NSString *errorMessage = @"Changing the template failed";

Expand Down Expand Up @@ -134,7 +137,7 @@ + (SDLMenuCell *)sdlex_sliderMenuCellWithManager:(SDLManager *)manager {
return [[SDLMenuCell alloc] initWithTitle:ACSliderMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[ACSliderMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
SDLSlider *sliderRPC = [[SDLSlider alloc] initWithNumTicks:3 position:1 sliderHeader:@"Select a letter" sliderFooters:@[@"A", @"B", @"C"] timeout:10000];
[manager sendRequest:sliderRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if(![response.resultCode isEqualToEnum:SDLResultSuccess]) {
if (![response.resultCode isEqualToEnum:SDLResultSuccess]) {
if ([response.resultCode isEqualToEnum:SDLResultTimedOut]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertSliderTimedOutWarningText textField2:nil];
} else if ([response.resultCode isEqualToEnum:SDLResultAborted]) {
Expand All @@ -151,7 +154,7 @@ + (SDLMenuCell *)sdlex_scrollableMessageMenuCellWithManager:(SDLManager *)manage
return [[SDLMenuCell alloc] initWithTitle:ACScrollableMessageMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:@[ACScrollableMessageMenuName] handler:^(SDLTriggerSource _Nonnull triggerSource) {
SDLScrollableMessage *messageRPC = [[SDLScrollableMessage alloc] initWithMessage:@"This is a scrollable message\nIt can contain many lines"];
[manager sendRequest:messageRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if(![response.resultCode isEqualToEnum:SDLResultSuccess]) {
if (![response.resultCode isEqualToEnum:SDLResultSuccess]) {
if ([response.resultCode isEqualToEnum:SDLResultTimedOut]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertScrollableMessageTimedOutWarningText textField2:nil];
} else if ([response.resultCode isEqualToEnum:SDLResultAborted]) {
Expand All @@ -164,6 +167,50 @@ + (SDLMenuCell *)sdlex_scrollableMessageMenuCellWithManager:(SDLManager *)manage
}];
}

+ (SDLMenuCell *)sdlex_menuCellRemoteWithManager:(SDLManager *)manager remoteManager:(RemoteControlManager *)remoteManager {
SDLArtwork *remoteControlIcon = [SDLArtwork artworkWithImage:[[UIImage imageNamed:RemoteControlIconName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG];

// Clicking on cell shows alert message when remote control permissions are disabled
if (!remoteManager.isEnabled) {
return [[SDLMenuCell alloc] initWithTitle:ACRemoteMenuName secondaryText:nil tertiaryText:nil icon:remoteControlIcon secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertRemoteControlNotEnabledWarningText textField2:nil];
}];
}

// Let's give an example of 2 templates
NSMutableArray *submenuItems = [NSMutableArray array];
NSString *errorMessage = @"Changing the template failed";

// Climate Control
SDLMenuCell *climateControlCell = [[SDLMenuCell alloc] initWithTitle:ACRemoteControlClimateMenuName secondaryText:nil tertiaryText:nil icon: nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
[manager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithPredefinedLayout:SDLPredefinedLayoutTilesOnly] withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[AlertManager sendAlertWithManager:manager image:nil textField1:errorMessage textField2:nil];
return;
}
[remoteManager showClimateControl];
}];
}];
[submenuItems addObject:climateControlCell];

// View Climate
SDLMenuCell *viewClimateCell = [[SDLMenuCell alloc] initWithTitle:ACRemoteViewClimateMenuName secondaryText:nil tertiaryText:nil icon:nil secondaryArtwork:nil voiceCommands:nil handler:^(SDLTriggerSource _Nonnull triggerSource) {
SDLScrollableMessage *messageRPC = [[SDLScrollableMessage alloc] initWithMessage:remoteManager.climateDataString];
[manager sendRequest:messageRPC withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
if ([response.resultCode isEqualToEnum:SDLResultTimedOut]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertScrollableMessageTimedOutWarningText textField2:nil];
} else if ([response.resultCode isEqualToEnum:SDLResultAborted]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertScrollableMessageCancelledWarningText textField2:nil];
} else if (![response.resultCode isEqualToEnum:SDLResultSuccess]) {
[AlertManager sendAlertWithManager:manager image:nil textField1:AlertScrollableMessageGeneralWarningText textField2:nil];
}
}];
}];
[submenuItems addObject:viewClimateCell];

return [[SDLMenuCell alloc] initWithTitle:ACRemoteMenuName secondaryText:nil tertiaryText:nil icon:remoteControlIcon secondaryArtwork:nil submenuLayout:SDLMenuLayoutList subCells:[submenuItems copy]];
}

#pragma mark - Voice Commands

+ (SDLVoiceCommand *)sdlex_voiceCommandStartWithManager:(SDLManager *)manager {
Expand Down
28 changes: 21 additions & 7 deletions Example Apps/Example ObjC/ProxyManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "PerformInteractionManager.h"
#import "Preferences.h"
#import "ProxyManager.h"
#import "RemoteControlManager.h"
#import "RPCPermissionsManager.h"
#import "SmartDeviceLink.h"
#import "SubscribeButtonManager.h"
Expand All @@ -22,6 +23,8 @@ @interface ProxyManager () <SDLManagerDelegate>
// Describes the first time the HMI state goes non-none and full.
@property (assign, nonatomic) SDLHMILevel firstHMILevel;

@property (assign, nonatomic, getter=isRemoteControlEnabled) BOOL remoteControlEnabled;
@property (strong, nonatomic) RemoteControlManager *remoteControlManager;
@property (strong, nonatomic) VehicleDataManager *vehicleDataManager;
@property (strong, nonatomic) PerformInteractionManager *performManager;
@property (strong, nonatomic) ButtonManager *buttonManager;
Expand Down Expand Up @@ -50,6 +53,7 @@ - (instancetype)init {
return nil;
}

_remoteControlEnabled = NO;
_state = ProxyStateStopped;
_firstHMILevel = SDLHMILevelNone;

Expand All @@ -69,7 +73,7 @@ - (void)sdlex_startManager {
self.performManager = [[PerformInteractionManager alloc] initWithManager:self.sdlManager];
self.buttonManager = [[ButtonManager alloc] initWithManager:self.sdlManager refreshUIHandler:self.refreshUIHandler];
self.subscribeButtonManager = [[SubscribeButtonManager alloc] initWithManager:self.sdlManager];

self.remoteControlManager = [[RemoteControlManager alloc] initWithManager:self.sdlManager isEnabled:self.isRemoteControlEnabled softButtons:[self.buttonManager allScreenSoftButtons]];
[weakSelf sdlex_updateProxyState:ProxyStateConnected];
[RPCPermissionsManager setupPermissionsCallbacksWithManager:weakSelf.sdlManager];

Expand Down Expand Up @@ -99,18 +103,19 @@ - (void)startWithProxyTransportType:(ProxyTransportType)proxyTransportType {
[self sdlex_updateProxyState:ProxyStateSearchingForConnection];

SDLConfiguration *config = (proxyTransportType == ProxyTransportTypeIAP) ? [self.class sdlex_iapConfiguration] : [self.class sdlex_tcpConfiguration];
self.remoteControlEnabled = (proxyTransportType == ProxyTransportTypeTCP);
self.sdlManager = [[SDLManager alloc] initWithConfiguration:config delegate:self];
[self sdlex_startManager];
}

+ (SDLConfiguration *)sdlex_iapConfiguration {
SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration defaultConfigurationWithAppName:ExampleAppName fullAppId:ExampleFullAppId]];
SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration defaultConfigurationWithAppName:ExampleAppName fullAppId:ExampleFullAppId] enableRemote:NO];

return [self sdlex_setupManagerConfigurationWithLifecycleConfiguration:lifecycleConfig];
}

+ (SDLConfiguration *)sdlex_tcpConfiguration {
SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration debugConfigurationWithAppName:ExampleAppName fullAppId:ExampleFullAppId ipAddress:[Preferences sharedPreferences].ipAddress port:[Preferences sharedPreferences].port]];
SDLLifecycleConfiguration *lifecycleConfig = [self.class sdlex_setLifecycleConfigurationPropertiesOnConfiguration:[SDLLifecycleConfiguration debugConfigurationWithAppName:ExampleAppName fullAppId:ExampleFullAppId ipAddress:[Preferences sharedPreferences].ipAddress port:[Preferences sharedPreferences].port] enableRemote:YES];

return [self sdlex_setupManagerConfigurationWithLifecycleConfiguration:lifecycleConfig];
}
Expand All @@ -121,7 +126,7 @@ + (SDLConfiguration *)sdlex_setupManagerConfigurationWithLifecycleConfiguration:
return [[SDLConfiguration alloc] initWithLifecycle:lifecycleConfiguration lockScreen:lockScreenConfiguration logging:[self.class sdlex_logConfiguration] fileManager:[SDLFileManagerConfiguration defaultConfiguration] encryption:[SDLEncryptionConfiguration defaultConfiguration]];
}

+ (SDLLifecycleConfiguration *)sdlex_setLifecycleConfigurationPropertiesOnConfiguration:(SDLLifecycleConfiguration *)config {
+ (SDLLifecycleConfiguration *)sdlex_setLifecycleConfigurationPropertiesOnConfiguration:(SDLLifecycleConfiguration *)config enableRemote:(BOOL)enableRemote {
UIImage *appLogo = [[UIImage imageNamed:ExampleAppLogoName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
SDLArtwork *appIconArt = [SDLArtwork persistentArtworkWithImage:appLogo asImageFormat:SDLArtworkImageFormatPNG];

Expand All @@ -133,6 +138,12 @@ + (SDLLifecycleConfiguration *)sdlex_setLifecycleConfigurationPropertiesOnConfig
config.languagesSupported = @[SDLLanguageEnUs, SDLLanguageFrCa, SDLLanguageEsMx];
config.appType = SDLAppHMITypeDefault;

// On actual hardware, the app requires permissions to do remote control which this example app will not have.
// Only use the remote control type on the TCP connection.
if (enableRemote) {
config.additionalAppTypes = @[SDLAppHMITypeRemoteControl];
}

SDLRGBColor *green = [[SDLRGBColor alloc] initWithRed:126 green:188 blue:121];
SDLRGBColor *white = [[SDLRGBColor alloc] initWithRed:249 green:251 blue:254];
SDLRGBColor *darkGrey = [[SDLRGBColor alloc] initWithRed:57 green:78 blue:96];
Expand All @@ -145,7 +156,7 @@ + (SDLLifecycleConfiguration *)sdlex_setLifecycleConfigurationPropertiesOnConfig

+ (SDLLogConfiguration *)sdlex_logConfiguration {
SDLLogConfiguration *logConfig = [SDLLogConfiguration debugConfiguration];
SDLLogFileModule *sdlExampleModule = [SDLLogFileModule moduleWithName:@"SDL Obj-C Example App" files:[NSSet setWithArray:@[@"ProxyManager", @"AlertManager", @"AudioManager", @"ButtonManager", @"SubscribeButtonManager", @"MenuManager", @"PerformInteractionManager", @"RPCPermissionsManager", @"VehicleDataManager"]]];
SDLLogFileModule *sdlExampleModule = [SDLLogFileModule moduleWithName:@"SDL Obj-C Example App" files:[NSSet setWithArray:@[@"ProxyManager", @"AlertManager", @"AudioManager", @"ButtonManager", @"SubscribeButtonManager", @"MenuManager", @"PerformInteractionManager", @"RPCPermissionsManager", @"VehicleDataManager", @"RemoteControlManager"]]];
logConfig.modules = [logConfig.modules setByAddingObject:sdlExampleModule];
logConfig.targets = [logConfig.targets setByAddingObject:[SDLLogTargetFile logger]];
logConfig.globalLogLevel = SDLLogLevelDebug;
Expand All @@ -156,7 +167,7 @@ + (SDLLogConfiguration *)sdlex_logConfiguration {
#pragma mark - Screen UI Helpers

- (void)sdlex_createMenus {
self.sdlManager.screenManager.menu = [MenuManager allMenuItemsWithManager:self.sdlManager performManager:self.performManager];
self.sdlManager.screenManager.menu = [MenuManager allMenuItemsWithManager:self.sdlManager performManager:self.performManager remoteManager:self.remoteControlManager];
self.sdlManager.screenManager.voiceCommands = [MenuManager allVoiceMenuItemsWithManager:self.sdlManager];
}

Expand Down Expand Up @@ -242,10 +253,13 @@ - (void)hmiLevel:(SDLHMILevel)oldLevel didChangeToLevel:(SDLHMILevel)newLevel {
if (![newLevel isEqualToEnum:SDLHMILevelNone] && ([self.firstHMILevel isEqualToEnum:SDLHMILevelNone])) {
// This is our first time in a non-NONE state
self.firstHMILevel = newLevel;

// Subscribe to vehicle data.
[self.vehicleDataManager subscribeToVehicleOdometer];

// Start Remote Control Connection
[self.remoteControlManager start];

//Handle initial launch
[self sdlex_showInitialData];
}
Expand Down
Loading

0 comments on commit a26dbc2

Please sign in to comment.