diff options
Diffstat (limited to 'SmartDeviceLink/private/SDLVoiceCommandManager.m')
-rw-r--r-- | SmartDeviceLink/private/SDLVoiceCommandManager.m | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/SmartDeviceLink/private/SDLVoiceCommandManager.m b/SmartDeviceLink/private/SDLVoiceCommandManager.m index fc0048736..3d7f51dd5 100644 --- a/SmartDeviceLink/private/SDLVoiceCommandManager.m +++ b/SmartDeviceLink/private/SDLVoiceCommandManager.m @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SDLVoiceCommand() @property (assign, nonatomic) UInt32 commandId; +@property (copy, nonatomic, readwrite) NSArray<NSString *> *voiceCommands; @end @@ -40,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN @property (assign, nonatomic) UInt32 lastVoiceCommandId; @property (copy, nonatomic) NSArray<SDLVoiceCommand *> *currentVoiceCommands; +@property (copy, nonatomic) NSArray<SDLVoiceCommand *> *originalVoiceCommands; @end @@ -104,20 +106,33 @@ UInt32 const VoiceCommandIdMin = 1900000000; #pragma mark - Setters - (void)setVoiceCommands:(NSArray<SDLVoiceCommand *> *)voiceCommands { - if (voiceCommands == self.voiceCommands) { + if (voiceCommands == self.originalVoiceCommands) { SDLLogD(@"New voice commands are equal to the existing voice commands, skipping..."); return; } - // Set the ids - [self sdl_updateIdsOnVoiceCommands:voiceCommands]; + // Validate the voiceCommand's strings. In the rare case that the user has set only empty whitespace strings, abort the update operation. + NSArray<SDLVoiceCommand *> *validatedVoiceCommands = [self sdl_removeEmptyVoiceCommands:voiceCommands]; + if (validatedVoiceCommands.count == 0 && voiceCommands.count > 0) { + SDLLogE(@"New voice commands are invalid, skipping..."); + return; + } + + // Check if all new voice commands have unique strings + if (![self.class sdl_arePendingVoiceCommandsUnique:voiceCommands]) { + SDLLogE(@"Not all voice command strings are unique across all voice commands. Voice commands will not be set."); + return; + } // Set the new voice commands internally - _voiceCommands = voiceCommands; + _originalVoiceCommands = voiceCommands; + _voiceCommands = validatedVoiceCommands; + // Set the ids + [self sdl_updateIdsOnVoiceCommands:self.voiceCommands]; // Create the operation, cancel previous ones and set this one __weak typeof(self) weakSelf = self; - SDLVoiceCommandUpdateOperation *updateOperation = [[SDLVoiceCommandUpdateOperation alloc] initWithConnectionManager:self.connectionManager pendingVoiceCommands:voiceCommands oldVoiceCommands:_currentVoiceCommands updateCompletionHandler:^(NSArray<SDLVoiceCommand *> *newCurrentVoiceCommands, NSError * _Nullable error) { + SDLVoiceCommandUpdateOperation *updateOperation = [[SDLVoiceCommandUpdateOperation alloc] initWithConnectionManager:self.connectionManager pendingVoiceCommands:self.voiceCommands oldVoiceCommands:_currentVoiceCommands updateCompletionHandler:^(NSArray<SDLVoiceCommand *> *newCurrentVoiceCommands, NSError * _Nullable error) { weakSelf.currentVoiceCommands = newCurrentVoiceCommands; [weakSelf sdl_updatePendingOperationsWithNewCurrentVoiceCommands:newCurrentVoiceCommands]; }]; @@ -146,12 +161,46 @@ UInt32 const VoiceCommandIdMin = 1900000000; } } +/// Remove all voice command strings consisting of just whitespace characters as the module will reject any "empty" strings. +/// @param voiceCommands - array of SDLVoiceCommands that are to be uploaded +/// @return A list of voice commands with the empty voice commands removed +- (NSArray<SDLVoiceCommand *> *)sdl_removeEmptyVoiceCommands:(NSArray<SDLVoiceCommand *> *)voiceCommands { + NSMutableArray<SDLVoiceCommand *> *validatedVoiceCommands = [[NSMutableArray alloc] init]; + for (SDLVoiceCommand *voiceCommand in voiceCommands) { + NSMutableArray<NSString *> *voiceCommandStrings = [[NSMutableArray alloc] init]; + for (NSString *voiceCommandString in voiceCommand.voiceCommands) { + NSString *trimmedString = [voiceCommandString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + // Updates voice command strings array by only adding ones that are not empty(e.g. "", " ", ...) + if (trimmedString.length > 0) { + [voiceCommandStrings addObject:voiceCommandString]; + } + } + if (voiceCommandStrings.count > 0) { + voiceCommand.voiceCommands = voiceCommandStrings; + [validatedVoiceCommands addObject:voiceCommand]; + } + } + return [validatedVoiceCommands copy]; +} + +/// Evaluate the pendingVoiceCommands to check if there is two or more voiceCommands with the same string ++ (BOOL)sdl_arePendingVoiceCommandsUnique:(NSArray<SDLVoiceCommand *> *)voiceCommands { + NSUInteger voiceCommandCount = 0; + NSMutableSet<NSString *> *voiceCommandsSet = [[NSMutableSet alloc] init]; + for (SDLVoiceCommand *voiceCommand in voiceCommands) { + [voiceCommandsSet addObjectsFromArray:voiceCommand.voiceCommands]; + voiceCommandCount += voiceCommand.voiceCommands.count; + } + + return (voiceCommandsSet.count == voiceCommandCount); +} + #pragma mark - Observers - (void)sdl_commandNotification:(SDLRPCNotificationNotification *)notification { SDLOnCommand *onCommand = (SDLOnCommand *)notification.notification; - for (SDLVoiceCommand *voiceCommand in self.voiceCommands) { + for (SDLVoiceCommand *voiceCommand in self.currentVoiceCommands) { if (onCommand.cmdID.unsignedIntegerValue != voiceCommand.commandId) { continue; } voiceCommand.handler(); |