From d5d905bb7c1257740ba6e8e8d8551022d55e0c4b Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 10:18:40 -0500 Subject: [PATCH 1/6] First pass at application state notifications * Piggyback the OnHMIState notification, send to the HU if xml version is > 4 * On connection, send state. * Setup NSNotificationCenter observers for state changes, send messages on fired observers --- sdl_ios/SmartDeviceLink/SDLProxy.m | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sdl_ios/SmartDeviceLink/SDLProxy.m b/sdl_ios/SmartDeviceLink/SDLProxy.m index c0b20ee7c..6297e29e8 100644 --- a/sdl_ios/SmartDeviceLink/SDLProxy.m +++ b/sdl_ios/SmartDeviceLink/SDLProxy.m @@ -66,7 +66,6 @@ - (id)initWithTransport:(NSObject *)theTransport protocol:(NSObjec [self.transport connect]; [[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications]; - } return self; @@ -101,6 +100,26 @@ -(void) notifyProxyClosed { } } +- (void)sendMobileHMIState { + UIApplicationState appState = [UIApplication sharedApplication].applicationState; + SDLOnHMIStatus *HMIStatusRPC = [[SDLOnHMIStatus alloc] init]; + + switch (appState) { + case UIApplicationStateActive: { + HMIStatusRPC.hmiLevel = [SDLHMILevel HMI_FULL]; + } break; + case UIApplicationStateInactive: // Fallthrough + case UIApplicationStateBackground: { + HMIStatusRPC.hmiLevel = [SDLHMILevel HMI_BACKGROUND]; + } break; + default: + break; + } + + // TODO: This won't work, there are runtime checks to make sure only requests are sent... + [self sendRPCRequest:HMIStatusRPC]; +} + #pragma mark - Pseudo properties - (NSObject *)getTransport { @@ -140,7 +159,7 @@ -(void)destroyHandshakeTimer { - (void) onProtocolOpened { isConnected = YES; [SDLDebugTool logInfo:@"StartSession (request)" withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - + [self.protocol sendStartSessionWithType:SDLServiceType_RPC]; [self destroyHandshakeTimer]; @@ -169,6 +188,13 @@ - (void)handleProtocolSessionStarted:(SDLServiceType)sessionType sessionID:(Byte rpcSessionID = sessionID; [self invokeMethodOnDelegates:@selector(onProxyOpened) withObject:nil]; } + + if (_version >= 4) { + // Send the Mobile HMI state and register handlers for changing state + [self sendMobileHMIState]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationDidBecomeActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationWillResignActiveNotification object:nil]; + } } - (void) onProtocolMessageReceived:(SDLProtocolMessage*) msgData { From 785efd1928dab62200d10d2bf03d0c761f90e83f Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 12:19:54 -0500 Subject: [PATCH 2/6] Fixes #36 --- sdl_ios/SmartDeviceLink/SDLRPCMessageType.h | 19 ++++---- sdl_ios/SmartDeviceLink/SDLRPCMessageType.m | 49 --------------------- 2 files changed, 8 insertions(+), 60 deletions(-) diff --git a/sdl_ios/SmartDeviceLink/SDLRPCMessageType.h b/sdl_ios/SmartDeviceLink/SDLRPCMessageType.h index 9b8afc5c4..981f0d42c 100644 --- a/sdl_ios/SmartDeviceLink/SDLRPCMessageType.h +++ b/sdl_ios/SmartDeviceLink/SDLRPCMessageType.h @@ -3,15 +3,12 @@ // Copyright (c) 2014 Ford Motor Company. All rights reserved. #import -#import -@interface SDLRPCMessageType : SDLEnum {} - -+(SDLRPCMessageType*) valueOf:(NSString*) value; -+(NSMutableArray*) values; - -+(SDLRPCMessageType*) request; -+(SDLRPCMessageType*) response; -+(SDLRPCMessageType*) notification; - -@end +/** + * Enumeration linking message types with function types. + */ +typedef NS_ENUM(Byte, SDLRPCMessageType){ + SDLRPCMessageTypeRequest = 0, + SDLRPCMessageTypeResponse, + SDLRPCMessageTypeNotification +}; diff --git a/sdl_ios/SmartDeviceLink/SDLRPCMessageType.m b/sdl_ios/SmartDeviceLink/SDLRPCMessageType.m index 2ece4f7ab..2fe8bd5da 100644 --- a/sdl_ios/SmartDeviceLink/SDLRPCMessageType.m +++ b/sdl_ios/SmartDeviceLink/SDLRPCMessageType.m @@ -4,52 +4,3 @@ #import -SDLRPCMessageType* SDLRPCMessageType_request = nil; -SDLRPCMessageType* SDLRPCMessageType_response = nil; -SDLRPCMessageType* SDLRPCMessageType_notification = nil; - -NSMutableArray* SDLRPCMessageType_values = nil; -@implementation SDLRPCMessageType - -+(SDLRPCMessageType*) valueOf:(NSString*) value { - for (SDLRPCMessageType* item in SDLRPCMessageType.values) { - if ([item.value isEqualToString:value]) { - return item; - } - } - return nil; -} - -+(NSMutableArray*) values { - if (SDLRPCMessageType_values == nil) { - SDLRPCMessageType_values = [[NSMutableArray alloc] initWithObjects: - SDLRPCMessageType_request, - SDLRPCMessageType_response, - SDLRPCMessageType_notification, - nil]; - } - return SDLRPCMessageType_values; -} - -+(SDLRPCMessageType*) request { - if (SDLRPCMessageType_request == nil) { - SDLRPCMessageType_request = [[SDLRPCMessageType alloc] initWithValue:@"request"]; - } - return SDLRPCMessageType_request; -} - -+(SDLRPCMessageType*) response { - if (SDLRPCMessageType_response == nil) { - SDLRPCMessageType_response = [[SDLRPCMessageType alloc] initWithValue:@"response"]; - } - return SDLRPCMessageType_response; -} - -+(SDLRPCMessageType*) notification { - if (SDLRPCMessageType_notification == nil) { - SDLRPCMessageType_notification = [[SDLRPCMessageType alloc] initWithValue:@"notification"]; - } - return SDLRPCMessageType_notification; -} - -@end From 73ce318604a918e35df36c9eebaf72cadbd8ba3c Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 12:20:11 -0500 Subject: [PATCH 3/6] SDLRPCPayload use enum instead of raw byte --- sdl_ios/SmartDeviceLink/SDLRPCPayload.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdl_ios/SmartDeviceLink/SDLRPCPayload.h b/sdl_ios/SmartDeviceLink/SDLRPCPayload.h index 44e3a0ba8..f57fb0b0e 100644 --- a/sdl_ios/SmartDeviceLink/SDLRPCPayload.h +++ b/sdl_ios/SmartDeviceLink/SDLRPCPayload.h @@ -3,10 +3,11 @@ // Copyright (c) 2014 Ford Motor Company. All rights reserved. #import +#import @interface SDLRPCPayload : NSObject -@property (assign) Byte rpcType; +@property (assign) SDLRPCMessageType rpcType; @property (assign) UInt32 functionID; @property (assign) UInt32 correlationID; @property (strong) NSData *jsonData; From b61066393dfc761fb02ae31f64a5c9cc59a56594 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 12:21:17 -0500 Subject: [PATCH 4/6] SDLProtocol handles any type of RPCMessage Deprecate sending strictly an RPCRequest --- sdl_ios/SmartDeviceLink/SDLProtocol.h | 6 +- sdl_ios/SmartDeviceLink/SDLProtocol.m | 89 +++++++++++++++++---------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/sdl_ios/SmartDeviceLink/SDLProtocol.h b/sdl_ios/SmartDeviceLink/SDLProtocol.h index 165f6df8a..3b4e0eb25 100644 --- a/sdl_ios/SmartDeviceLink/SDLProtocol.h +++ b/sdl_ios/SmartDeviceLink/SDLProtocol.h @@ -3,14 +3,18 @@ // Copyright (c) 2014 Ford Motor Company. All rights reserved. #import "SDLAbstractProtocol.h" +#import @interface SDLProtocol : SDLAbstractProtocol - (void)sendStartSessionWithType:(SDLServiceType)serviceType; - (void)sendEndSessionWithType:(SDLServiceType)serviceType sessionID:(Byte)sessionID; -- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest; +- (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type; - (void)handleBytesFromTransport:(NSData *)receivedData; - (void)sendHeartbeat; +#pragma mark - Deprecated +- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest __deprecated_msg("use -sendRPC:withType: instead"); + @end diff --git a/sdl_ios/SmartDeviceLink/SDLProtocol.m b/sdl_ios/SmartDeviceLink/SDLProtocol.m index 61b738ac1..662042426 100644 --- a/sdl_ios/SmartDeviceLink/SDLProtocol.m +++ b/sdl_ios/SmartDeviceLink/SDLProtocol.m @@ -14,6 +14,8 @@ #import "SDLRPCPayload.h" #import "SDLDebugTool.h" #import "SDLPrioritizedObjectCollection.h" +#import "SDLRPCNotification.h" +#import "SDLRPCResponse.h" const NSUInteger MAX_TRANSMISSION_SIZE = 512; @@ -82,67 +84,88 @@ - (void)sendEndSessionWithType:(SDLServiceType)serviceType sessionID:(Byte)sessi } -// SDLRPCRequest in from app -> SDLProtocolMessage out to transport layer. -- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest { - - NSData *jsonData = [[SDLJsonEncoder instance] encodeDictionary:[rpcRequest serializeAsDictionary:self.version]]; +- (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type { + NSParameterAssert(message != nil); + + NSData *jsonData = [[SDLJsonEncoder instance] encodeDictionary:[message serializeAsDictionary:self.version]]; NSData* messagePayload = nil; - - NSString *logMessage = [NSString stringWithFormat:@"%@", rpcRequest]; + + NSString *logMessage = [NSString stringWithFormat:@"%@", message]; [SDLDebugTool logInfo:logMessage withType:SDLDebugType_RPC toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; - - - if(self.version == 1) { - messagePayload = jsonData; - } else if (self.version == 2) { - // Serialize the RPC data into an NSData - SDLRPCPayload *rpcPayload = [[SDLRPCPayload alloc] init]; - rpcPayload.rpcType = 0; - rpcPayload.functionID = [[[[SDLFunctionID alloc] init] getFunctionID:[rpcRequest getFunctionName]] intValue]; - rpcPayload.correlationID = [rpcRequest.correlationID intValue]; - rpcPayload.jsonData = jsonData; - rpcPayload.binaryData = rpcRequest.bulkData; - messagePayload = rpcPayload.data; + + // Build the message payload. Include the binary header if necessary + switch (self.version) { + case 1: { + // No binary header in version 1 + messagePayload = jsonData; + } break; + case 2: // Fallthrough + case 3: { + // Build a binary header + // Serialize the RPC data into an NSData + SDLRPCPayload *rpcPayload = [[SDLRPCPayload alloc] init]; + rpcPayload.rpcType = type; + rpcPayload.functionID = [[[[SDLFunctionID alloc] init] getFunctionID:[message getFunctionName]] intValue]; + rpcPayload.jsonData = jsonData; + rpcPayload.binaryData = message.bulkData; + + // If it's a request or a response, we need to pull out the correlation ID, so we'll upcast + switch (type) { + case SDLRPCMessageTypeRequest: { + rpcPayload.correlationID = [((SDLRPCRequest *)message).correlationID intValue]; + } break; + case SDLRPCMessageTypeResponse: { + rpcPayload.correlationID = [((SDLRPCResponse *)message).correlationID intValue]; + } + case SDLRPCMessageTypeNotification: // Fallthrough + default: break; + } + + messagePayload = rpcPayload.data; + } break; + default: { + NSAssert(NO, @"sendRPCMessage:withType: must handle additional versions"); + } break; } - - // + // Build the protocol level header & message - // SDLProtocolHeader *header = [SDLProtocolHeader headerForVersion:self.version]; header.frameType = SDLFrameType_Single; header.serviceType = SDLServiceType_RPC; header.frameData = SDLFrameData_SingleFrame; header.sessionID = self.sessionID; header.bytesInPayload = (UInt32)messagePayload.length; - + // V2+ messages need to have message ID property set. if (self.version >= 2) { [((SDLV2ProtocolHeader*)header) setMessageID:++_messageID]; } - - - SDLProtocolMessage *message = [SDLProtocolMessage messageWithHeader:header andPayload:messagePayload]; - - + + SDLProtocolMessage *protocolMessage = [SDLProtocolMessage messageWithHeader:header andPayload:messagePayload]; + // // See if the message is small enough to send in one transmission. // If not, break it up into smaller messages and send. // - if (message.size < MAX_TRANSMISSION_SIZE) + if (protocolMessage.size < MAX_TRANSMISSION_SIZE) { - [self logRPCSend:message]; - [self sendDataToTransport:message.data withPriority:SDLServiceType_RPC]; + [self logRPCSend:protocolMessage]; + [self sendDataToTransport:protocolMessage.data withPriority:SDLServiceType_RPC]; } else { - NSArray *messages = [SDLProtocolMessageDisassembler disassemble:message withLimit:MAX_TRANSMISSION_SIZE]; + NSArray *messages = [SDLProtocolMessageDisassembler disassemble:protocolMessage withLimit:MAX_TRANSMISSION_SIZE]; for (SDLProtocolMessage *smallerMessage in messages) { [self logRPCSend:smallerMessage]; [self sendDataToTransport:smallerMessage.data withPriority:SDLServiceType_RPC]; } - + } +} +// SDLRPCRequest in from app -> SDLProtocolMessage out to transport layer. +- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest { + [self sendRPC:rpcRequest withType:SDLRPCMessageTypeRequest]; } - (void)logRPCSend:(SDLProtocolMessage *)message { From a407a76c69491e73a3c9cd077c552525705dddca Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 14:42:29 -0500 Subject: [PATCH 5/6] Remove withType: part of sendRPC call and do introspection instead --- sdl_ios/SmartDeviceLink/SDLProtocol.h | 4 ++-- sdl_ios/SmartDeviceLink/SDLProtocol.m | 17 +++++------------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/sdl_ios/SmartDeviceLink/SDLProtocol.h b/sdl_ios/SmartDeviceLink/SDLProtocol.h index 3b4e0eb25..c0d0970f7 100644 --- a/sdl_ios/SmartDeviceLink/SDLProtocol.h +++ b/sdl_ios/SmartDeviceLink/SDLProtocol.h @@ -10,11 +10,11 @@ - (void)sendStartSessionWithType:(SDLServiceType)serviceType; - (void)sendEndSessionWithType:(SDLServiceType)serviceType sessionID:(Byte)sessionID; -- (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type; +- (void)sendRPC:(SDLRPCMessage *)message; - (void)handleBytesFromTransport:(NSData *)receivedData; - (void)sendHeartbeat; #pragma mark - Deprecated -- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest __deprecated_msg("use -sendRPC:withType: instead"); +- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest __deprecated_msg("use -sendRPC: instead"); @end diff --git a/sdl_ios/SmartDeviceLink/SDLProtocol.m b/sdl_ios/SmartDeviceLink/SDLProtocol.m index 662042426..cca041c30 100644 --- a/sdl_ios/SmartDeviceLink/SDLProtocol.m +++ b/sdl_ios/SmartDeviceLink/SDLProtocol.m @@ -84,7 +84,7 @@ - (void)sendEndSessionWithType:(SDLServiceType)serviceType sessionID:(Byte)sessi } -- (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type { +- (void)sendRPC:(SDLRPCMessage *)message { NSParameterAssert(message != nil); NSData *jsonData = [[SDLJsonEncoder instance] encodeDictionary:[message serializeAsDictionary:self.version]]; @@ -110,15 +110,10 @@ - (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type { rpcPayload.binaryData = message.bulkData; // If it's a request or a response, we need to pull out the correlation ID, so we'll upcast - switch (type) { - case SDLRPCMessageTypeRequest: { - rpcPayload.correlationID = [((SDLRPCRequest *)message).correlationID intValue]; - } break; - case SDLRPCMessageTypeResponse: { - rpcPayload.correlationID = [((SDLRPCResponse *)message).correlationID intValue]; - } - case SDLRPCMessageTypeNotification: // Fallthrough - default: break; + if ([message isKindOfClass:SDLRPCRequest.class]) { + rpcPayload.correlationID = [((SDLRPCRequest *)message).correlationID intValue]; + } else if ([message isKindOfClass:SDLRPCResponse.class]) { + rpcPayload.correlationID = [((SDLRPCResponse *)message).correlationID intValue]; } messagePayload = rpcPayload.data; @@ -143,10 +138,8 @@ - (void)sendRPC:(SDLRPCMessage *)message withType:(SDLRPCMessageType)type { SDLProtocolMessage *protocolMessage = [SDLProtocolMessage messageWithHeader:header andPayload:messagePayload]; - // // See if the message is small enough to send in one transmission. // If not, break it up into smaller messages and send. - // if (protocolMessage.size < MAX_TRANSMISSION_SIZE) { [self logRPCSend:protocolMessage]; From 5cf4cd0640d1ff284ce06ff2afd9976865c8c854 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Tue, 20 Jan 2015 15:00:25 -0500 Subject: [PATCH 6/6] Refactor other sendRPCRequest methods to be more generic with sendRPC --- sdl_ios/SmartDeviceLink/SDLInterfaceProtocol.h | 3 ++- sdl_ios/SmartDeviceLink/SDLProxy.h | 4 +++- sdl_ios/SmartDeviceLink/SDLProxy.m | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/sdl_ios/SmartDeviceLink/SDLInterfaceProtocol.h b/sdl_ios/SmartDeviceLink/SDLInterfaceProtocol.h index de6591ada..c1d1da490 100644 --- a/sdl_ios/SmartDeviceLink/SDLInterfaceProtocol.h +++ b/sdl_ios/SmartDeviceLink/SDLInterfaceProtocol.h @@ -17,6 +17,7 @@ - (void)handleBytesFromTransport:(NSData *)receivedData; - (void)sendStartSessionWithType:(SDLServiceType)sessionType; - (void)sendEndSessionWithType:(SDLServiceType)sessionType sessionID:(Byte)sessionID; -- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest; +- (void)sendRPC:(SDLRPCMessage *)message; +- (void)sendRPCRequest:(SDLRPCRequest *)rpcRequest __deprecated_msg("use sendRPC: instead"); @end \ No newline at end of file diff --git a/sdl_ios/SmartDeviceLink/SDLProxy.h b/sdl_ios/SmartDeviceLink/SDLProxy.h index ac3dafb4b..98d626bf6 100644 --- a/sdl_ios/SmartDeviceLink/SDLProxy.h +++ b/sdl_ios/SmartDeviceLink/SDLProxy.h @@ -29,7 +29,9 @@ -(void) dispose; -(void) addDelegate:(NSObject*) delegate; --(void) sendRPCRequest:(SDLRPCMessage*) msg; +-(void) sendRPCRequest:(SDLRPCMessage*) msg __deprecated_msg("use sendRPC: instead"); +-(void) sendRPC:(SDLRPCMessage *)message; + -(void) handleRpcMessage:(NSDictionary*) msg; -(NSString*) getProxyVersion; diff --git a/sdl_ios/SmartDeviceLink/SDLProxy.m b/sdl_ios/SmartDeviceLink/SDLProxy.m index 6297e29e8..2c8995fad 100644 --- a/sdl_ios/SmartDeviceLink/SDLProxy.m +++ b/sdl_ios/SmartDeviceLink/SDLProxy.m @@ -209,6 +209,15 @@ - (void) onProtocolMessageReceived:(SDLProtocolMessage*) msgData { #pragma mark - Message sending and recieving +- (void)sendRPC:(SDLRPCMessage *)message { + @try { + [self.protocol sendRPC:message]; + } @catch (NSException *exception) { + NSString *logMessage = [NSString stringWithFormat:@"Proxy: Failed to send RPC message: %@", message.name]; + [SDLDebugTool logInfo:logMessage withType:SDLDebugType_Debug toOutput:SDLDebugOutput_All toGroup:self.debugConsoleGroupName]; + } +} + -(void) sendRPCRequest:(SDLRPCMessage*) msg { if ([msg isKindOfClass:SDLRPCRequest.class]) { [self sendRPCRequestPrivate:(SDLRPCRequest *)msg];