summaryrefslogtreecommitdiff
path: root/Example Apps/Example ObjC/VehicleDataManager.m
blob: cc2ee46fa770c8fe5bf304a53043c4713f718051 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
//
//  VehicleDataManager.m
//  SmartDeviceLink-Example-ObjC
//
//  Created by Nicole on 4/23/18.
//  Copyright © 2018 smartdevicelink. All rights reserved.
//

#import "AlertManager.h"
#import "AppConstants.h"
#import "SmartDeviceLink.h"
#import "TextValidator.h"
#import "VehicleDataManager.h"

NS_ASSUME_NONNULL_BEGIN


@interface VehicleDataManager ()

@property (strong, nonatomic) SDLManager *sdlManager;
@property (copy, nonatomic, readwrite) NSString *vehicleOdometerData;
@property (copy, nonatomic, nullable) RefreshUIHandler refreshUIHandler;

@end

@implementation VehicleDataManager

#pragma mark - Lifecycle

- (instancetype)initWithManager:(SDLManager *)manager refreshUIHandler:(RefreshUIHandler)refreshUIHandler {
    self = [super init];
    if (!self) {
        return nil;
    }

    _sdlManager = manager;
    _refreshUIHandler = refreshUIHandler;
    _vehicleOdometerData = @"";

    [_sdlManager subscribeToRPC:SDLDidReceiveVehicleDataNotification withObserver:self selector:@selector(vehicleDataNotification:)];
    [self sdlex_resetOdometer];

    return self;
}


#pragma mark - Subscribe Vehicle Data

/**
 *  Subscribes to odometer data. You must subscribe to a notification with name `SDLDidReceiveVehicleData` to get the new data when the odometer data changes.
 */
- (void)subscribeToVehicleOdometer {
    SDLLogD(@"Subscribing to odometer vehicle data");
    SDLSubscribeVehicleData *subscribeToVehicleOdometer = [[SDLSubscribeVehicleData alloc] init];
    subscribeToVehicleOdometer.odometer = @YES;
    [self.sdlManager sendRequest:subscribeToVehicleOdometer withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
        if (error || ![response isKindOfClass:SDLSubscribeVehicleDataResponse.class]) {
            SDLLogE(@"Error sending Get Vehicle Data RPC: %@", error);
        }

        SDLGetVehicleDataResponse* getVehicleDataResponse = (SDLGetVehicleDataResponse *)response;
        SDLResult resultCode = getVehicleDataResponse.resultCode;

        NSMutableString *message = [NSMutableString stringWithFormat:@"%@: ", VehicleDataOdometerName];
        if ([resultCode isEqualToEnum:SDLResultSuccess]) {
            SDLLogD(@"Subscribed to vehicle odometer data");
            [message appendString:@"Subscribed"];
        } else if ([resultCode isEqualToEnum:SDLResultDisallowed]) {
            SDLLogD(@"Access to vehicle data disallowed");
            [message appendString:@"Disallowed"];
        } else if ([resultCode isEqualToEnum:SDLResultUserDisallowed]) {
            SDLLogD(@"Vehicle user disabled access to vehicle data");
            [message appendString:@"Disabled"];
        } else if ([resultCode isEqualToEnum:SDLResultIgnored]) {
            SDLLogD(@"Already subscribed to odometer data");
            [message appendString:@"Subscribed"];
        } else if ([resultCode isEqualToEnum:SDLResultDataNotAvailable]) {
            SDLLogD(@"You have permission to access to vehicle data, but the vehicle you are connected to did not provide any data");
            [message appendString:@"Unknown"];
        } else {
            SDLLogE(@"Unknown reason for failure to get vehicle data: %@", error != nil ? error.localizedDescription : @"no error message");
            [message appendString:@"Unsubscribed"];
        }

        self.vehicleOdometerData = message;

        if (!self.refreshUIHandler) { return; }
        self.refreshUIHandler();
    }];
}

/**
 *  Unsubscribes to vehicle odometer data.
 */
- (void)unsubscribeToVehicleOdometer {
    SDLUnsubscribeVehicleData *unsubscribeToVehicleOdometer = [[SDLUnsubscribeVehicleData alloc] init];
    unsubscribeToVehicleOdometer.odometer = @YES;
    [self.sdlManager sendRequest:unsubscribeToVehicleOdometer withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
        if (!response.success.boolValue) { return; }
        [self sdlex_resetOdometer];
    }];
}

/**
 *  Notification containing the updated vehicle data.
 *
 *  @param notification A SDLOnVehicleData notification
 */
- (void)vehicleDataNotification:(SDLRPCNotificationNotification *)notification {
    if (![notification.notification isKindOfClass:SDLOnVehicleData.class]) {
        return;
    }

    SDLOnVehicleData *onVehicleData = (SDLOnVehicleData *)notification.notification;
    self.vehicleOdometerData = [NSString stringWithFormat:@"%@: %@ km", VehicleDataOdometerName, onVehicleData.odometer];

    if (!self.refreshUIHandler) { return; }
    self.refreshUIHandler();
}

/**
 *  Resets the odometer data
 */
- (void)sdlex_resetOdometer {
    self.vehicleOdometerData = [NSString stringWithFormat:@"%@: Unsubscribed", VehicleDataOdometerName];
}

#pragma mark - Get Vehicle Data

/**
 *  Retreives the current vehicle data
 *
 *  @param manager The SDL Manager
 *  @param triggerSource Whether the menu item was selected by voice or touch
 *  @param vehicleDataType The vehicle data to look for
 */
+ (void)getAllVehicleDataWithManager:(SDLManager *)manager triggerSource:(SDLTriggerSource)triggerSource vehicleDataType:(NSString *)vehicleDataType {
    SDLLogD(@"Checking if app has permission to access vehicle data...");
    if (![manager.permissionManager isRPCAllowed:@"GetVehicleData"]) {
        [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"This app does not have the required permissions to access vehicle data" textField2:nil]];
        return;
    }

    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];

    [manager sendRequest:getAllVehicleData withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
        if (error || ![response isKindOfClass:SDLGetVehicleDataResponse.class]) {
            [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"Something went wrong while getting vehicle data" textField2:nil]];
            return;
        }

        SDLGetVehicleDataResponse *getVehicleDataResponse = (SDLGetVehicleDataResponse *)response;
        SDLResult resultCode = getVehicleDataResponse.resultCode;

        NSString *alertTitle = vehicleDataType;
        NSString *alertMessage = nil;

        if ([resultCode isEqualToEnum:SDLResultRejected]) {
            SDLLogD(@"The request for vehicle data was rejected");
            alertMessage = @"Rejected";
        } else if ([resultCode isEqualToEnum:SDLResultDisallowed]) {
            SDLLogD(@"This app does not have the required permissions to access vehicle data.");
            alertMessage = @"Disallowed";
        } else if ([resultCode isEqualToEnum:SDLResultSuccess] || [resultCode isEqualToEnum:SDLResultDataNotAvailable]) {
            SDLLogD(@"Request for vehicle data successful");
            if (getVehicleDataResponse) {
                alertMessage = [self sdlex_vehicleDataDescription:getVehicleDataResponse vehicleDataType:vehicleDataType];
            } else {
                SDLLogE(@"No vehicle data returned");
                alertMessage = @"No vehicle data returned";
            }
        }

        alertTitle = [TextValidator validateText:alertTitle length:25];
        alertMessage = [TextValidator validateText:alertMessage length:200];

        if ([triggerSource isEqualToEnum:SDLTriggerSourceMenu]) {
            [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:alertTitle textField2:alertMessage]];
        } else {
            NSString *spokenAlert = alertMessage ?: alertTitle;
            [manager sendRequest:[[SDLSpeak alloc] initWithTTS:spokenAlert]];
        }
    }];
}

+ (NSString *)sdlex_vehicleDataDescription:(SDLGetVehicleDataResponse *)vehicleData vehicleDataType:(NSString *)vehicleDataType {
    NSString *vehicleDataDescription = nil;

    if ([vehicleDataType isEqualToString:ACAccelerationPedalPositionMenuName]) {
        vehicleDataDescription = vehicleData.accPedalPosition.description;
    } else if ([vehicleDataType isEqualToString:ACAirbagStatusMenuName]) {
        vehicleDataDescription = vehicleData.airbagStatus.description;
    } else if ([vehicleDataType isEqualToString:ACBeltStatusMenuName]) {
        vehicleDataDescription = vehicleData.beltStatus.description;
    } else if ([vehicleDataType isEqualToString:ACBodyInformationMenuName]) {
        vehicleDataDescription = vehicleData.bodyInformation.description;
    } else if ([vehicleDataType isEqualToString:ACClusterModeStatusMenuName]) {
        vehicleDataDescription = vehicleData.clusterModeStatus.description;
    } else if ([vehicleDataType isEqualToString:ACDeviceStatusMenuName]) {
        vehicleDataDescription = vehicleData.deviceStatus.description;
    } else if ([vehicleDataType isEqualToString:ACDriverBrakingMenuName]) {
        vehicleDataDescription = vehicleData.driverBraking.description;
    } else if ([vehicleDataType isEqualToString:ACECallInfoMenuName]) {
        vehicleDataDescription = vehicleData.eCallInfo.description;
    } else if ([vehicleDataType isEqualToEnum:ACElectronicParkBrakeStatus]) {
        vehicleDataDescription = vehicleData.electronicParkBrakeStatus.description;
    } else if ([vehicleDataType isEqualToString:ACEmergencyEventMenuName]) {
        vehicleDataDescription = vehicleData.emergencyEvent.description;
    } else if ([vehicleDataType isEqualToString:ACEngineOilLifeMenuName]) {
        vehicleDataDescription = vehicleData.engineOilLife.description;
    } else if ([vehicleDataType isEqualToString:ACEngineTorqueMenuName]) {
        vehicleDataDescription = vehicleData.engineTorque.description;
    } else if ([vehicleDataType isEqualToString:ACExternalTemperatureMenuName]) {
        vehicleDataDescription = vehicleData.externalTemperature.description;
    } else if ([vehicleDataType isEqualToString:ACFuelLevelMenuName]) {
        vehicleDataDescription = vehicleData.fuelLevel.description;
    } else if ([vehicleDataType isEqualToString:ACFuelLevelStateMenuName]) {
        vehicleDataDescription = vehicleData.fuelLevel_State.description;
    } else if ([vehicleDataType isEqualToString:ACFuelRangeMenuName]) {
        vehicleDataDescription = vehicleData.fuelRange.description;
    } else if ([vehicleDataType isEqualToString:ACGPSMenuName]) {
        vehicleDataDescription = vehicleData.gps.description;
    } else if ([vehicleDataType isEqualToString:ACHeadLampStatusMenuName]) {
        vehicleDataDescription = vehicleData.headLampStatus.description;
    } else if ([vehicleDataType isEqualToString:ACInstantFuelConsumptionMenuName]) {
        vehicleDataDescription = vehicleData.instantFuelConsumption.description;
    } else if ([vehicleDataType isEqualToString:ACMyKeyMenuName]) {
        vehicleDataDescription = vehicleData.myKey.description;
    } else if ([vehicleDataType isEqualToString:ACOdometerMenuName]) {
        vehicleDataDescription = vehicleData.odometer.description;
    } else if ([vehicleDataType isEqualToString:ACPRNDLMenuName]) {
        vehicleDataDescription = vehicleData.prndl.description;
    } else if ([vehicleDataType isEqualToString:ACSpeedMenuName]) {
        vehicleDataDescription = vehicleData.speed.description;
    } else if ([vehicleDataType isEqualToString:ACSteeringWheelAngleMenuName]) {
        vehicleDataDescription = vehicleData.steeringWheelAngle.description;
    } else if ([vehicleDataType isEqualToString:ACTirePressureMenuName]) {
        vehicleDataDescription = vehicleData.tirePressure.description;
    } else if ([vehicleDataType isEqualToString:ACTurnSignalMenuName]) {
        vehicleDataDescription = vehicleData.turnSignal.description;
    } else if ([vehicleDataType isEqualToString: ACVINMenuName]) {
        vehicleDataDescription = vehicleData.vin.description;
    }

    return vehicleDataDescription ?: @"Vehicle data not available";
}

#pragma mark - Phone Calls

/**
 *  Checks if the head unit has the ability and/or permissions to make a phone call. If it does, the phone number is dialed.
 *
 *  @param manager      The SDL manager
 *  @param phoneNumber  A phone number to dial
 */
+ (void)checkPhoneCallCapabilityWithManager:(SDLManager *)manager phoneNumber:(NSString *)phoneNumber {
    SDLLogD(@"Checking phone call capability");
    [manager.systemCapabilityManager updateCapabilityType:SDLSystemCapabilityTypePhoneCall completionHandler:^(NSError * _Nullable error, SDLSystemCapabilityManager * _Nonnull systemCapabilityManager) {
        if (!systemCapabilityManager.phoneCapability) {
            [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"The head unit does not support the phone call  capability" textField2:nil]];
            return;
        }

        if (systemCapabilityManager.phoneCapability.dialNumberEnabled.boolValue) {
            SDLLogD(@"Dialing phone number %@", phoneNumber);
            [self sdlex_dialPhoneNumber:phoneNumber manager:manager];
        } else {
            [manager sendRequest:[AlertManager alertWithMessageAndCloseButton:@"The dial number feature is unavailable for this head unit" textField2:nil]];
        }
    }];
}

/**
 *  Dials a phone number.
 *
 *  @param phoneNumber  A phone number to dial
 *  @param manager      The SDL manager
 */
+ (void)sdlex_dialPhoneNumber:(NSString *)phoneNumber manager:(SDLManager *)manager {
    SDLDialNumber *dialNumber = [[SDLDialNumber alloc] initWithNumber:phoneNumber];
    [manager sendRequest:dialNumber withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
        if (!response.resultCode) { return; }
        SDLLogD(@"Sent dial number request: %@", response.resultCode == SDLResultSuccess ? @"successfully" : @"unsuccessfully");
    }];
}

@end

NS_ASSUME_NONNULL_END