summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2019-05-21 16:31:08 -0400
committerJoel Fischer <joeljfischer@gmail.com>2019-05-21 16:31:08 -0400
commit9419bd13adf0785cb731bc19d16e9de073297368 (patch)
tree0dd165d3d17cc776cc504c9e6d5ccf223dc70780
parente8f84aba02246dbdebfc9eb69cb71398afe889ec (diff)
downloadsdl_ios-9419bd13adf0785cb731bc19d16e9de073297368.tar.gz
In progress capability observations
-rw-r--r--SmartDeviceLink/SDLSystemCapabilityManager.h40
-rw-r--r--SmartDeviceLink/SDLSystemCapabilityManager.m104
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