summaryrefslogtreecommitdiff
path: root/Example Apps/Example ObjC
diff options
context:
space:
mode:
Diffstat (limited to 'Example Apps/Example ObjC')
-rw-r--r--Example Apps/Example ObjC/MenuManager.h3
-rw-r--r--Example Apps/Example ObjC/MenuManager.m55
-rw-r--r--Example Apps/Example ObjC/ProxyManager.m28
-rw-r--r--Example Apps/Example ObjC/RemoteControlManager.h29
-rw-r--r--Example Apps/Example ObjC/RemoteControlManager.m247
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