diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2019-04-05 16:24:40 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-05 16:24:40 -0400 |
commit | 416b73e40351e0801fcc1ae1d91cac5fa9a8b658 (patch) | |
tree | 3385f714d975d70dcaed4cb1a4f0d2650828367a | |
parent | 4c0a0821c2909a4fcad11996b9a1591e38c7d27c (diff) | |
parent | 292a6cbfcbeb6133627ce01cd96235cf857fafa9 (diff) | |
download | sdl_ios-416b73e40351e0801fcc1ae1d91cac5fa9a8b658.tar.gz |
Merge pull request #1215 from smartdevicelink/feature/issue_1212_update_system_capability_manager_auto_caching
Update System Capability Manager to auto-cache`OnSystemCapability`
-rw-r--r-- | SmartDeviceLink/SDLSystemCapabilityManager.m | 184 | ||||
-rw-r--r-- | SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m | 218 |
2 files changed, 296 insertions, 106 deletions
diff --git a/SmartDeviceLink/SDLSystemCapabilityManager.m b/SmartDeviceLink/SDLSystemCapabilityManager.m index 04d991e66..0a48ce71f 100644 --- a/SmartDeviceLink/SDLSystemCapabilityManager.m +++ b/SmartDeviceLink/SDLSystemCapabilityManager.m @@ -8,25 +8,34 @@ #import "SDLSystemCapabilityManager.h" +#import "SDLAppServiceCapability.h" +#import "SDLAppServiceRecord.h" #import "SDLAppServicesCapabilities.h" #import "SDLConnectionManagerType.h" #import "SDLGenericResponse.h" #import "SDLGetSystemCapability.h" #import "SDLGetSystemCapabilityResponse.h" +#import "SDLGlobals.h" #import "SDLLogMacros.h" #import "SDLNotificationConstants.h" +#import "SDLOnHMIStatus.h" +#import "SDLOnSystemCapabilityUpdated.h" #import "SDLRegisterAppInterfaceResponse.h" +#import "SDLRPCNotificationNotification.h" #import "SDLRPCResponseNotification.h" #import "SDLSetDisplayLayoutResponse.h" #import "SDLSystemCapability.h" +#import "SDLVersion.h" #import "SDLVideoStreamingCapability.h" + NS_ASSUME_NONNULL_BEGIN @interface SDLSystemCapabilityManager () +typedef NSString * SDLServiceID; + @property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; -@property (copy, nonatomic, nullable) SDLUpdateCapabilityHandler systemCapabilityHandler; @property (nullable, strong, nonatomic, readwrite) SDLDisplayCapabilities *displayCapabilities; @property (nullable, strong, nonatomic, readwrite) SDLHMICapabilities *hmiCapabilities; @@ -39,12 +48,15 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign, readwrite) BOOL vrCapability; @property (nullable, copy, nonatomic, readwrite) NSArray<SDLAudioPassThruCapabilities *> *audioPassThruCapabilities; @property (nullable, strong, nonatomic, readwrite) SDLAudioPassThruCapabilities *pcmStreamCapability; -@property (nullable, strong, nonatomic, readwrite) SDLAppServicesCapabilities *appServicesCapabilities; @property (nullable, strong, nonatomic, readwrite) SDLNavigationCapability *navigationCapability; @property (nullable, strong, nonatomic, readwrite) SDLPhoneCapability *phoneCapability; @property (nullable, strong, nonatomic, readwrite) SDLVideoStreamingCapability *videoStreamingCapability; @property (nullable, strong, nonatomic, readwrite) SDLRemoteControlCapabilities *remoteControlCapability; +@property (nullable, strong, nonatomic) NSMutableDictionary<SDLServiceID, SDLAppServiceCapability *> *appServicesCapabilitiesDictionary; + +@property (assign, nonatomic) BOOL isFirstHMILevelFull; + @end @implementation SDLSystemCapabilityManager @@ -58,11 +70,17 @@ NS_ASSUME_NONNULL_BEGIN } _connectionManager = manager; + _isFirstHMILevelFull = NO; + _appServicesCapabilitiesDictionary = [NSMutableDictionary dictionary]; + [self sdl_registerForNotifications]; return self; } +/** + * Resets the capabilities when a transport session is closed. + */ - (void)stop { SDLLogD(@"System Capability manager stopped"); _displayCapabilities = nil; @@ -80,18 +98,36 @@ NS_ASSUME_NONNULL_BEGIN _phoneCapability = nil; _videoStreamingCapability = nil; _remoteControlCapability = nil; - _appServicesCapabilities = nil; + _appServicesCapabilitiesDictionary = [NSMutableDictionary dictionary]; + + _isFirstHMILevelFull = NO; } +#pragma mark - Getters + +- (nullable SDLAppServicesCapabilities *)appServicesCapabilities { + if (self.appServicesCapabilitiesDictionary.count == 0) { return nil; } + + return [[SDLAppServicesCapabilities alloc] initWithAppServices:self.appServicesCapabilitiesDictionary.allValues]; +} #pragma mark - Notifications +/** + * Registers for notifications and responses from Core + */ -(void)sdl_registerForNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_registerResponse:) name:SDLDidReceiveRegisterAppInterfaceResponse object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_displayLayoutResponse:) name:SDLDidReceiveSetDisplayLayoutResponse object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_systemCapabilityResponse:) name:SDLDidReceiveGetSystemCapabilitiesResponse object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_systemCapabilityUpdatedNotification:) name:SDLDidReceiveSystemCapabilityUpdatedNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_hmiStatusNotification:) name:SDLDidChangeHMIStatusNotification object:nil]; } +/** + * Called when a `RegisterAppInterfaceResponse` response is received from Core. The head unit capabilities are saved. + * + * @param notification The `RegisterAppInterfaceResponse` response received from Core + */ - (void)sdl_registerResponse:(SDLRPCResponseNotification *)notification { SDLRegisterAppInterfaceResponse *response = (SDLRegisterAppInterfaceResponse *)notification.response; if (!response.success.boolValue) { return; } @@ -109,6 +145,11 @@ NS_ASSUME_NONNULL_BEGIN self.pcmStreamCapability = response.pcmStreamCapabilities; } +/** + * Called when a `SetDisplayLayoutResponse` response is received from Core. If the template was set successfully, the the new capabilities for the template are saved. + * + * @param notification The `SetDisplayLayoutResponse` response received from Core + */ - (void)sdl_displayLayoutResponse:(SDLRPCResponseNotification *)notification { SDLSetDisplayLayoutResponse *response = (SDLSetDisplayLayoutResponse *)notification.response; if (!response.success.boolValue) { return; } @@ -119,41 +160,132 @@ NS_ASSUME_NONNULL_BEGIN self.presetBankCapabilities = response.presetBankCapabilities; } -- (void)sdl_systemCapabilityResponse:(SDLRPCResponseNotification *)notification { - SDLGetSystemCapabilityResponse *response = (SDLGetSystemCapabilityResponse *)notification.response; - if (!response.success.boolValue) { return; } +/** + * Called when an `OnSystemCapabilityUpdated` notification is received from Core. The updated system capabilty is saved. + * + * @param notification The `OnSystemCapabilityUpdated` notification received from Core + */ +- (void)sdl_systemCapabilityUpdatedNotification:(SDLRPCNotificationNotification *)notification { + SDLOnSystemCapabilityUpdated *systemCapabilityUpdatedNotification = (SDLOnSystemCapabilityUpdated *)notification.notification; + [self sdl_saveSystemCapability:systemCapabilityUpdatedNotification.systemCapability completionHandler:nil]; +} + +/** + * Called when an `OnHMIStatus` notification is received from Core. The first time the `hmiLevel` is `FULL` attempt to subscribe to system capabilty updates. + * + * @param notification The `OnHMIStatus` notification received from Core + */ +- (void)sdl_hmiStatusNotification:(SDLRPCNotificationNotification *)notification { + SDLOnHMIStatus *hmiStatus = (SDLOnHMIStatus *)notification.notification; + if (self.isFirstHMILevelFull || ![hmiStatus.hmiLevel isEqualToEnum:SDLHMILevelFull]) { + return; + } + + self.isFirstHMILevelFull = YES; + [self sdl_subscribeToSystemCapabilityUpdates]; +} + +#pragma mark - System Capabilities + +- (void)updateCapabilityType:(SDLSystemCapabilityType)type completionHandler:(SDLUpdateCapabilityHandler)handler { + SDLVersion *onSystemCapabilityNotificationRPCVersion = [SDLVersion versionWithString:@"5.1.0"]; + SDLVersion *headUnitRPCVersion = SDLGlobals.sharedGlobals.rpcVersion; + if ([headUnitRPCVersion isGreaterThanOrEqualToVersion:onSystemCapabilityNotificationRPCVersion]) { + // Just return the cached data because we get `onSystemCapability` callbacks + handler(nil, self); + } else { + // Go and get the actual data + SDLGetSystemCapability *getSystemCapability = [[SDLGetSystemCapability alloc] initWithType:type]; + [self sdl_sendGetSystemCapability:getSystemCapability completionHandler:handler]; + } +} + +/** + * A list of all possible system capability types. + * + * @return An array of all possible system capability types + */ ++ (NSArray<SDLSystemCapabilityType> *)sdl_systemCapabilityTypes { + return @[SDLSystemCapabilityTypeAppServices, SDLSystemCapabilityTypeNavigation, SDLSystemCapabilityTypePhoneCall, SDLSystemCapabilityTypeVideoStreaming, SDLSystemCapabilityTypeRemoteControl]; +} + +/** + * Sends a subscribe request for all possible system capabilites. If connecting to Core versions 4.5+, the requested capability will be returned in the response. If connecting to Core versions 5.1+, the manager will received `OnSystemCapabilityUpdated` notifications when the capability updates if the subscription was successful. + */ +- (void)sdl_subscribeToSystemCapabilityUpdates { + for (SDLSystemCapabilityType type in [self.class sdl_systemCapabilityTypes]) { + SDLGetSystemCapability *getSystemCapability = [[SDLGetSystemCapability alloc] initWithType:type]; + SDLVersion *onSystemCapabilityNotificationRPCVersion = [SDLVersion versionWithString:@"5.1.0"]; + SDLVersion *headUnitRPCVersion = SDLGlobals.sharedGlobals.rpcVersion; + if ([headUnitRPCVersion isGreaterThanOrEqualToVersion:onSystemCapabilityNotificationRPCVersion]) { + getSystemCapability.subscribe = @YES; + } - SDLSystemCapability *systemCapabilityResponse = ((SDLGetSystemCapabilityResponse *)response).systemCapability; - SDLSystemCapabilityType systemCapabilityType = systemCapabilityResponse.systemCapabilityType; + [self sdl_sendGetSystemCapability:getSystemCapability completionHandler:nil]; + } +} + +/** + * Sends a `GetSystemCapability` to Core and handles the response by saving the returned data and notifying the subscriber. + * + * @param getSystemCapability The `GetSystemCapability` request to send + */ +- (void)sdl_sendGetSystemCapability:(SDLGetSystemCapability *)getSystemCapability completionHandler:(nullable SDLUpdateCapabilityHandler)handler { + [self.connectionManager sendConnectionRequest:getSystemCapability withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { + if (error != nil) { + // An error is returned if the request was unsuccessful or if a Generic Response was returned + if (handler == nil) { return; } + handler(error, self); + return; + } + + SDLGetSystemCapabilityResponse *getSystemCapabilityResponse = (SDLGetSystemCapabilityResponse *)response; + if (!getSystemCapabilityResponse.success.boolValue) { return; } + [self sdl_saveSystemCapability:getSystemCapabilityResponse.systemCapability completionHandler:handler]; + }]; +} + +/** + * Saves a system capability. All system capabilities will update with the full object except for app services. For app services only the updated app service capabilities will be included in the `SystemCapability` sent from Core. The cached `appServicesCapabilities` will be updated with the new `appService` data. + * + * @param systemCapability The system capability + */ +- (void)sdl_saveSystemCapability:(SDLSystemCapability *)systemCapability completionHandler:(nullable SDLUpdateCapabilityHandler)handler { + SDLSystemCapabilityType systemCapabilityType = systemCapability.systemCapabilityType; if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypePhoneCall]) { - self.phoneCapability = systemCapabilityResponse.phoneCapability; + self.phoneCapability = systemCapability.phoneCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeNavigation]) { - self.navigationCapability = systemCapabilityResponse.navigationCapability; + self.navigationCapability = systemCapability.navigationCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeRemoteControl]) { - self.remoteControlCapability = systemCapabilityResponse.remoteControlCapability; + self.remoteControlCapability = systemCapability.remoteControlCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeVideoStreaming]) { - self.videoStreamingCapability = systemCapabilityResponse.videoStreamingCapability; + self.videoStreamingCapability = systemCapability.videoStreamingCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeAppServices]) { - self.appServicesCapabilities = systemCapabilityResponse.appServicesCapabilities; + [self sdl_saveAppServicesCapabilitiesUpdate:systemCapability.appServicesCapabilities]; } else { SDLLogW(@"Received response for unknown System Capability Type: %@", systemCapabilityType); + return; } - if (self.systemCapabilityHandler == nil) { return; } - self.systemCapabilityHandler(nil, self); -} + SDLLogD(@"Updated system capability manager with new data: %@", systemCapability); -#pragma mark - Capability Request + if (handler == nil) { return; } + handler(nil, self); +} -- (void)updateCapabilityType:(SDLSystemCapabilityType)type completionHandler:(SDLUpdateCapabilityHandler)handler { - self.systemCapabilityHandler = handler; - SDLGetSystemCapability *getSystemCapability = [[SDLGetSystemCapability alloc] initWithType:type]; - [self.connectionManager sendConnectionRequest:getSystemCapability withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) { - if (error == nil) { return; } - // An error is returned if the request was unsuccessful or a Generic Response is returned - handler(error, self); - }]; +- (void)sdl_saveAppServicesCapabilitiesUpdate:(SDLAppServicesCapabilities *)newCapabilities { + for (SDLAppServiceCapability *capability in newCapabilities.appServices) { + if (capability.updateReason == nil) { + // First update, new capability + self.appServicesCapabilitiesDictionary[capability.updatedAppServiceRecord.serviceID] = capability; + } else if ([capability.updateReason isEqualToEnum:SDLServiceUpdateRemoved]) { + self.appServicesCapabilitiesDictionary[capability.updatedAppServiceRecord.serviceID] = nil; + } else { + // Everything else involves adding or updating the existing service record + self.appServicesCapabilitiesDictionary[capability.updatedAppServiceRecord.serviceID] = capability; + } + } } @end diff --git a/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m b/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m index a3bb55c58..109b8ea2d 100644 --- a/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m +++ b/SmartDeviceLinkTests/SDLSystemCapabilityManagerSpec.m @@ -1,14 +1,21 @@ #import <Quick/Quick.h> #import <Nimble/Nimble.h> +#import "SDLAppServiceCapability.h" +#import "SDLAppServiceManifest.h" +#import "SDLAppServiceRecord.h" +#import "SDLAppServicesCapabilities.h" #import "SDLAudioPassThruCapabilities.h" #import "SDLButtonCapabilities.h" #import "SDLDisplayCapabilities.h" #import "SDLGetSystemCapability.h" #import "SDLGetSystemCapabilityResponse.h" #import "SDLHMICapabilities.h" +#import "SDLMediaServiceManifest.h" #import "SDLNavigationCapability.h" #import "SDLNotificationConstants.h" +#import "SDLOnHMIStatus.h" +#import "SDLOnSystemCapabilityUpdated.h" #import "SDLPhoneCapability.h" #import "SDLPresetBankCapabilities.h" #import "SDLRegisterAppInterfaceResponse.h" @@ -256,12 +263,12 @@ describe(@"System capability manager", ^{ }); }); - context(@"When notified of a Get System Capability Response", ^{ + context(@"When sending a Get System Capability request", ^{ __block SDLGetSystemCapabilityResponse *testGetSystemCapabilityResponse; __block SDLPhoneCapability *testPhoneCapability = nil; beforeEach(^{ - testPhoneCapability = [[SDLPhoneCapability alloc] initWithDialNumber:YES]; + testPhoneCapability = [[SDLPhoneCapability alloc] initWithDialNumber:YES]; testGetSystemCapabilityResponse = [[SDLGetSystemCapabilityResponse alloc] init]; testGetSystemCapabilityResponse.systemCapability = [[SDLSystemCapability alloc] init]; @@ -269,69 +276,45 @@ describe(@"System capability manager", ^{ testGetSystemCapabilityResponse.systemCapability.systemCapabilityType = SDLSystemCapabilityTypePhoneCall; }); - describe(@"If a Get System Capability Response notification is received", ^{ - context(@"If the request failed", ^{ - beforeEach(^{ - testGetSystemCapabilityResponse.success = @NO; - SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveGetSystemCapabilitiesResponse object:self rpcResponse:testGetSystemCapabilityResponse]; - [[NSNotificationCenter defaultCenter] postNotification:notification]; - }); + context(@"If the request failed with an error", ^{ + __block NSError *testError = nil; - it(@"should should not save the capabilities", ^{ - expect(testSystemCapabilityManager.phoneCapability).to(beNil()); - }); + beforeEach(^{ + testGetSystemCapabilityResponse.success = @NO; + testError = [NSError errorWithDomain:NSCocoaErrorDomain code:-234 userInfo:nil]; }); - context(@"If the request succeeded", ^{ - beforeEach(^{ - testGetSystemCapabilityResponse.success = @YES; - SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveGetSystemCapabilitiesResponse object:self rpcResponse:testGetSystemCapabilityResponse]; - [[NSNotificationCenter defaultCenter] postNotification:notification]; - }); + it(@"should should not save the capabilities", ^{ + waitUntilTimeout(1, ^(void (^done)(void)) { + [testSystemCapabilityManager updateCapabilityType:testGetSystemCapabilityResponse.systemCapability.systemCapabilityType completionHandler:^(NSError * _Nullable error, SDLSystemCapabilityManager * _Nonnull systemCapabilityManager) { + expect(error).to(equal(testConnectionManager.defaultError)); + expect(systemCapabilityManager.phoneCapability).to(beNil()); + done(); + }]; + + [NSThread sleepForTimeInterval:0.1]; - it(@"should should save the capabilities", ^{ - expect(testSystemCapabilityManager.phoneCapability).to(equal(testPhoneCapability)); + [testConnectionManager respondToLastRequestWithResponse:testGetSystemCapabilityResponse]; }); }); }); - describe(@"If a response is received for a sent Get System Capability request", ^{ - context(@"If the request failed with an error", ^{ - __block NSError *testError = nil; - - beforeEach(^{ - testGetSystemCapabilityResponse.success = @NO; - testError = [NSError errorWithDomain:NSCocoaErrorDomain code:-234 userInfo:nil]; - - waitUntilTimeout(1.0, ^(void (^done)(void)) { - [testSystemCapabilityManager updateCapabilityType:testGetSystemCapabilityResponse.systemCapability.systemCapabilityType completionHandler:^(NSError * _Nullable error, SDLSystemCapabilityManager * _Nonnull systemCapabilityManager) { - expect(error).to(equal(testConnectionManager.defaultError)); - expect(systemCapabilityManager.phoneCapability).to(beNil()); - done(); - }]; - - [testConnectionManager respondToLastRequestWithResponse:testGetSystemCapabilityResponse]; - }); - }); - - it(@"should should not save the capabilities", ^{ - expect(testSystemCapabilityManager.phoneCapability).to(beNil()); - }); + context(@"If the request succeeded", ^{ + beforeEach(^{ + testGetSystemCapabilityResponse.success = @YES; }); - context(@"If the request succeeded", ^{ - beforeEach(^{ - testGetSystemCapabilityResponse.success = @YES; - + it(@"should save the capabilitity", ^{ + waitUntilTimeout(1, ^(void (^done)(void)){ [testSystemCapabilityManager updateCapabilityType:testGetSystemCapabilityResponse.systemCapability.systemCapabilityType completionHandler:^(NSError * _Nullable error, SDLSystemCapabilityManager * _Nonnull systemCapabilityManager) { - // The handler will not be notifified + expect(testSystemCapabilityManager.phoneCapability).to(equal(testPhoneCapability)); + expect(error).to(beNil()); + done(); }]; - [testConnectionManager respondToLastRequestWithResponse:testGetSystemCapabilityResponse]; - }); + [NSThread sleepForTimeInterval:0.1]; - it(@"should not save the capabilities because a successful Get System Capability Response notification will be intercepted by the manager and be handled there", ^{ - expect(testSystemCapabilityManager.phoneCapability).to(beNil()); + [testConnectionManager respondToLastRequestWithResponse:testGetSystemCapabilityResponse]; }); }); }); @@ -356,46 +339,121 @@ describe(@"System capability manager", ^{ }); }); - context(@"When the system capability manager is stopped after being started", ^{ + describe(@"updating the SCM through OnSystemCapability", ^{ + __block SDLPhoneCapability *phoneCapability = nil; + beforeEach(^{ - SDLDisplayCapabilities *testDisplayCapabilities = [[SDLDisplayCapabilities alloc] init]; - testDisplayCapabilities.graphicSupported = @NO; + phoneCapability = [[SDLPhoneCapability alloc] initWithDialNumber:YES]; + SDLSystemCapability *newCapability = [[SDLSystemCapability alloc] initWithPhoneCapability:phoneCapability]; + SDLOnSystemCapabilityUpdated *update = [[SDLOnSystemCapabilityUpdated alloc] initWithSystemCapability:newCapability]; + SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveSystemCapabilityUpdatedNotification object:nil rpcNotification:update]; + [[NSNotificationCenter defaultCenter] postNotification:notification]; + }); - SDLRegisterAppInterfaceResponse *testRegisterAppInterfaceResponse = [[SDLRegisterAppInterfaceResponse alloc] init]; - testRegisterAppInterfaceResponse.displayCapabilities = testDisplayCapabilities; - testRegisterAppInterfaceResponse.success = @YES; + it(@"should properly update phone capability", ^{ + expect(testSystemCapabilityManager.phoneCapability).toEventually(equal(phoneCapability)); + }); + }); + + describe(@"merging app services capability changes", ^{ + __block SDLAppServicesCapabilities *baseAppServices = nil; + __block SDLAppServiceCapability *deleteCapability = nil; + __block SDLAppServiceCapability *updateCapability = nil; + __block SDLAppServiceCapability *newCapability = nil; - SDLRPCResponseNotification *notification = [[SDLRPCResponseNotification alloc] initWithName:SDLDidReceiveRegisterAppInterfaceResponse object:self rpcResponse:testRegisterAppInterfaceResponse]; + beforeEach(^{ + SDLAppServiceManifest *deleteCapabilityManifest = [[SDLAppServiceManifest alloc] initWithMediaServiceName:@"Delete me" serviceIcon:nil allowAppConsumers:YES rpcSpecVersion:nil handledRPCs:nil mediaServiceManifest:[[SDLMediaServiceManifest alloc] init]]; + SDLAppServiceRecord *deleteCapabilityRecord = [[SDLAppServiceRecord alloc] initWithServiceID:@"1234" serviceManifest:deleteCapabilityManifest servicePublished:YES serviceActive:YES]; + deleteCapability = [[SDLAppServiceCapability alloc] initWithUpdatedAppServiceRecord:deleteCapabilityRecord]; + + SDLAppServiceManifest *updateCapabilityManifest = [[SDLAppServiceManifest alloc] initWithMediaServiceName:@"Update me" serviceIcon:nil allowAppConsumers:YES rpcSpecVersion:nil handledRPCs:nil mediaServiceManifest:[[SDLMediaServiceManifest alloc] init]]; + SDLAppServiceRecord *updateCapabilityRecord = [[SDLAppServiceRecord alloc] initWithServiceID:@"2345" serviceManifest:updateCapabilityManifest servicePublished:YES serviceActive:NO]; + updateCapability = [[SDLAppServiceCapability alloc] initWithUpdatedAppServiceRecord:updateCapabilityRecord]; + + baseAppServices = [[SDLAppServicesCapabilities alloc] initWithAppServices:@[deleteCapability, updateCapability]]; + SDLSystemCapability *appServiceCapability = [[SDLSystemCapability alloc] initWithAppServicesCapabilities:baseAppServices]; + SDLOnSystemCapabilityUpdated *update = [[SDLOnSystemCapabilityUpdated alloc] initWithSystemCapability:appServiceCapability]; + SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveSystemCapabilityUpdatedNotification object:nil rpcNotification:update]; [[NSNotificationCenter defaultCenter] postNotification:notification]; + }); - expect(testSystemCapabilityManager.displayCapabilities).to(equal(testDisplayCapabilities)); + it(@"should have the correct base services", ^{ + expect(testSystemCapabilityManager.appServicesCapabilities).to(equal(baseAppServices)); }); - describe(@"When stopped", ^{ - beforeEach(^{ - [testSystemCapabilityManager stop]; - }); + describe(@"when sending the merge update", ^{ + it(@"should correctly merge", ^{ + deleteCapability.updateReason = SDLServiceUpdateRemoved; + deleteCapability.updatedAppServiceRecord.servicePublished = @NO; + deleteCapability.updatedAppServiceRecord.serviceActive = @NO; - it(@"It should reset the system capability manager properties correctly", ^{ - expect(testSystemCapabilityManager.displayCapabilities).to(beNil()); - expect(testSystemCapabilityManager.hmiCapabilities).to(beNil()); - expect(testSystemCapabilityManager.softButtonCapabilities).to(beNil()); - expect(testSystemCapabilityManager.buttonCapabilities).to(beNil()); - expect(testSystemCapabilityManager.presetBankCapabilities).to(beNil()); - expect(testSystemCapabilityManager.hmiZoneCapabilities).to(beNil()); - expect(testSystemCapabilityManager.speechCapabilities).to(beNil()); - expect(testSystemCapabilityManager.prerecordedSpeechCapabilities).to(beNil()); - expect(testSystemCapabilityManager.vrCapability).to(beFalse()); - expect(testSystemCapabilityManager.audioPassThruCapabilities).to(beNil()); - expect(testSystemCapabilityManager.pcmStreamCapability).to(beNil()); - expect(testSystemCapabilityManager.phoneCapability).to(beNil()); - expect(testSystemCapabilityManager.navigationCapability).to(beNil()); - expect(testSystemCapabilityManager.videoStreamingCapability).to(beNil()); - expect(testSystemCapabilityManager.remoteControlCapability).to(beNil()); - expect(testSystemCapabilityManager.appServicesCapabilities).to(beNil()); + updateCapability.updateReason = SDLServiceUpdateActivated; + updateCapability.updatedAppServiceRecord.serviceActive = @YES; + + SDLAppServiceManifest *newCapabilityManifest = [[SDLAppServiceManifest alloc] initWithMediaServiceName:@"New me" serviceIcon:nil allowAppConsumers:YES rpcSpecVersion:nil handledRPCs:nil mediaServiceManifest:[[SDLMediaServiceManifest alloc] init]]; + SDLAppServiceRecord *newCapabilityRecord = [[SDLAppServiceRecord alloc] initWithServiceID:@"3456" serviceManifest:newCapabilityManifest servicePublished:YES serviceActive:NO]; + newCapability = [[SDLAppServiceCapability alloc] initWithUpdateReason:SDLServiceUpdatePublished updatedAppServiceRecord:newCapabilityRecord]; + + SDLAppServicesCapabilities *appServicesUpdate = [[SDLAppServicesCapabilities alloc] initWithAppServices:@[deleteCapability, updateCapability, newCapability]]; + SDLSystemCapability *appServiceCapability = [[SDLSystemCapability alloc] initWithAppServicesCapabilities:appServicesUpdate]; + SDLOnSystemCapabilityUpdated *update = [[SDLOnSystemCapabilityUpdated alloc] initWithSystemCapability:appServiceCapability]; + SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidReceiveSystemCapabilityUpdatedNotification object:nil rpcNotification:update]; + [[NSNotificationCenter defaultCenter] postNotification:notification]; + + expect(testSystemCapabilityManager.appServicesCapabilities.appServices).toNot(contain(deleteCapability)); + expect(testSystemCapabilityManager.appServicesCapabilities.appServices).to(haveCount(2)); + + SDLAppServiceCapability *firstCapability = testSystemCapabilityManager.appServicesCapabilities.appServices.firstObject; + SDLAppServiceCapability *secondCapability = testSystemCapabilityManager.appServicesCapabilities.appServices.lastObject; + + expect(firstCapability.updateReason).to(equal(SDLServiceUpdatePublished)); + expect(firstCapability.updatedAppServiceRecord.serviceID).to(equal(@"3456")); + + expect(secondCapability.updateReason).to(equal(SDLServiceUpdateActivated)); + expect(secondCapability.updatedAppServiceRecord.serviceID).to(equal(@"2345")); + expect(secondCapability.updatedAppServiceRecord.serviceActive).to(beTrue()); }); }); }); + + describe(@"when entering HMI FULL", ^{ + beforeEach(^{ + SDLOnHMIStatus *fullStatus = [[SDLOnHMIStatus alloc] init]; + fullStatus.hmiLevel = SDLHMILevelFull; + SDLRPCNotificationNotification *notification = [[SDLRPCNotificationNotification alloc] initWithName:SDLDidChangeHMIStatusNotification object:nil rpcNotification:fullStatus]; + [[NSNotificationCenter defaultCenter] postNotification:notification]; + }); + + it(@"should send GetSystemCapability subscriptions for all known capabilities", ^{ + expect(testConnectionManager.receivedRequests).to(haveCount(5)); + expect(testConnectionManager.receivedRequests.lastObject).to(beAnInstanceOf([SDLGetSystemCapability class])); + }); + }); + + describe(@"when the system capability manager is stopped after being started", ^{ + beforeEach(^{ + [testSystemCapabilityManager stop]; + }); + + it(@"It should reset the system capability manager properties correctly", ^{ + expect(testSystemCapabilityManager.displayCapabilities).to(beNil()); + expect(testSystemCapabilityManager.hmiCapabilities).to(beNil()); + expect(testSystemCapabilityManager.softButtonCapabilities).to(beNil()); + expect(testSystemCapabilityManager.buttonCapabilities).to(beNil()); + expect(testSystemCapabilityManager.presetBankCapabilities).to(beNil()); + expect(testSystemCapabilityManager.hmiZoneCapabilities).to(beNil()); + expect(testSystemCapabilityManager.speechCapabilities).to(beNil()); + expect(testSystemCapabilityManager.prerecordedSpeechCapabilities).to(beNil()); + expect(testSystemCapabilityManager.vrCapability).to(beFalse()); + expect(testSystemCapabilityManager.audioPassThruCapabilities).to(beNil()); + expect(testSystemCapabilityManager.pcmStreamCapability).to(beNil()); + expect(testSystemCapabilityManager.phoneCapability).to(beNil()); + expect(testSystemCapabilityManager.navigationCapability).to(beNil()); + expect(testSystemCapabilityManager.videoStreamingCapability).to(beNil()); + expect(testSystemCapabilityManager.remoteControlCapability).to(beNil()); + expect(testSystemCapabilityManager.appServicesCapabilities).to(beNil()); + }); + }); }); QuickSpecEnd |