Skip to content

Commit

Permalink
Merge pull request #1886 from smartdevicelink/feature/issue-1024-sdl-…
Browse files Browse the repository at this point in the history
…0180-broaden-choiceCell-uniqueness

SDL 0180 - Fix to support broaden choice cell uniqueness
  • Loading branch information
joeljfischer authored Mar 4, 2021
2 parents ee70ad1 + 35e3168 commit 19055a8
Show file tree
Hide file tree
Showing 25 changed files with 523 additions and 107 deletions.
20 changes: 20 additions & 0 deletions SmartDeviceLink-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@
4A457DD524A3C16E00386CBA /* SDLLifecycleMobileHMIStateHandlerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A457DD424A3C16E00386CBA /* SDLLifecycleMobileHMIStateHandlerSpec.m */; };
4A457DD724A3CCED00386CBA /* SDLLifecycleSystemRequestHandlerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A457DD624A3CCED00386CBA /* SDLLifecycleSystemRequestHandlerSpec.m */; };
4A457DD924A5137100386CBA /* SDLLifecycleProtocolHandlerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A457DD824A5137100386CBA /* SDLLifecycleProtocolHandlerSpec.m */; };
4A5822C225E40BB5002822F1 /* NSArray+ExtensionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A5822C125E40BB5002822F1 /* NSArray+ExtensionsSpec.m */; };
4A8BD23B24F93135000945E3 /* SDLMassageCushionFirmness.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8BD22324F93131000945E3 /* SDLMassageCushionFirmness.h */; settings = {ATTRIBUTES = (Public, ); }; };
4A8BD23C24F93135000945E3 /* SDLMediaServiceData.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A8BD22424F93131000945E3 /* SDLMediaServiceData.m */; };
4A8BD23D24F93135000945E3 /* SDLMsgVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A8BD22524F93132000945E3 /* SDLMsgVersion.m */; };
Expand Down Expand Up @@ -1716,6 +1717,10 @@
B3A9DA1225D270EA00CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A9DA1125D270E900CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m */; };
B3EC9E6E2579AA010039F3AA /* SDLClimateDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = B3EC9E6D2579AA010039F3AA /* SDLClimateDataSpec.m */; };
B3F7918324E062C200DB5CAF /* SDLGetVehicleDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 162E824C1A9BDE8A00906325 /* SDLGetVehicleDataSpec.m */; };
C9707D1825DEE786009D00F2 /* NSArray+Extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = C9707D1625DEE786009D00F2 /* NSArray+Extensions.h */; };
C9707D1925DEE786009D00F2 /* NSArray+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = C9707D1725DEE786009D00F2 /* NSArray+Extensions.m */; };
C9707D3025E0444D009D00F2 /* SDLMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = C9707D2E25E0444D009D00F2 /* SDLMacros.h */; };
C9707D3125E0444D009D00F2 /* SDLMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = C9707D2F25E0444D009D00F2 /* SDLMacros.m */; };
C975877F257AEFDB0066F271 /* SDLSeekIndicatorTypeSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = C975877E257AEFDB0066F271 /* SDLSeekIndicatorTypeSpec.m */; };
C9758785257F4C570066F271 /* SDLSeekStreamingIndicatorSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = C9758784257F4C570066F271 /* SDLSeekStreamingIndicatorSpec.m */; };
C9DFFE78257ACE0000F7D57A /* SDLSeekStreamingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = C9DFFE76257ACE0000F7D57A /* SDLSeekStreamingIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -2132,6 +2137,7 @@
4A457DD424A3C16E00386CBA /* SDLLifecycleMobileHMIStateHandlerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLLifecycleMobileHMIStateHandlerSpec.m; path = DevAPISpecs/SDLLifecycleMobileHMIStateHandlerSpec.m; sourceTree = "<group>"; };
4A457DD624A3CCED00386CBA /* SDLLifecycleSystemRequestHandlerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLLifecycleSystemRequestHandlerSpec.m; path = DevAPISpecs/SDLLifecycleSystemRequestHandlerSpec.m; sourceTree = "<group>"; };
4A457DD824A5137100386CBA /* SDLLifecycleProtocolHandlerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLLifecycleProtocolHandlerSpec.m; path = DevAPISpecs/SDLLifecycleProtocolHandlerSpec.m; sourceTree = "<group>"; };
4A5822C125E40BB5002822F1 /* NSArray+ExtensionsSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSArray+ExtensionsSpec.m"; path = "DevAPISpecs/NSArray+ExtensionsSpec.m"; sourceTree = "<group>"; };
4A680F192513E1F4004A2C31 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
4A8BD22324F93131000945E3 /* SDLMassageCushionFirmness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLMassageCushionFirmness.h; path = public/SDLMassageCushionFirmness.h; sourceTree = "<group>"; };
4A8BD22424F93131000945E3 /* SDLMediaServiceData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLMediaServiceData.m; path = public/SDLMediaServiceData.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3595,6 +3601,10 @@
B3A9DA1125D270E900CDFD21 /* SDLKeyboardLayoutCapabilitySpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLKeyboardLayoutCapabilitySpec.m; sourceTree = "<group>"; };
B3EC9E6D2579AA010039F3AA /* SDLClimateDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLClimateDataSpec.m; sourceTree = "<group>"; };
BB3C600D221AEF37007DD4CA /* NSMutableDictionary+StoreSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSMutableDictionary+StoreSpec.m"; path = "DevAPISpecs/NSMutableDictionary+StoreSpec.m"; sourceTree = "<group>"; };
C9707D1625DEE786009D00F2 /* NSArray+Extensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSArray+Extensions.h"; path = "private/NSArray+Extensions.h"; sourceTree = "<group>"; };
C9707D1725DEE786009D00F2 /* NSArray+Extensions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSArray+Extensions.m"; path = "private/NSArray+Extensions.m"; sourceTree = "<group>"; };
C9707D2E25E0444D009D00F2 /* SDLMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLMacros.h; path = private/SDLMacros.h; sourceTree = "<group>"; };
C9707D2F25E0444D009D00F2 /* SDLMacros.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLMacros.m; path = private/SDLMacros.m; sourceTree = "<group>"; };
C975877E257AEFDB0066F271 /* SDLSeekIndicatorTypeSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSeekIndicatorTypeSpec.m; sourceTree = "<group>"; };
C9758784257F4C570066F271 /* SDLSeekStreamingIndicatorSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLSeekStreamingIndicatorSpec.m; sourceTree = "<group>"; };
C9DFFE76257ACE0000F7D57A /* SDLSeekStreamingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDLSeekStreamingIndicator.h; path = public/SDLSeekStreamingIndicator.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5877,6 +5887,7 @@
children = (
5D6EB4CB1BF28DC600693731 /* NSMapTable+SubscriptingSpec.m */,
BB3C600D221AEF37007DD4CA /* NSMutableDictionary+StoreSpec.m */,
4A5822C125E40BB5002822F1 /* NSArray+ExtensionsSpec.m */,
);
name = Categories;
sourceTree = "<group>";
Expand Down Expand Up @@ -6191,6 +6202,10 @@
4ABB24B824F592620061BF55 /* NSMutableDictionary+SafeRemove.h */,
4ABB24B524F592620061BF55 /* NSMutableDictionary+SafeRemove.m */,
4A8BD3AB24F98602000945E3 /* NSNumber+NumberType.h */,
C9707D1625DEE786009D00F2 /* NSArray+Extensions.h */,
C9707D1725DEE786009D00F2 /* NSArray+Extensions.m */,
C9707D2E25E0444D009D00F2 /* SDLMacros.h */,
C9707D2F25E0444D009D00F2 /* SDLMacros.m */,
);
name = Categories;
sourceTree = "<group>";
Expand Down Expand Up @@ -7357,6 +7372,7 @@
4ABB2AB824F847F40061BF55 /* SDLSendHapticDataResponse.h in Headers */,
4ABB268624F7F8E20061BF55 /* SDLMutableDataQueue.h in Headers */,
4ABB27CE24F8006D0061BF55 /* SDLMediaType.h in Headers */,
C9707D1825DEE786009D00F2 /* NSArray+Extensions.h in Headers */,
4ABB28E324F82A6A0061BF55 /* SDLOnTBTClientState.h in Headers */,
4ABB2A5C24F847B10061BF55 /* SDLGetWayPointsResponse.h in Headers */,
4ABB260024F7E9230061BF55 /* SDLStreamingMediaManagerConstants.h in Headers */,
Expand Down Expand Up @@ -7441,6 +7457,7 @@
4ABB25E024F7E7980061BF55 /* SDLStreamingMediaConfiguration.h in Headers */,
4A8BD2FE24F938A4000945E3 /* SDLVehicleType.h in Headers */,
4ABB282B24F824E70061BF55 /* SDLTBTState.h in Headers */,
C9707D3025E0444D009D00F2 /* SDLMacros.h in Headers */,
4ABB26D724F7FAFD0061BF55 /* SDLRPCMessage.h in Headers */,
4A8BD24A24F93135000945E3 /* SDLMyKey.h in Headers */,
4ABB24F924F5959E0061BF55 /* SDLAsynchronousOperation.h in Headers */,
Expand Down Expand Up @@ -7998,6 +8015,7 @@
4ABB255C24F7E5880061BF55 /* SDLPermissionFilter.m in Sources */,
4ABB27C624F8006D0061BF55 /* SDLModuleType.m in Sources */,
4ABB25FD24F7E8E10061BF55 /* SDLStreamingVideoScaleManager.m in Sources */,
C9707D3125E0444D009D00F2 /* SDLMacros.m in Sources */,
4ABB26F724F7FB8F0061BF55 /* SDLAudioStreamingState.m in Sources */,
4ABB265A24F7F5C10061BF55 /* SDLRPCResponseNotification.m in Sources */,
4ABB2AB724F847F40061BF55 /* SDLSetGlobalPropertiesResponse.m in Sources */,
Expand Down Expand Up @@ -8039,6 +8057,7 @@
4ABB265624F7F5B40061BF55 /* SDLRPCNotificationNotification.m in Sources */,
4ABB2B8424F8504A0061BF55 /* SDLHMISettingsControlData.m in Sources */,
4ABB287624F8294A0061BF55 /* SDLVentilationMode.m in Sources */,
C9707D1925DEE786009D00F2 /* NSArray+Extensions.m in Sources */,
4ABB25E724F7E7A90061BF55 /* SDLAudioStreamManager.m in Sources */,
4ABB277B24F7FEBA0061BF55 /* SDLLightStatus.m in Sources */,
4ABB2A7324F847D40061BF55 /* SDLPutFileResponse.m in Sources */,
Expand Down Expand Up @@ -8910,6 +8929,7 @@
5DBF0D601F3B3DB4008AF2C9 /* SDLControlFrameVideoStartServiceAckSpec.m in Sources */,
162E83311A9BDE8B00906325 /* SDLListFilesSpec.m in Sources */,
EE5D1B33208EBCA900D17216 /* SDLTCPTransportSpec.m in Sources */,
4A5822C225E40BB5002822F1 /* NSArray+ExtensionsSpec.m in Sources */,
DA9F7EB01DCC063400ACAE48 /* SDLLocationDetailsSpec.m in Sources */,
8816772922208B82001FACFF /* SDLNavigationInstructionSpec.m in Sources */,
5DC978261B7A38640012C2F1 /* SDLGlobalsSpec.m in Sources */,
Expand Down
20 changes: 20 additions & 0 deletions SmartDeviceLink/private/NSArray+Extensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// NSArray+Extensions.h
// SmartDeviceLink
//
// Created by Frank Elias on 2/18/21.
// Copyright © 2021 smartdevicelink. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "SDLMacros.h"

NS_ASSUME_NONNULL_BEGIN

@interface NSArray (Extensions)

-(NSUInteger)dynamicHash;

@end

NS_ASSUME_NONNULL_END
26 changes: 26 additions & 0 deletions SmartDeviceLink/private/NSArray+Extensions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// NSArray+Extensions.m
// SmartDeviceLink
//
// Created by Frank Elias on 2/18/21.
// Copyright © 2021 smartdevicelink. All rights reserved.
//

#import "NSArray+Extensions.h"

@implementation NSArray (Extensions)

/// A dynamic version of the NSArray `hash` method. The default `hash` method returns the number of objects in the array as its hash and this leads to clashes between arrays with the same number of objects.
/// Instead, this method calls hash on each of it's sub-objects, XOR and rotates them, then returns this as the hash. This is much slower than the default hash method, but sometimes necessary to properly compare arrays.
/// @returns A hash based on the hashes of all of the contained objects
- (NSUInteger)dynamicHash {
NSUInteger retVal = 0;
for (NSUInteger i = 0; i < self.count; i++) {
retVal ^= NSUIntRotateCell(((NSObject *)self[i]).hash, (NSUIntBitCell / (i + 2)));
}

return retVal;
}


@end
50 changes: 40 additions & 10 deletions SmartDeviceLink/private/SDLChoiceSetManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#import "SDLStateMachine.h"
#import "SDLSystemCapability.h"
#import "SDLSystemCapabilityManager.h"
#import "SDLVersion.h"
#import "SDLWindowCapability.h"
#import "SDLWindowCapability+ScreenManagerExtensions.h"

Expand All @@ -53,6 +54,7 @@
@interface SDLChoiceCell()

@property (assign, nonatomic) UInt16 choiceId;
@property (strong, nonatomic, readwrite) NSString *uniqueText;

@end

Expand Down Expand Up @@ -229,13 +231,14 @@ - (void)preloadChoices:(NSArray<SDLChoiceCell *> *)choices withCompletionHandler
return;
}

NSMutableSet<SDLChoiceCell *> *choicesToUpload = [[self sdl_choicesToBeUploadedWithArray:choices] mutableCopy];

NSMutableOrderedSet<SDLChoiceCell *> *mutableChoicesToUpload = [self sdl_choicesToBeUploadedWithArray:choices];
[SDLGlobals runSyncOnSerialSubQueue:self.readWriteQueue block:^{
[choicesToUpload minusSet:self.preloadedMutableChoices];
[choicesToUpload minusSet:self.pendingMutablePreloadChoices];
[mutableChoicesToUpload minusSet:self.preloadedMutableChoices];
[mutableChoicesToUpload minusSet:self.pendingMutablePreloadChoices];
}];

NSOrderedSet<SDLChoiceCell *> *choicesToUpload = [mutableChoicesToUpload copy];
if (choicesToUpload.count == 0) {
SDLLogD(@"All choices already preloaded. No need to perform a preload");
if (handler != nil) {
Expand All @@ -249,7 +252,7 @@ - (void)preloadChoices:(NSArray<SDLChoiceCell *> *)choices withCompletionHandler

// Add the preload cells to the pending preloads
[SDLGlobals runSyncOnSerialSubQueue:self.readWriteQueue block:^{
[self.pendingMutablePreloadChoices unionSet:choicesToUpload];
[self.pendingMutablePreloadChoices unionSet:choicesToUpload.set];
}];

// Upload pending preloads
Expand Down Expand Up @@ -277,8 +280,8 @@ - (void)preloadChoices:(NSArray<SDLChoiceCell *> *)choices withCompletionHandler

[SDLGlobals runSyncOnSerialSubQueue:self.readWriteQueue block:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf.preloadedMutableChoices unionSet:choicesToUpload];
[strongSelf.pendingMutablePreloadChoices minusSet:choicesToUpload];
[strongSelf.preloadedMutableChoices unionSet:choicesToUpload.set];
[strongSelf.pendingMutablePreloadChoices minusSet:choicesToUpload.set];
}];
};
[self.transactionQueue addOperation:preloadOp];
Expand Down Expand Up @@ -447,11 +450,38 @@ - (void)dismissKeyboardWithCancelID:(NSNumber<SDLInt> *)cancelID {
/// Checks the passed list of choices to be uploaded and returns the items that have not yet been uploaded to the module.
/// @param choices The choices to be uploaded
/// @return The choices that have not yet been uploaded to the module
- (NSSet<SDLChoiceCell *> *)sdl_choicesToBeUploadedWithArray:(NSArray<SDLChoiceCell *> *)choices {
NSMutableSet<SDLChoiceCell *> *choicesSet = [NSMutableSet setWithArray:choices];
- (NSMutableOrderedSet<SDLChoiceCell *> *)sdl_choicesToBeUploadedWithArray:(NSArray<SDLChoiceCell *> *)choices {
NSMutableOrderedSet<SDLChoiceCell *> *choicesSet = [[NSMutableOrderedSet alloc] initWithArray:choices];

// If we're running on a connection < RPC 7.1, we need to de-duplicate cells because presenting them will fail if we have the same cell primary text.
SDLVersion *choiceUniquenessSupportedVersion = [[SDLVersion alloc] initWithMajor:7 minor:1 patch:0];
if ([[SDLGlobals sharedGlobals].rpcVersion isLessThanVersion:choiceUniquenessSupportedVersion]) {
[self sdl_addUniqueNamesToCells:choicesSet];
}
[choicesSet minusSet:self.preloadedChoices];

return [choicesSet copy];
return choicesSet;
}

/// Checks if 2 or more cells have the same text/title. In case this condition is true, this function will handle the presented issue by adding "(count)".
/// E.g. Choices param contains 2 cells with text/title "Address" will be handled by updating the uniqueText/uniqueTitle of the second cell to "Address (2)".
/// @param choices The choices to be uploaded.
- (void)sdl_addUniqueNamesToCells:(NSOrderedSet<SDLChoiceCell *> *)choices {
// Tracks how many of each cell primary text there are so that we can append numbers to make each unique as necessary
NSMutableDictionary<NSString *, NSNumber *> *dictCounter = [[NSMutableDictionary alloc] init];
for (SDLChoiceCell *cell in choices) {
NSString *cellName = cell.text;
NSNumber *counter = dictCounter[cellName];
if (counter != nil) {
counter = @(counter.intValue + 1);
dictCounter[cellName] = counter;
} else {
dictCounter[cellName] = @1;
}
if (counter.intValue > 1) {
cell.uniqueText = [NSString stringWithFormat: @"%@ (%d)", cell.text, counter.intValue];
}
}
}

/// Checks the passed list of choices to be deleted and returns the items that have been uploaded to the module.
Expand All @@ -476,7 +506,7 @@ - (void)dismissKeyboardWithCancelID:(NSNumber<SDLInt> *)cancelID {

/// Assigns a unique id to each choice item.
/// @param choices An array of choices
- (void)sdl_updateIdsOnChoices:(NSSet<SDLChoiceCell *> *)choices {
- (void)sdl_updateIdsOnChoices:(NSOrderedSet<SDLChoiceCell *> *)choices {
for (SDLChoiceCell *cell in choices) {
cell.choiceId = self.nextChoiceId;
}
Expand Down
16 changes: 16 additions & 0 deletions SmartDeviceLink/private/SDLMacros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// SDLMacros.h
// SmartDeviceLink
//
// Created by Joel Fischer on 2/8/21.
// Copyright © 2021 smartdevicelink. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

extern NSUInteger const NSUIntBitCell;
extern NSUInteger NSUIntRotateCell(NSUInteger val, NSUInteger howMuch);

NS_ASSUME_NONNULL_END
14 changes: 14 additions & 0 deletions SmartDeviceLink/private/SDLMacros.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// SDLMacros.m
// SmartDeviceLink
//
// Created by Joel Fischer on 2/8/21.
// Copyright © 2021 smartdevicelink. All rights reserved.
//

#import "SDLMacros.h"

NSUInteger const NSUIntBitCell = (CHAR_BIT * sizeof(NSUInteger));
NSUInteger NSUIntRotateCell(NSUInteger val, NSUInteger howMuch) {
return ((((NSUInteger)val) << howMuch) | (((NSUInteger)val) >> (NSUIntBitCell - howMuch)));
}
Loading

0 comments on commit 19055a8

Please sign in to comment.