Chromium Code Reviews| Index: content/renderer/bluetooth/bluetooth_dispatcher.cc |
| diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.cc b/content/renderer/bluetooth/bluetooth_dispatcher.cc |
| index 1a4679e6d63291c6cb450c564ed1cd8f98f109ac..2e83e4fd3e49219fdf56ffdc9e82a63438554c0c 100644 |
| --- a/content/renderer/bluetooth/bluetooth_dispatcher.cc |
| +++ b/content/renderer/bluetooth/bluetooth_dispatcher.cc |
| @@ -15,6 +15,7 @@ |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h" |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h" |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristic.h" |
| +#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristicDelegate.h" |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h" |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTService.h" |
| #include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h" |
| @@ -62,6 +63,25 @@ struct BluetoothCharacteristicRequest { |
| scoped_ptr<blink::WebBluetoothGetCharacteristicCallbacks> callbacks; |
| }; |
| +struct BluetoothNotificationsRequest { |
| + BluetoothNotificationsRequest( |
| + blink::WebString characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate, |
| + blink::WebBluetoothNotificationsCallbacks* callbacks) |
| + : characteristic_instance_id(characteristic_instance_id), |
| + delegate(delegate), |
| + callbacks(callbacks) {} |
| + ~BluetoothNotificationsRequest() {} |
| + |
| + blink::WebString characteristic_instance_id; |
| + // Note that the delegate is owned by the execution context on the blink |
| + // side which can destroy the delegate at any point. Since the delegate |
| + // implements ActiveDOMObject we do get notify when it's being destroyed, |
| + // so we can remove any references to it. |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate; |
| + scoped_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks; |
| +}; |
| + |
| namespace content { |
| namespace { |
| @@ -143,6 +163,12 @@ void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) { |
| OnWriteValueSuccess); |
| IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueError, |
| OnWriteValueError); |
| + IPC_MESSAGE_HANDLER(BluetoothMsg_StartNotificationsSuccess, |
| + OnStartNotificationsSuccess) |
| + IPC_MESSAGE_HANDLER(BluetoothMsg_StartNotificationsError, |
| + OnStartNotificationsError) |
| + IPC_MESSAGE_HANDLER(BluetoothMsg_StopNotificationsSuccess, |
| + OnStopNotificationsSuccess) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| DCHECK(handled) << "Unhandled message:" << msg.type(); |
| @@ -225,10 +251,145 @@ void BluetoothDispatcher::writeValue( |
| CurrentWorkerId(), request_id, characteristic_instance_id.utf8(), value)); |
| } |
| +void BluetoothDispatcher::startNotifications( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate, |
| + blink::WebBluetoothNotificationsCallbacks* callbacks) { |
| + // If an object is already subcribed to notifications from the characteristic, |
| + // no need to subscribe to the dispatcher host again. |
| + if (HasActiveCharacteristicNotification(characteristic_instance_id)) { |
| + AddToActiveNotificationsMap(characteristic_instance_id, delegate); |
| + callbacks->onSuccess(); |
| + return; |
| + } |
| + |
| + int request_id = pending_start_notifications_requests_.Add( |
| + new BluetoothNotificationsRequest(characteristic_instance_id, delegate, |
| + callbacks)); |
| + |
| + Send(new BluetoothHostMsg_StartNotifications( |
| + CurrentWorkerId(), request_id, characteristic_instance_id.utf8())); |
| +} |
| + |
| +void BluetoothDispatcher::stopNotifications( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate, |
| + blink::WebBluetoothNotificationsCallbacks* callbacks) { |
| + // If this is not an active characteristic then no need to unsubscribe. |
| + if (!HasActiveCharacteristicNotification(characteristic_instance_id)) { |
| + callbacks->onSuccess(); |
| + return; |
| + } |
| + |
| + if (WillBeActiveNotificationWhenRemoved(characteristic_instance_id, |
| + delegate)) { |
| + RemoveFromActiveNotificationsMap(characteristic_instance_id, delegate); |
| + callbacks->onSuccess(); |
| + return; |
| + } |
| + |
| + int request_id = pending_stop_notifications_requests_.Add( |
| + new BluetoothNotificationsRequest(characteristic_instance_id, delegate, |
| + callbacks)); |
| + |
| + Send(new BluetoothHostMsg_StopNotifications( |
| + CurrentWorkerId(), request_id, characteristic_instance_id.utf8())); |
| +} |
| + |
| +void BluetoothDispatcher::characteristicDelegateRemoved( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate) { |
| + RemoveFromActiveNotificationsMap(characteristic_instance_id, delegate); |
| + |
| + // If the characteristic is still active no need to unsubscribe. |
| + if (HasActiveCharacteristicNotification(characteristic_instance_id)) { |
| + return; |
| + } |
| + |
| + // There could be a request pending on a delegate so we need to check |
| + // the requests map. We ignore the stop request since we don't use |
| + // the delegate in those. |
| + for (IDMap<BluetoothNotificationsRequest, IDMapOwnPointer>::iterator iter( |
| + &pending_start_notifications_requests_); |
| + !iter.IsAtEnd(); iter.Advance()) { |
| + iter.GetCurrentValue()->delegate = nullptr; |
| + } |
| +} |
| + |
| void BluetoothDispatcher::WillStopCurrentWorkerThread() { |
| delete this; |
| } |
| +bool BluetoothDispatcher::HasActiveCharacteristicNotification( |
| + const blink::WebString& characteristic_instance_id) { |
| + auto char_iter = active_characteristic_notifications.find( |
| + characteristic_instance_id.utf8()); |
| + |
| + // An active characteristic will point to a set of delegates. |
| + if (char_iter == active_characteristic_notifications.end()) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void BluetoothDispatcher::AddToActiveNotificationsMap( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate) { |
| + auto char_iter = active_characteristic_notifications.find( |
| + characteristic_instance_id.utf8()); |
| + |
| + // First object that subscribes to notifications for the characteristic. |
| + if (char_iter == active_characteristic_notifications.end()) { |
| + std::set<blink::WebBluetoothGATTCharacteristicDelegate*> delegates; |
| + delegates.insert(delegate); |
| + active_characteristic_notifications.insert( |
| + std::make_pair(characteristic_instance_id.utf8(), delegates)); |
| + return; |
| + } |
| + // Otherwise add to already existing set. |
| + char_iter->second.insert(delegate); |
| +} |
| + |
| +bool BluetoothDispatcher::WillBeActiveNotificationWhenRemoved( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate) { |
| + auto char_iter = active_characteristic_notifications.find( |
| + characteristic_instance_id.utf8()); |
| + |
| + // The characteristic will point to a set as long as there is at least |
| + // one delegate subscribed to notifications. |
| + if (char_iter == active_characteristic_notifications.end()) { |
| + return false; |
| + } |
| + const std::set<blink::WebBluetoothGATTCharacteristicDelegate*>& delegate_set = |
| + char_iter->second; |
| + // If we find the delegate and the size of the set is one then removing |
| + // the delegate will make the notification inactive. |
| + if (delegate_set.find(delegate) != delegate_set.end() && |
| + delegate_set.size() == 1) { |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +void BluetoothDispatcher::RemoveFromActiveNotificationsMap( |
| + const blink::WebString& characteristic_instance_id, |
| + blink::WebBluetoothGATTCharacteristicDelegate* delegate) { |
| + auto char_iter = active_characteristic_notifications.find( |
| + characteristic_instance_id.utf8()); |
| + |
| + if (char_iter == active_characteristic_notifications.end()) { |
| + return; |
| + } |
| + |
| + char_iter->second.erase(delegate); |
| + |
| + if (char_iter->second.size() == 0) { |
| + active_characteristic_notifications.erase(char_iter); |
| + } |
| +} |
| + |
| void BluetoothDispatcher::OnRequestDeviceSuccess( |
| int thread_id, |
| int request_id, |
| @@ -386,4 +547,52 @@ void BluetoothDispatcher::OnWriteValueError(int thread_id, |
| pending_write_value_requests_.Remove(request_id); |
| } |
| +void BluetoothDispatcher::OnStartNotificationsSuccess(int thread_id, |
| + int request_id) { |
| + DCHECK(pending_start_notifications_requests_.Lookup(request_id)) |
| + << request_id; |
| + |
| + BluetoothNotificationsRequest* request = |
| + pending_start_notifications_requests_.Lookup(request_id); |
| + |
| + // The object requesting the notification could have been destroyed |
| + // while waiting for the subscription. characteristicDelegateRemoved |
| + // nulls the delegate when the delegate gets destroyed. |
| + if (request->delegate != nullptr) { |
|
ortuno
2015/09/16 16:30:08
Argh. This doesn't work. If the delegate gets dest
|
| + AddToActiveNotificationsMap(request->characteristic_instance_id, |
| + request->delegate); |
| + } |
| + request->callbacks->onSuccess(); |
| + |
| + pending_start_notifications_requests_.Remove(request_id); |
| +} |
| + |
| +void BluetoothDispatcher::OnStartNotificationsError(int thread_id, |
| + int request_id, |
| + WebBluetoothError error) { |
| + DCHECK(pending_start_notifications_requests_.Lookup(request_id)) |
| + << request_id; |
| + |
| + pending_start_notifications_requests_.Lookup(request_id) |
| + ->callbacks->onError(error); |
| + |
| + pending_start_notifications_requests_.Remove(request_id); |
| +} |
| + |
| +void BluetoothDispatcher::OnStopNotificationsSuccess(int thread_id, |
| + int request_id) { |
| + DCHECK(pending_stop_notifications_requests_.Lookup(request_id)) << request_id; |
| + |
| + BluetoothNotificationsRequest* request = |
| + pending_stop_notifications_requests_.Lookup(request_id); |
| + |
| + RemoveFromActiveNotificationsMap(request->characteristic_instance_id, |
| + request->delegate); |
| + |
| + pending_stop_notifications_requests_.Lookup(request_id) |
| + ->callbacks->onSuccess(); |
| + |
| + pending_stop_notifications_requests_.Remove(request_id); |
| +} |
| + |
| } // namespace content |