diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2019-05-21 16:31:08 -0400 |
---|---|---|
committer | Joel Fischer <joeljfischer@gmail.com> | 2019-05-21 16:31:08 -0400 |
commit | 9419bd13adf0785cb731bc19d16e9de073297368 (patch) | |
tree | 0dd165d3d17cc776cc504c9e6d5ccf223dc70780 | |
parent | e8f84aba02246dbdebfc9eb69cb71398afe889ec (diff) | |
download | sdl_ios-9419bd13adf0785cb731bc19d16e9de073297368.tar.gz |
In progress capability observations
-rw-r--r-- | SmartDeviceLink/SDLSystemCapabilityManager.h | 40 | ||||
-rw-r--r-- | SmartDeviceLink/SDLSystemCapabilityManager.m | 104 |
2 files changed, 135 insertions, 9 deletions
diff --git a/SmartDeviceLink/SDLSystemCapabilityManager.h b/SmartDeviceLink/SDLSystemCapabilityManager.h index 11e31a1c2..da6d21ee4 100644 --- a/SmartDeviceLink/SDLSystemCapabilityManager.h +++ b/SmartDeviceLink/SDLSystemCapabilityManager.h @@ -24,6 +24,7 @@ @class SDLPresetBankCapabilities; @class SDLRemoteControlCapabilities; @class SDLSoftButtonCapabilities; +@class SDLSystemCapability; @class SDLSystemCapabilityManager; @class SDLVideoStreamingCapability; @@ -31,7 +32,6 @@ NS_ASSUME_NONNULL_BEGIN - /** * A completion handler called after a request for the capability type is returned from the remote system. * @@ -40,6 +40,13 @@ NS_ASSUME_NONNULL_BEGIN */ typedef void (^SDLUpdateCapabilityHandler)(NSError * _Nullable error, SDLSystemCapabilityManager *systemCapabilityManager); +/** + An observer block whenever a subscription is called. + + @param systemCapabilityManager This manager. The user of the handler can then use the manager to pull the newest data. + */ +typedef void (^SDLCapabilityUpdateHandler)(SDLSystemCapabilityManager *systemCapabilityManager); + @interface SDLSystemCapabilityManager : NSObject @@ -198,6 +205,37 @@ typedef void (^SDLUpdateCapabilityHandler)(NSError * _Nullable error, SDLSystemC */ - (void)updateCapabilityType:(SDLSystemCapabilityType)type completionHandler:(SDLUpdateCapabilityHandler)handler; +/** + Subscribe to a particular capability type using a block callback + + @param type The type of capability to subscribe to + @param block The block to be called when the capability is updated + @return An object that can be used to unsubscribe the block using unsubscribeFromCapabilityType:withObserver: by passing it in the observer callback + */ +- (id<NSObject>)subscribeToCapabilityType:(SDLSystemCapabilityType)type usingBlock:(SDLCapabilityUpdateHandler)block; + +/** + * Subscribe to a particular capability type with a selector callback. The selector supports the following parameters: + * + * 1. No parameters e.g. `- (void)phoneCapabilityUpdated;` + * 2. One `SDLSystemCapability *` parameter e.g. `- (void)phoneCapabilityUpdated:(SDLSystemCapability *)capability` + * + * This method will be called immediately with the current value and called every time the value is updated on RPC v5.1.0+ systems (`supportsSubscriptions == YES`). If this method is called on a sub-v5.1.0 system (`supportsSubscriptions == NO`), the method will return `NO` and the selector will never be called. + * + * @param type The type of the system capability to subscribe to + * @param observer The object that will have `selector` called whenever the capability is updated + * @param selector The selector on `observer` that will be called whenever the capability is updated + * @return Whether or not the subscription succeeded. `NO` if the connected system doesn't support capability subscriptions, or if the `selector` doesn't support the correct parameters (see above) + */ +- (BOOL)subscribeToCapabilityType:(SDLSystemCapabilityType)type withObserver:(id)observer selector:(SEL)selector; + +/** + * Unsubscribe from a particular capability type. If it was subscribed with a block, the return value should be passed to the `observer` to unsubscribe the block. If it was subscribed with a selector, the `observer` object should be passed to unsubscribe the object selector. + * + * @param type The type of the system capability to unsubscribe from + * @param observer The object that will be unsubscribed. If a block was subscribed, the return value should be passed. If a selector was subscribed, the observer object should be passed. + */ +- (void)unsubscribeFromCapabilityType:(SDLSystemCapabilityType)type withObserver:(id)observer; @end diff --git a/SmartDeviceLink/SDLSystemCapabilityManager.m b/SmartDeviceLink/SDLSystemCapabilityManager.m index bbe839bcf..49344e751 100644 --- a/SmartDeviceLink/SDLSystemCapabilityManager.m +++ b/SmartDeviceLink/SDLSystemCapabilityManager.m @@ -34,6 +34,43 @@ NS_ASSUME_NONNULL_BEGIN +@interface SDLSystemCapabilityObserver : NSObject + +@property (strong, nonatomic) id<NSObject> observer; +@property (assign, nonatomic) SEL selector; +@property (copy, nonatomic) SDLCapabilityUpdateHandler block; + +- (instancetype)initWithObserver:(id<NSObject>)observer selector:(SEL)selector; +- (instancetype)initWithObserver:(id<NSObject>)observer block:(SDLCapabilityUpdateHandler)block; + +@end + +@implementation SDLSystemCapabilityObserver + +- (instancetype)initWithObserver:(id<NSObject>)observer selector:(SEL)selector { + self = [super init]; + if (!self) { return nil; } + + _observer = observer; + _selector = selector; + + return self; +} + +- (instancetype)initWithObserver:(id<NSObject>)observer block:(SDLCapabilityUpdateHandler)block { + self = [super init]; + if (!self) { return nil; } + + _observer = observer; + _block = block; + + return self; +} + +@end + + + @interface SDLSystemCapabilityManager () typedef NSString * SDLServiceID; @@ -58,6 +95,8 @@ typedef NSString * SDLServiceID; @property (nullable, strong, nonatomic) NSMutableDictionary<SDLServiceID, SDLAppServiceCapability *> *appServicesCapabilitiesDictionary; +@property (strong, nonatomic) NSMutableDictionary<SDLSystemCapabilityType, NSMutableArray<SDLSystemCapabilityObserver *> *> *capabilityObservers; + @property (nullable, strong, nonatomic) SDLSystemCapability *lastReceivedCapability; @property (assign, nonatomic) BOOL isFirstHMILevelFull; @@ -78,6 +117,11 @@ typedef NSString * SDLServiceID; _isFirstHMILevelFull = NO; _appServicesCapabilitiesDictionary = [NSMutableDictionary dictionary]; + _capabilityObservers = [NSMutableDictionary dictionary]; + for (SDLSystemCapabilityType capabilityType in [self.class sdl_systemCapabilityTypes]) { + _capabilityObservers[capabilityType] = @[]; + } + [self sdl_registerForNotifications]; return self; @@ -270,26 +314,26 @@ typedef NSString * SDLServiceID; */ - (BOOL)sdl_saveSystemCapability:(SDLSystemCapability *)systemCapability completionHandler:(nullable SDLUpdateCapabilityHandler)handler { if ([self.lastReceivedCapability isEqual:systemCapability]) { - return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; + return [self sdl_callSaveHandlerForCapabilityType:systemCapability.systemCapabilityType andReturnWithValue:NO handler:handler]; } self.lastReceivedCapability = systemCapability; SDLSystemCapabilityType systemCapabilityType = systemCapability.systemCapabilityType; if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypePhoneCall]) { - if ([self.phoneCapability isEqual:systemCapability.phoneCapability]) { return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; } + if ([self.phoneCapability isEqual:systemCapability.phoneCapability]) { return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:NO handler:handler]; } self.phoneCapability = systemCapability.phoneCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeNavigation]) { - if ([self.navigationCapability isEqual:systemCapability.navigationCapability]) { return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; } + if ([self.navigationCapability isEqual:systemCapability.navigationCapability]) { return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:NO handler:handler]; } self.navigationCapability = systemCapability.navigationCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeRemoteControl]) { - if ([self.remoteControlCapability isEqual:systemCapability.remoteControlCapability]) { return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; } + if ([self.remoteControlCapability isEqual:systemCapability.remoteControlCapability]) { return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:NO handler:handler]; } self.remoteControlCapability = systemCapability.remoteControlCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeVideoStreaming]) { - if ([self.videoStreamingCapability isEqual:systemCapability.videoStreamingCapability]) { return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; } + if ([self.videoStreamingCapability isEqual:systemCapability.videoStreamingCapability]) { return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:NO handler:handler]; } self.videoStreamingCapability = systemCapability.videoStreamingCapability; } else if ([systemCapabilityType isEqualToEnum:SDLSystemCapabilityTypeAppServices]) { - if ([self.appServicesCapabilities isEqual:systemCapability.appServicesCapabilities]) { return [self sdl_callSaveHandlerAndReturnWithValue:NO handler:handler]; } + if ([self.appServicesCapabilities isEqual:systemCapability.appServicesCapabilities]) { return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:NO handler:handler]; } [self sdl_saveAppServicesCapabilitiesUpdate:systemCapability.appServicesCapabilities]; } else { SDLLogW(@"Received response for unknown System Capability Type: %@", systemCapabilityType); @@ -298,15 +342,34 @@ typedef NSString * SDLServiceID; SDLLogD(@"Updated system capability manager with new data: %@", systemCapability); - return [self sdl_callSaveHandlerAndReturnWithValue:YES handler:handler]; + return [self sdl_callSaveHandlerForCapabilityType:systemCapabilityType andReturnWithValue:YES handler:handler]; } -- (BOOL)sdl_callSaveHandlerAndReturnWithValue:(BOOL)value handler:(nullable SDLUpdateCapabilityHandler)handler { +- (BOOL)sdl_callSaveHandlerForCapabilityType:(SDLSystemCapabilityType)type andReturnWithValue:(BOOL)value handler:(nullable SDLUpdateCapabilityHandler)handler { if (handler == nil) { return value; } handler(nil, self); + + for (SDLSystemCapabilityObserver *observer in self.capabilityObservers[type]) { + if (observer.block != nil) { + observer.block(self); + } else { + if ([observer.observer respondsToSelector:observer.selector]) { + [observer.observer performSelector:observer.selector]; + } + } + } + return value; } +//- (SDLSystemCapability *)capabilityForType:(SDLSystemCapabilityType)type { +// if ([type isEqualToEnum:SDLSystemCapabilityTypePhoneCall]) { +// return [[SDLSystemCapability alloc] initWithPhoneCapability:self.phoneCapability]; +// } else if ([type isEqualToEnum:SDLSystemCapabilityTypeNavigation]) { +// return [SDLSystemcap] self.navigationCapability; +// } +//} + - (void)sdl_saveAppServicesCapabilitiesUpdate:(SDLAppServicesCapabilities *)newCapabilities { for (SDLAppServiceCapability *capability in newCapabilities.appServices) { if (capability.updateReason == nil) { @@ -321,6 +384,31 @@ typedef NSString * SDLServiceID; } } +#pragma mark - Subscriptions + +- (id<NSObject>)subscribeToCapabilityType:(SDLSystemCapabilityType)type usingBlock:(SDLCapabilityUpdateHandler)block { + SDLSystemCapabilityObserver *observerObject = [[SDLSystemCapabilityObserver alloc] initWithObserver:[[NSObject alloc] init] block:block]; + [self.capabilityObservers[type] addObject:observerObject]; + + return observerObject.observer; +} + +- (BOOL)subscribeToCapabilityType:(SDLSystemCapabilityType)type withObserver:(id<NSObject>)observer selector:(SEL)selector { + SDLSystemCapabilityObserver *observerObject = [[SDLSystemCapabilityObserver alloc] initWithObserver:observer selector:selector]; + [self.capabilityObservers[type] addObject:observerObject]; + + return observerObject.observer; +} + +- (void)unsubscribeFromCapabilityType:(SDLSystemCapabilityType)type withObserver:(id)observer { + for (SDLSystemCapabilityObserver *capabilityObserver in self.capabilityObservers[type]) { + if ([observer isEqual:capabilityObserver.observer]) { + [self.capabilityObservers[type] removeObject:capabilityObserver]; + break; + } + } +} + @end NS_ASSUME_NONNULL_END |