diff options
Diffstat (limited to 'Example Apps/Example ObjC')
-rw-r--r-- | Example Apps/Example ObjC/MenuManager.h | 3 | ||||
-rw-r--r-- | Example Apps/Example ObjC/MenuManager.m | 55 | ||||
-rw-r--r-- | Example Apps/Example ObjC/ProxyManager.m | 28 | ||||
-rw-r--r-- | Example Apps/Example ObjC/RemoteControlManager.h | 29 | ||||
-rw-r--r-- | Example Apps/Example ObjC/RemoteControlManager.m | 247 |
5 files changed, 350 insertions, 12 deletions
diff --git a/Example Apps/Example ObjC/MenuManager.h b/Example Apps/Example ObjC/MenuManager.h index a7c1404c1..a78b2d077 100644 --- a/Example Apps/Example ObjC/MenuManager.h +++ b/Example Apps/Example ObjC/MenuManager.h @@ -9,6 +9,7 @@ #import <Foundation/Foundation.h> @class PerformInteractionManager; +@class RemoteControlManager; @class SDLManager; @class SDLMenuCell; @class SDLVoiceCommand; @@ -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 diff --git a/Example Apps/Example ObjC/MenuManager.m b/Example Apps/Example ObjC/MenuManager.m index d78be2b8f..29d5986fa 100644 --- a/Example Apps/Example ObjC/MenuManager.m +++ b/Example Apps/Example ObjC/MenuManager.m @@ -7,6 +7,7 @@ // #import "MenuManager.h" + #import "AlertManager.h" #import "AudioManager.h" #import "AppConstants.h" @@ -14,14 +15,16 @@ #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], @@ -91,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN + (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"; @@ -134,7 +137,7 @@ NS_ASSUME_NONNULL_BEGIN 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]) { @@ -151,7 +154,7 @@ NS_ASSUME_NONNULL_BEGIN 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]) { @@ -164,6 +167,50 @@ NS_ASSUME_NONNULL_BEGIN }]; } ++ (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 { diff --git a/Example Apps/Example ObjC/ProxyManager.m b/Example Apps/Example ObjC/ProxyManager.m index 35520d2f9..06f1d7334 100644 --- a/Example Apps/Example ObjC/ProxyManager.m +++ b/Example Apps/Example ObjC/ProxyManager.m @@ -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" @@ -22,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN // 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; @@ -50,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN return nil; } + _remoteControlEnabled = NO; _state = ProxyStateStopped; _firstHMILevel = SDLHMILevelNone; @@ -69,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN 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]; @@ -99,18 +103,19 @@ NS_ASSUME_NONNULL_BEGIN [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]; } @@ -121,7 +126,7 @@ NS_ASSUME_NONNULL_BEGIN 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]; @@ -133,6 +138,12 @@ NS_ASSUME_NONNULL_BEGIN 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]; @@ -145,7 +156,7 @@ NS_ASSUME_NONNULL_BEGIN + (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; @@ -156,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN #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]; } @@ -242,10 +253,13 @@ NS_ASSUME_NONNULL_BEGIN 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]; } diff --git a/Example Apps/Example ObjC/RemoteControlManager.h b/Example Apps/Example ObjC/RemoteControlManager.h new file mode 100644 index 000000000..d85c49d5c --- /dev/null +++ b/Example Apps/Example ObjC/RemoteControlManager.h @@ -0,0 +1,29 @@ +// +// RemoteControlManager.h +// SmartDeviceLink-Example-ObjC +// +// Created by Beharry, Justin (J.S.) on 8/1/22. +// Copyright © 2022 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@class SDLManager; +@class SDLSoftButtonObject; + +NS_ASSUME_NONNULL_BEGIN + +@interface RemoteControlManager : NSObject + +@property (assign, nonatomic, readonly, getter=isEnabled) BOOL enabled; +@property (copy, nonatomic, readonly) NSString *climateDataString; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithManager:(SDLManager *)manager isEnabled:(BOOL)enabled softButtons:(NSArray<SDLSoftButtonObject *> *)buttons; + +- (void)start; +- (void)showClimateControl; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example Apps/Example ObjC/RemoteControlManager.m b/Example Apps/Example ObjC/RemoteControlManager.m new file mode 100644 index 000000000..05d74540b --- /dev/null +++ b/Example Apps/Example ObjC/RemoteControlManager.m @@ -0,0 +1,247 @@ +// +// RemoteControlManager.m +// SmartDeviceLink-Example-ObjC +// +// Created by Beharry, Justin (J.S.) on 8/1/22. +// Copyright © 2022 smartdevicelink. All rights reserved. +// + +#import "RemoteControlManager.h" + +#import "AlertManager.h" +#import "SmartDeviceLink.h" + +@interface RemoteControlManager() + +@property (strong, nonatomic) SDLManager *sdlManager; +@property (strong, nonatomic) NSArray<SDLSoftButtonObject *> *homeButtons; + +@property (strong, nonatomic) SDLRemoteControlCapabilities *remoteControlCapabilities; +@property (strong, nonatomic) NSString *climateModuleId; +@property (strong, nonatomic) NSNumber<SDLBool> *hasConsent; +@property (strong, nonatomic) SDLClimateControlData *climateData; +@property (copy, nonatomic, readwrite) NSString *climateDataString; +@property (strong, nonatomic, readonly) NSArray<SDLSoftButtonObject *> *remoteButtons; + +@end + +@implementation RemoteControlManager + +- (instancetype)initWithManager:(SDLManager *)manager isEnabled:(BOOL)enabled softButtons:(NSArray<SDLSoftButtonObject *> *)buttons { + self = [super init]; + if (!self) { return nil; } + + _sdlManager = manager; + _enabled = enabled; + _homeButtons = buttons; + + return self; +} + +- (void)start { + if (!self.isEnabled) { + SDLLogW(@"Missing permissions for Remote Control Manager. Example remote control works only on TCP."); + return; + } + + [self.sdlManager.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeRemoteControl withUpdateHandler:^(SDLSystemCapability * _Nullable capability, BOOL subscribed, NSError * _Nullable error) { + if (!capability.remoteControlCapability) { + SDLLogE(@"SDL errored getting remote control module information: %@", error); + return; + } + + self.remoteControlCapabilities = capability.remoteControlCapability; + self.climateModuleId = self.remoteControlCapabilities.climateControlCapabilities.firstObject.moduleInfo.moduleId; + + // Get consent to control modules + SDLGetInteriorVehicleDataConsent *getInteriorVehicleDataConsent = [[SDLGetInteriorVehicleDataConsent alloc] initWithModuleType:SDLModuleTypeClimate moduleIds:@[self.climateModuleId]]; + [self.sdlManager sendRequest:getInteriorVehicleDataConsent withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored getting remote control consent: %@", error); + return; + } + self.hasConsent = response.success; + + // Initialize climate data and setup subscription + if (self.hasConsent) { + [self sdlex_initializeClimateData]; + [self sdlex_subscribeClimateControlData]; + } + }]; + }]; +} + +- (void)showClimateControl { + if (self.climateModuleId == nil && self.hasConsent) { + NSString *errorMessage = @"The climate module id was not set or consent was not given"; + [AlertManager sendAlertWithManager:self.sdlManager image:nil textField1:errorMessage textField2:nil]; + return; + } + + // Set the soft buttons to change remote control parameters + self.sdlManager.screenManager.softButtonObjects = self.remoteButtons; +} + +- (NSString *)climateDataString { + return [NSString stringWithFormat:@"AC: %@\n" + "AC Max: %@\n" + "Auto Mode: %@\n" + "Circulate Air: %@\n" + "Climate: %@\n" + "Current Temperature: %@\n" + "Defrost Zone: %@\n" + "Desired Temperature: %@\n" + "Dual Mode: %@\n" + "Fan Speed: %@\n" + "Heated Mirrors: %@\n" + "Heated Rears Window: %@\n" + "Heated Steering: %@\n" + "Heated Windshield: %@\n" + "Ventilation: %@\n", + self.climateData.acEnable.boolValue ? @"On" : @"Off", + self.climateData.acMaxEnable.boolValue ? @"On" : @"Off", + self.climateData.autoModeEnable.boolValue ? @"On" : @"Off", + self.climateData.circulateAirEnable.boolValue ? @"On" : @"Off", + self.climateData.climateEnable.boolValue ? @"On" : @"Off", + self.climateData.currentTemperature, + self.climateData.defrostZone, + self.climateData.desiredTemperature, + self.climateData.dualModeEnable.boolValue ? @"On" : @"Off", + self.climateData.fanSpeed, + self.climateData.heatedMirrorsEnable.boolValue ? @"On" : @"Off", + self.climateData.heatedRearWindowEnable.boolValue ? @"On" : @"Off", + self.climateData.heatedSteeringWheelEnable.boolValue ? @"On" : @"Off", + self.climateData.heatedWindshieldEnable.boolValue ? @"On" : @"Off", + self.climateData.ventilationMode + ]; +} + +- (void)sdlex_initializeClimateData { + if (self.climateModuleId == nil && !self.hasConsent.boolValue) { + NSString *errorMessage = @"The climate module id was not set or consent was not given"; + [AlertManager sendAlertWithManager:self.sdlManager image:nil textField1:errorMessage textField2:nil]; + } + + SDLGetInteriorVehicleData *getInteriorVehicleData = [[SDLGetInteriorVehicleData alloc] initWithModuleType:SDLModuleTypeClimate moduleId:self.climateModuleId]; + [self.sdlManager sendRequest:getInteriorVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + SDLGetInteriorVehicleDataResponse *dataResponse = (SDLGetInteriorVehicleDataResponse *)response; + self.climateData = dataResponse.moduleData.climateControlData; + }]; +} + +- (void)sdlex_subscribeClimateControlData { + // Start the subscription to remote control data + [self.sdlManager subscribeToRPC:SDLDidReceiveInteriorVehicleDataNotification withBlock:^(__kindof SDLRPCMessage * _Nonnull message) { + SDLOnInteriorVehicleData *onInteriorVehicleData = (SDLOnInteriorVehicleData *)message; + self.climateData = onInteriorVehicleData.moduleData.climateControlData; + }]; + + // Start the subscriptin to climate data + SDLGetInteriorVehicleData *getInteriorVehicleData = [[SDLGetInteriorVehicleData alloc] initAndSubscribeToModuleType:SDLModuleTypeClimate moduleId:self.climateModuleId]; + [self.sdlManager sendRequest:getInteriorVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (error != nil) { + return SDLLogE(@"SDL errored trying to subscribe to climate data: %@", error); + } + SDLLogD(@"SDL Subscribing to climate control data"); + }]; +} + +- (void)sdlex_turnOnAC { + SDLClimateControlData *climateControlData = [[SDLClimateControlData alloc] initWithDictionary:@{ @"acEnable": @YES }]; + SDLModuleData *moduleData = [[SDLModuleData alloc] initWithClimateControlData:climateControlData]; + SDLSetInteriorVehicleData *setInteriorVehicleData = [[SDLSetInteriorVehicleData alloc] initWithModuleData:moduleData]; + + [self.sdlManager sendRequest:setInteriorVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored trying to turn on climate AC: %@", error); + return; + } + }]; +} + +- (void)sdlex_turnOffAC { + SDLClimateControlData *climateControlData = [[SDLClimateControlData alloc] initWithDictionary:@{ @"acEnable": @NO }]; + SDLModuleData *moduleData = [[SDLModuleData alloc] initWithClimateControlData:climateControlData]; + SDLSetInteriorVehicleData *setInteriorVehicleData = [[SDLSetInteriorVehicleData alloc] initWithModuleData:moduleData]; + + [self.sdlManager sendRequest:setInteriorVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored trying to turn off climate AC: %@", error); + return; + } + }]; +} + +- (void)sdlex_setClimateTemperature { + SDLTemperature *temperature = [[SDLTemperature alloc] initWithFahrenheitValue:73]; + NSDictionary<NSString *, id> *climateDictionary = @{@"acEnable": @YES, @"fanSpeed": @100, @"desiredTemperature": temperature, @"ventilationMode": SDLVentilationModeBoth }; + + SDLClimateControlData *climateControlData = [[SDLClimateControlData alloc] initWithDictionary:climateDictionary]; + SDLModuleData *moduleData = [[SDLModuleData alloc] initWithClimateControlData:climateControlData]; + SDLSetInteriorVehicleData *setInteriorVehicleData = [[SDLSetInteriorVehicleData alloc] initWithModuleData:moduleData]; + + [self.sdlManager sendRequest:setInteriorVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored trying to set climate temperature to 73 degrees: %@", error); + return; + } + }]; +} + +- (NSArray *)remoteButtons { + SDLSoftButtonObject *acOnButton = [[SDLSoftButtonObject alloc] initWithName:@"AC On" text:@"AC On" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + [self sdlex_turnOnAC]; + }]; + + SDLSoftButtonObject *acOffButton = [[SDLSoftButtonObject alloc] initWithName:@"AC Off" text:@"AC Off" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + [self sdlex_turnOffAC]; + }]; + + SDLSoftButtonObject *acMaxToggle = [[SDLSoftButtonObject alloc] initWithName:@"AC Max" text:@"AC Max" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + + SDLButtonPress *buttonTouch = [[SDLButtonPress alloc] initWithButtonName:SDLButtonNameACMax moduleType:SDLModuleTypeClimate moduleId:self.climateModuleId buttonPressMode:SDLButtonPressModeShort]; + [self.sdlManager sendRequest:buttonTouch withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored toggle AC Max with remote button press: %@", error); + return; + } + }]; + }]; + + SDLSoftButtonObject *temperatureDecreaseButton = [[SDLSoftButtonObject alloc] initWithName:@"Temperature Decrease" text:@"Temperature -" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + + SDLButtonPress *buttonTouch = [[SDLButtonPress alloc] initWithButtonName:SDLButtonNameTempDown moduleType:SDLModuleTypeClimate moduleId:self.climateModuleId buttonPressMode:SDLButtonPressModeShort]; + [self.sdlManager sendRequest:buttonTouch withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored decreasing target climate temperature with remote button: %@", error); + return; + } + }]; + }]; + + SDLSoftButtonObject *temperatureIncreaseButton = [[SDLSoftButtonObject alloc] initWithName:@"Temperature Increase" text:@"Temperature +" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + + SDLButtonPress *buttonTouch = [[SDLButtonPress alloc] initWithButtonName:SDLButtonNameTempUp moduleType:SDLModuleTypeClimate moduleId:self.climateModuleId buttonPressMode:SDLButtonPressModeShort]; + [self.sdlManager sendRequest:buttonTouch withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (!response.success) { + SDLLogE(@"SDL errored increasing target climate temperature with remote button:: %@", error); + return; + } + }]; + }]; + + SDLSoftButtonObject *backToHomeButton = [[SDLSoftButtonObject alloc] initWithName:@"Home" text:@"Back to Home" artwork:nil handler:^(SDLOnButtonPress * _Nullable buttonPress, SDLOnButtonEvent * _Nullable buttonEvent) { + if (buttonPress == nil) { return; } + self.sdlManager.screenManager.softButtonObjects = self.homeButtons; + [self.sdlManager.screenManager changeLayout:[[SDLTemplateConfiguration alloc] initWithPredefinedLayout:SDLPredefinedLayoutNonMedia] withCompletionHandler:nil]; + }]; + + return @[acOnButton, acOffButton, acMaxToggle, temperatureDecreaseButton, temperatureIncreaseButton, backToHomeButton]; +} + +@end |