summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrkc <rkc@chromium.org>2014-10-07 14:27:19 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-07 21:27:34 +0000
commita3e8914682cb7e046b5a76e93c053f070ea25a0b (patch)
treef86a43abc6257b908ffbcbee14b42f43f4d34a11
parent5fb1e3aedf28059eb8bb51aa1b530f24be2f18ef (diff)
downloadchromium_src-a3e8914682cb7e046b5a76e93c053f070ea25a0b.zip
chromium_src-a3e8914682cb7e046b5a76e93c053f070ea25a0b.tar.gz
chromium_src-a3e8914682cb7e046b5a76e93c053f070ea25a0b.tar.bz2
Prototype for copresenceSockets.
This is the prototype implementation of the chrome.copresenceSocket API. This CL adds the API and the copresence_sockets component (which is a currently a thin wrapper around the bluetooth APIs). Only the receive parts of the code have been implemented with this CL. Reviews requested, rockot@ - Extension parts armansito@ - BT parts caitkp@ - Owners review for components BUG=418615 Review URL: https://codereview.chromium.org/610633002 Cr-Commit-Position: refs/heads/master@{#298577}
-rw-r--r--chrome/common/extensions/docs/templates/public/apps/copresenceSocket.html1
-rw-r--r--components/BUILD.gn6
-rw-r--r--components/OWNERS2
-rw-r--r--components/components.gyp1
-rw-r--r--components/copresence_sockets.gypi28
-rw-r--r--components/copresence_sockets/BUILD.gn19
-rw-r--r--components/copresence_sockets/DEPS5
-rw-r--r--components/copresence_sockets/OWNERS1
-rw-r--r--components/copresence_sockets/copresence_peer.cc157
-rw-r--r--components/copresence_sockets/public/copresence_peer.h81
-rw-r--r--components/copresence_sockets/public/copresence_socket.h44
-rw-r--r--components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.cc74
-rw-r--r--components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h53
-rw-r--r--extensions/browser/BUILD.gn3
-rw-r--r--extensions/browser/api/copresence_socket/DEPS3
-rw-r--r--extensions/browser/api/copresence_socket/OWNERS1
-rw-r--r--extensions/browser/api/copresence_socket/copresence_socket_api.cc222
-rw-r--r--extensions/browser/api/copresence_socket/copresence_socket_api.h120
-rw-r--r--extensions/browser/extension_function_histogram_value.h4
-rw-r--r--extensions/common/api/_api_features.json5
-rw-r--r--extensions/common/api/copresence_socket.idl135
-rw-r--r--extensions/common/api/schemas.gypi1
-rw-r--r--extensions/extensions.gyp3
-rw-r--r--tools/metrics/histograms/histograms.xml4
24 files changed, 972 insertions, 1 deletions
diff --git a/chrome/common/extensions/docs/templates/public/apps/copresenceSocket.html b/chrome/common/extensions/docs/templates/public/apps/copresenceSocket.html
new file mode 100644
index 0000000..62ffccc
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/copresenceSocket.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_api api:apis.apps.copresence_socket/}}
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 2eed3b7..90b52a1 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -27,6 +27,7 @@ group("all_components") {
"//components/component_updater",
"//components/content_settings/core/browser",
"//components/content_settings/core/common",
+ "//components/copresence_sockets",
"//components/crash/app",
"//components/crash/browser",
"//components/crx_file",
@@ -114,7 +115,10 @@ group("all_components") {
deps -= [ "//components/pairing" ]
}
if (is_ios) {
- deps -= [ "//components/keyed_service/content" ]
+ deps -= [
+ "//components/keyed_service/content",
+ "//components/copresence_sockets",
+ ]
}
if (!enable_plugins) {
diff --git a/components/OWNERS b/components/OWNERS
index aa88043..a1c635a 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -20,6 +20,8 @@ per-file copresence.gypi=ckehoe@chromium.org
per-file copresence.gypi=xiyuan@chromium.org
per-file copresence.gypi=derat@chromium.org
+per-file copresence_sockets.gypi=rkc@chromium.org
+
per-file crash.gypi=jochen@chromium.org
per-file crash.gypi=rsesek@chromium.org
per-file crash.gypi=thestig@chromium.org
diff --git a/components/components.gyp b/components/components.gyp
index b9af219..5778920 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -62,6 +62,7 @@
['OS != "ios"', {
'includes': [
'cdm.gypi',
+ 'copresence_sockets.gypi',
'navigation_interception.gypi',
'plugins.gypi',
'power.gypi',
diff --git a/components/copresence_sockets.gypi b/components/copresence_sockets.gypi
new file mode 100644
index 0000000..60cb957
--- /dev/null
+++ b/components/copresence_sockets.gypi
@@ -0,0 +1,28 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'copresence_sockets',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../device/bluetooth/bluetooth.gyp:device_bluetooth',
+ '../net/net.gyp:net',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ # GN version: //components/copresence_sockets
+ 'copresence_sockets/copresence_peer.cc',
+ 'copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.cc',
+ 'copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h',
+ 'copresence_sockets/public/copresence_peer.h',
+ 'copresence_sockets/public/copresence_socket.h',
+ ],
+ },
+ ],
+}
diff --git a/components/copresence_sockets/BUILD.gn b/components/copresence_sockets/BUILD.gn
new file mode 100644
index 0000000..f48f601
--- /dev/null
+++ b/components/copresence_sockets/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("copresence_sockets") {
+ sources = [
+ "copresence_peer.cc",
+ "transports/bluetooth/copresence_socket_bluetooth.cc",
+ "transports/bluetooth/copresence_socket_bluetooth.h",
+ "public/copresence_peer.h",
+ "public/copresence_socket.h",
+ ]
+
+ deps = [
+ "//base",
+ "//device/bluetooth",
+ "//net",
+ ]
+}
diff --git a/components/copresence_sockets/DEPS b/components/copresence_sockets/DEPS
new file mode 100644
index 0000000..338b701
--- /dev/null
+++ b/components/copresence_sockets/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+base",
+ "+device/bluetooth",
+ "+net",
+]
diff --git a/components/copresence_sockets/OWNERS b/components/copresence_sockets/OWNERS
new file mode 100644
index 0000000..6a2cb03
--- /dev/null
+++ b/components/copresence_sockets/OWNERS
@@ -0,0 +1 @@
+rkc@chromium.org
diff --git a/components/copresence_sockets/copresence_peer.cc b/components/copresence_sockets/copresence_peer.cc
new file mode 100644
index 0000000..af897df
--- /dev/null
+++ b/components/copresence_sockets/copresence_peer.cc
@@ -0,0 +1,157 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/copresence_sockets/public/copresence_peer.h"
+
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_socket.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace {
+
+const char kAdapterError[] = "NOADAPTER";
+
+device::BluetoothUUID GenerateRandomUuid() {
+ // Random hex string of the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+ return device::BluetoothUUID(base::StringPrintf(
+ "%08" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%012" PRIx64,
+ base::RandGenerator(UINT32_MAX),
+ base::RandGenerator(UINT16_MAX),
+ base::RandGenerator(UINT16_MAX),
+ base::RandGenerator(UINT16_MAX),
+ base::RandGenerator(static_cast<uint64>(UINT16_MAX) + UINT32_MAX)));
+}
+
+// This class will confirm pairing for a device that is expecting a pairing
+// confirmation.
+class DefaultApprovalDelegate
+ : public device::BluetoothDevice::PairingDelegate {
+ public:
+ DefaultApprovalDelegate() {}
+ virtual ~DefaultApprovalDelegate() {}
+
+ // device::BluetoothDevice::PairingDelegate overrides:
+ virtual void RequestPinCode(device::BluetoothDevice* device) override {}
+ virtual void RequestPasskey(device::BluetoothDevice* device) override {}
+ virtual void DisplayPinCode(device::BluetoothDevice* device,
+ const std::string& pincode) override {}
+ virtual void DisplayPasskey(device::BluetoothDevice* device,
+ uint32 passkey) override {}
+ virtual void KeysEntered(device::BluetoothDevice* device,
+ uint32 entered) override {}
+ virtual void ConfirmPasskey(device::BluetoothDevice* device,
+ uint32 passkey) override {}
+ virtual void AuthorizePairing(device::BluetoothDevice* device) override {
+ if (device->ExpectingConfirmation())
+ device->ConfirmPairing();
+ }
+};
+
+} // namespace
+
+namespace copresence_sockets {
+
+CopresencePeer::CopresencePeer(const CreatePeerCallback& create_callback,
+ const AcceptCallback& accept_callback)
+ : create_callback_(create_callback),
+ accept_callback_(accept_callback),
+ delegate_(nullptr),
+ weak_ptr_factory_(this) {
+ DCHECK(!create_callback.is_null());
+ DCHECK(!accept_callback.is_null());
+
+ if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
+ create_callback_.Run(std::string());
+ return;
+ }
+
+ device::BluetoothAdapterFactory::GetAdapter(base::Bind(
+ &CopresencePeer::OnGetAdapter, weak_ptr_factory_.GetWeakPtr()));
+}
+
+std::string CopresencePeer::GetLocatorData() {
+ if (!adapter_.get())
+ return kAdapterError;
+ // TODO(rkc): Fix the "1." once we have finalized the locator format with
+ // other platforms. http://crbug.com/418616
+ return "1." + adapter_->GetAddress() + "." + service_uuid_.value();
+}
+
+CopresencePeer::~CopresencePeer() {
+ server_socket_->Disconnect(base::Bind(&base::DoNothing));
+ server_socket_->Close();
+ if (delegate_)
+ adapter_->RemovePairingDelegate(delegate_.get());
+}
+
+// Private methods.
+
+void CopresencePeer::OnGetAdapter(
+ scoped_refptr<device::BluetoothAdapter> adapter) {
+ if (!adapter.get() || !adapter->IsPresent() || !adapter->IsPowered()) {
+ create_callback_.Run(std::string());
+ return;
+ }
+
+ adapter_ = adapter;
+ service_uuid_ = GenerateRandomUuid();
+
+ delegate_ = make_scoped_ptr(new DefaultApprovalDelegate());
+ VLOG(2) << "Creating service with UUID: " << service_uuid_.value();
+ adapter_->AddPairingDelegate(
+ delegate_.get(),
+ device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
+ adapter_->CreateRfcommService(
+ service_uuid_,
+ device::BluetoothAdapter::ServiceOptions(),
+ base::Bind(&CopresencePeer::OnCreateService,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CopresencePeer::OnCreateServiceError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CopresencePeer::OnCreateService(
+ scoped_refptr<device::BluetoothSocket> socket) {
+ if (!socket.get()) {
+ create_callback_.Run(std::string());
+ return;
+ }
+
+ server_socket_ = socket;
+ create_callback_.Run(GetLocatorData());
+ server_socket_->Accept(
+ base::Bind(&CopresencePeer::OnAccept, weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CopresencePeer::OnAcceptError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CopresencePeer::OnCreateServiceError(const std::string& message) {
+ LOG(WARNING) << "Couldn't create Bluetooth service: " << message;
+ create_callback_.Run(std::string());
+}
+
+void CopresencePeer::OnAccept(const device::BluetoothDevice* device,
+ scoped_refptr<device::BluetoothSocket> socket) {
+ if (!socket.get())
+ return;
+ accept_callback_.Run(make_scoped_ptr(new CopresenceSocketBluetooth(socket)));
+}
+
+void CopresencePeer::OnAcceptError(const std::string& message) {
+ LOG(WARNING) << "Couldn't accept Bluetooth connection: " << message;
+}
+
+} // namespace copresence_sockets
diff --git a/components/copresence_sockets/public/copresence_peer.h b/components/copresence_sockets/public/copresence_peer.h
new file mode 100644
index 0000000..6c8d09b
--- /dev/null
+++ b/components/copresence_sockets/public/copresence_peer.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_PEER_H_
+#define COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_PEER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace device {
+class BluetoothAdapter;
+class BluetoothDevice;
+class BluetoothSocket;
+}
+
+namespace copresence_sockets {
+
+class CopresenceSocket;
+
+// A CopresencePeer is an object that can be connected to. Creating a peer
+// will create a server that will listen on a medium (currently only Bluetooth)
+// and accept connections.
+class CopresencePeer {
+ public:
+ // Callback with the locator data for the created peer. On a failed create,
+ // the locator string will be empty.
+ typedef base::Callback<void(const std::string&)> CreatePeerCallback;
+
+ // Callback that accepts connections. The callback takes ownership of the
+ // Copresence socket passed in the parameter.
+ typedef base::Callback<void(scoped_ptr<CopresenceSocket> socket)>
+ AcceptCallback;
+
+ // Create a CopresencePeer and start listening for connections. Once the peer
+ // object is created, the locator data for the object is returned via
+ // create_callback. This locator data can be used to connect to this peer by
+ // remote CopresenceSockets. Any connections accepted by this peer are
+ // delivered as CopresenceSocket objects to accept_callback.
+ CopresencePeer(const CreatePeerCallback& create_callback,
+ const AcceptCallback& accept_callback);
+
+ virtual ~CopresencePeer();
+
+ // This will return a string containing the data needed for a remote
+ // CopresenceSocket to connect to this peer.
+ std::string GetLocatorData();
+
+ private:
+ void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+ void OnCreateService(scoped_refptr<device::BluetoothSocket> socket);
+ void OnCreateServiceError(const std::string& message);
+
+ void OnAccept(const device::BluetoothDevice* device,
+ scoped_refptr<device::BluetoothSocket> socket);
+ void OnAcceptError(const std::string& message);
+
+ scoped_refptr<device::BluetoothAdapter> adapter_;
+ scoped_refptr<device::BluetoothSocket> server_socket_;
+ device::BluetoothUUID service_uuid_;
+
+ CreatePeerCallback create_callback_;
+ AcceptCallback accept_callback_;
+
+ scoped_ptr<device::BluetoothDevice::PairingDelegate> delegate_;
+
+ base::WeakPtrFactory<CopresencePeer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopresencePeer);
+};
+
+} // namespace copresence_sockets
+
+#endif // COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_PEER_H_
diff --git a/components/copresence_sockets/public/copresence_socket.h b/components/copresence_sockets/public/copresence_socket.h
new file mode 100644
index 0000000..c970732
--- /dev/null
+++ b/components/copresence_sockets/public/copresence_socket.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_SOCKET_H_
+#define COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_SOCKET_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace copresence_sockets {
+
+// A CopresenceSocket is an object that is used to send receive data to and
+// from CopresencePeers.
+// TODO(rkc): Add the ability to connect to a remote CopresencePeer.
+class CopresenceSocket {
+ public:
+ typedef base::Callback<void(const scoped_refptr<net::IOBuffer>& buffer,
+ int buffer_size)> ReceiveCallback;
+
+ CopresenceSocket() {}
+ virtual ~CopresenceSocket() {}
+
+ // Send data on this socket. If unable to send the data, return false. This
+ // operation only guarantees that if the return value is a success, the send
+ // was started. It does not make any guarantees about the completion of the
+ // operation.
+ // TODO(rkc): Expand the bool into more a more detailed failures enum.
+ virtual bool Send(const scoped_refptr<net::IOBuffer>& buffer,
+ int buffer_size) = 0;
+ virtual void Receive(const ReceiveCallback& callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CopresenceSocket);
+};
+
+} // namespace copresence_sockets
+
+#endif // COMPONENTS_COPRESENCE_SOCKETS_COPRESENCE_SOCKET_H_
diff --git a/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.cc b/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.cc
new file mode 100644
index 0000000..5887ef5
--- /dev/null
+++ b/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.cc
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h"
+
+#include "base/bind.h"
+#include "base/strings/string_piece.h"
+#include "device/bluetooth/bluetooth_socket.h"
+#include "net/base/io_buffer.h"
+
+namespace {
+
+// TODO(rkc): This number is totally arbitrary. Figure out what this should be.
+const int kMaxReceiveBytes = 4096;
+
+} // namespace
+
+namespace copresence_sockets {
+
+CopresenceSocketBluetooth::CopresenceSocketBluetooth(
+ const scoped_refptr<device::BluetoothSocket>& socket)
+ : socket_(socket), weak_ptr_factory_(this) {
+}
+
+CopresenceSocketBluetooth::~CopresenceSocketBluetooth() {
+}
+
+bool CopresenceSocketBluetooth::Send(const scoped_refptr<net::IOBuffer>& buffer,
+ int buffer_size) {
+ socket_->Send(buffer,
+ buffer_size,
+ base::Bind(&CopresenceSocketBluetooth::OnSendComplete,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CopresenceSocketBluetooth::OnSendError,
+ weak_ptr_factory_.GetWeakPtr()));
+ return true;
+}
+
+void CopresenceSocketBluetooth::Receive(const ReceiveCallback& callback) {
+ receive_callback_ = callback;
+ socket_->Receive(kMaxReceiveBytes,
+ base::Bind(&CopresenceSocketBluetooth::OnReceive,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CopresenceSocketBluetooth::OnReceiveError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CopresenceSocketBluetooth::OnSendComplete(int status) {
+}
+
+void CopresenceSocketBluetooth::OnSendError(const std::string& message) {
+ LOG(ERROR) << "Bluetooth send error: " << message;
+}
+
+void CopresenceSocketBluetooth::OnReceive(
+ int size,
+ scoped_refptr<net::IOBuffer> io_buffer) {
+ // Dispatch the data to the callback and go back to listening for more data.
+ receive_callback_.Run(io_buffer, size);
+ socket_->Receive(kMaxReceiveBytes,
+ base::Bind(&CopresenceSocketBluetooth::OnReceive,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&CopresenceSocketBluetooth::OnReceiveError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CopresenceSocketBluetooth::OnReceiveError(
+ device::BluetoothSocket::ErrorReason /* reason */,
+ const std::string& message) {
+ LOG(ERROR) << "Bluetooth receive error: " << message;
+}
+
+} // namespace copresence_sockets
diff --git a/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h b/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h
new file mode 100644
index 0000000..6544d35
--- /dev/null
+++ b/components/copresence_sockets/transports/bluetooth/copresence_socket_bluetooth.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
+#define COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/copresence_sockets/public/copresence_socket.h"
+#include "device/bluetooth/bluetooth_socket.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace copresence_sockets {
+
+// A CopresenceSocketBluetooth is the Bluetooth implementation of a
+// CopresenceSocket. This is currently a thin wrapper around BluetoothSocket.
+class CopresenceSocketBluetooth : public CopresenceSocket {
+ public:
+ explicit CopresenceSocketBluetooth(
+ const scoped_refptr<device::BluetoothSocket>& socket);
+ virtual ~CopresenceSocketBluetooth();
+
+ // CopresenceSocket overrides:
+ virtual bool Send(const scoped_refptr<net::IOBuffer>& buffer,
+ int buffer_size) override;
+ virtual void Receive(const ReceiveCallback& callback) override;
+
+ private:
+ void OnSendComplete(int status);
+ void OnSendError(const std::string& message);
+
+ void OnReceive(int size, scoped_refptr<net::IOBuffer> io_buffer);
+ void OnReceiveError(device::BluetoothSocket::ErrorReason reason,
+ const std::string& message);
+
+ scoped_refptr<device::BluetoothSocket> socket_;
+ ReceiveCallback receive_callback_;
+
+ base::WeakPtrFactory<CopresenceSocketBluetooth> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopresenceSocketBluetooth);
+};
+
+} // namespace copresence_sockets
+
+#endif // COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index a274a52..9ea3e4f 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -11,6 +11,7 @@ source_set("browser") {
]
deps = [
+ "//components/copresence_sockets",
"//components/keyed_service/content",
"//components/keyed_service/core",
"//components/pref_registry",
@@ -97,6 +98,8 @@ source_set("browser") {
"api/cast_channel/logger.h",
"api/cast_channel/logger_util.cc",
"api/cast_channel/logger_util.h",
+ "api/copresence_socket/copresence_socket_api.cc",
+ "api/copresence_socket/copresence_socket_api.h",
"api/declarative/declarative_api.cc",
"api/declarative/declarative_api.h",
"api/declarative/declarative_rule.h",
diff --git a/extensions/browser/api/copresence_socket/DEPS b/extensions/browser/api/copresence_socket/DEPS
new file mode 100644
index 0000000..bf5b843
--- /dev/null
+++ b/extensions/browser/api/copresence_socket/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/copresence_sockets",
+]
diff --git a/extensions/browser/api/copresence_socket/OWNERS b/extensions/browser/api/copresence_socket/OWNERS
new file mode 100644
index 0000000..6a2cb03
--- /dev/null
+++ b/extensions/browser/api/copresence_socket/OWNERS
@@ -0,0 +1 @@
+rkc@chromium.org
diff --git a/extensions/browser/api/copresence_socket/copresence_socket_api.cc b/extensions/browser/api/copresence_socket/copresence_socket_api.cc
new file mode 100644
index 0000000..0704297
--- /dev/null
+++ b/extensions/browser/api/copresence_socket/copresence_socket_api.cc
@@ -0,0 +1,222 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/copresence_socket/copresence_socket_api.h"
+
+#include "base/lazy_instance.h"
+#include "components/copresence_sockets/public/copresence_peer.h"
+#include "components/copresence_sockets/public/copresence_socket.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/common/api/copresence_socket.h"
+#include "net/base/io_buffer.h"
+
+using copresence_sockets::CopresencePeer;
+using copresence_sockets::CopresenceSocket;
+
+namespace extensions {
+
+class CopresencePeerResource : public ApiResource {
+ public:
+ // Takes ownership of peer.
+ CopresencePeerResource(const std::string& owner_extension_id,
+ scoped_ptr<copresence_sockets::CopresencePeer> peer)
+ : ApiResource(owner_extension_id), peer_(peer.Pass()) {}
+
+ virtual ~CopresencePeerResource() {}
+
+ copresence_sockets::CopresencePeer* peer() { return peer_.get(); }
+
+ static const content::BrowserThread::ID kThreadId =
+ content::BrowserThread::UI;
+
+ private:
+ scoped_ptr<copresence_sockets::CopresencePeer> peer_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopresencePeerResource);
+};
+
+class CopresenceSocketResource : public ApiResource {
+ public:
+ // Takes ownership of socket.
+ CopresenceSocketResource(
+ const std::string& owner_extension_id,
+ scoped_ptr<copresence_sockets::CopresenceSocket> socket)
+ : ApiResource(owner_extension_id), socket_(socket.Pass()) {}
+
+ virtual ~CopresenceSocketResource() {}
+
+ copresence_sockets::CopresenceSocket* socket() { return socket_.get(); }
+
+ static const content::BrowserThread::ID kThreadId =
+ content::BrowserThread::UI;
+
+ private:
+ scoped_ptr<copresence_sockets::CopresenceSocket> socket_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopresenceSocketResource);
+};
+
+CopresenceSocketFunction::CopresenceSocketFunction()
+ : peers_manager_(nullptr), sockets_manager_(nullptr) {
+}
+
+CopresenceSocketFunction::~CopresenceSocketFunction() {
+ delete peers_manager_;
+ delete sockets_manager_;
+}
+
+void CopresenceSocketFunction::Initialize() {
+ peers_manager_ =
+ new ApiResourceManager<CopresencePeerResource>(browser_context());
+ sockets_manager_ =
+ new ApiResourceManager<CopresenceSocketResource>(browser_context());
+}
+
+int CopresenceSocketFunction::AddPeer(CopresencePeerResource* peer) {
+ return peers_manager_->Add(peer);
+}
+
+int CopresenceSocketFunction::AddSocket(CopresenceSocketResource* socket) {
+ return sockets_manager_->Add(socket);
+}
+
+void CopresenceSocketFunction::ReplacePeer(const std::string& extension_id,
+ int peer_id,
+ CopresencePeerResource* peer) {
+ peers_manager_->Replace(extension_id, peer_id, peer);
+}
+
+CopresencePeerResource* CopresenceSocketFunction::GetPeer(int peer_id) {
+ return peers_manager_->Get(extension_id(), peer_id);
+}
+
+CopresenceSocketResource* CopresenceSocketFunction::GetSocket(int socket_id) {
+ return sockets_manager_->Get(extension_id(), socket_id);
+}
+
+void CopresenceSocketFunction::RemovePeer(int peer_id) {
+ peers_manager_->Remove(extension_id(), peer_id);
+}
+
+void CopresenceSocketFunction::RemoveSocket(int socket_id) {
+ sockets_manager_->Remove(extension_id(), socket_id);
+}
+
+void CopresenceSocketFunction::DispatchOnReceiveEvent(
+ int socket_id,
+ const scoped_refptr<net::IOBuffer>& buffer,
+ int size) {
+ core_api::copresence_socket::ReceiveInfo info;
+ info.socket_id = socket_id;
+ info.data = std::string(buffer->data(), size);
+ // Send the data to the client app.
+ scoped_ptr<Event> event(
+ new Event(core_api::copresence_socket::OnReceive::kEventName,
+ core_api::copresence_socket::OnReceive::Create(info),
+ browser_context()));
+ EventRouter::Get(browser_context())
+ ->DispatchEventToExtension(extension_id(), event.Pass());
+ VLOG(2) << "Dispatched OnReceive event: socketId = " << socket_id
+ << " and data = " << info.data;
+}
+
+void CopresenceSocketFunction::DispatchOnConnectedEvent(
+ int peer_id,
+ scoped_ptr<copresence_sockets::CopresenceSocket> socket) {
+ int socket_id =
+ AddSocket(new CopresenceSocketResource(extension_id(), socket.Pass()));
+
+ // Send the messages to the client app.
+ scoped_ptr<Event> event(new Event(
+ core_api::copresence_socket::OnConnected::kEventName,
+ core_api::copresence_socket::OnConnected::Create(peer_id, socket_id),
+ browser_context()));
+ EventRouter::Get(browser_context())
+ ->DispatchEventToExtension(extension_id(), event.Pass());
+ VLOG(2) << "Dispatched OnConnected event: peerId = " << peer_id
+ << " and socketId = " << socket_id;
+
+ socket->Receive(base::Bind(base::Bind(
+ &CopresenceSocketFunction::DispatchOnReceiveEvent, this, peer_id)));
+}
+
+ExtensionFunction::ResponseAction CopresenceSocketFunction::Run() {
+ Initialize();
+ return Execute();
+}
+
+// CopresenceSocketCreatePeerFunction implementation:
+ExtensionFunction::ResponseAction
+CopresenceSocketCreatePeerFunction::Execute() {
+ // Add an empty peer to create a placeholder peer_id. We will need to bind
+ // this id to the OnConnected event dispatcher, so we need it before we
+ // create the actual peer. Once we have the peer created, we'll replace the
+ // placeholder with the actual peer object.
+ int peer_id = AddPeer(new CopresencePeerResource(extension_id(), nullptr));
+
+ scoped_ptr<CopresencePeer> peer = make_scoped_ptr(new CopresencePeer(
+ base::Bind(&CopresenceSocketCreatePeerFunction::OnCreated, this, peer_id),
+ base::Bind(
+ &CopresenceSocketFunction::DispatchOnConnectedEvent, this, peer_id)));
+
+ ReplacePeer(extension_id(),
+ peer_id,
+ new CopresencePeerResource(extension_id(), peer.Pass()));
+
+ return RespondLater();
+}
+
+void CopresenceSocketCreatePeerFunction::OnCreated(int peer_id,
+ const std::string& locator) {
+ core_api::copresence_socket::PeerInfo peer_info;
+ peer_info.peer_id = peer_id;
+ peer_info.locator = locator;
+ Respond(ArgumentList(
+ core_api::copresence_socket::CreatePeer::Results::Create(peer_info)));
+}
+
+// CopresenceSocketDestroyPeerFunction implementation:
+ExtensionFunction::ResponseAction
+CopresenceSocketDestroyPeerFunction::Execute() {
+ scoped_ptr<core_api::copresence_socket::DestroyPeer::Params> params(
+ core_api::copresence_socket::DestroyPeer::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ RemovePeer(params->peer_id);
+ return RespondNow(NoArguments());
+}
+
+// CopresenceSocketSendFunction implementation:
+ExtensionFunction::ResponseAction CopresenceSocketSendFunction::Execute() {
+ scoped_ptr<core_api::copresence_socket::Send::Params> params(
+ core_api::copresence_socket::Send::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ CopresenceSocketResource* socket = GetSocket(params->socket_id);
+ if (!socket) {
+ VLOG(1) << "Socket not found. ID = " << params->socket_id;
+ return RespondNow(
+ ArgumentList(core_api::copresence_socket::Send::Results::Create(
+ core_api::copresence_socket::SOCKET_STATUS_INVALID_SOCKET)));
+ }
+
+ socket->socket()->Send(new net::StringIOBuffer(params->data),
+ params->data.size());
+ return RespondNow(
+ ArgumentList(core_api::copresence_socket::Send::Results::Create(
+ core_api::copresence_socket::SOCKET_STATUS_NO_ERROR)));
+}
+
+// CopresenceSocketDisconnectFunction implementation:
+ExtensionFunction::ResponseAction
+CopresenceSocketDisconnectFunction::Execute() {
+ scoped_ptr<core_api::copresence_socket::Disconnect::Params> params(
+ core_api::copresence_socket::Disconnect::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ return RespondLater();
+}
+
+} // namespace extensions
diff --git a/extensions/browser/api/copresence_socket/copresence_socket_api.h b/extensions/browser/api/copresence_socket/copresence_socket_api.h
new file mode 100644
index 0000000..97f6782
--- /dev/null
+++ b/extensions/browser/api/copresence_socket/copresence_socket_api.h
@@ -0,0 +1,120 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_COPRESENCE_SOCKET_COPRESENCE_SOCKET_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_COPRESENCE_SOCKET_COPRESENCE_SOCKET_API_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "extensions/browser/api/api_resource.h"
+#include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_histogram_value.h"
+
+namespace copresence_sockets {
+class CopresenceSocket;
+}
+
+namespace net {
+class IOBuffer;
+}
+
+namespace extensions {
+
+class CopresencePeerResource;
+class CopresenceSocketResource;
+
+class CopresenceSocketFunction : public UIThreadExtensionFunction {
+ public:
+ CopresenceSocketFunction();
+
+ void DispatchOnConnectedEvent(
+ int peer_id,
+ scoped_ptr<copresence_sockets::CopresenceSocket> socket);
+ void DispatchOnReceiveEvent(int socket_id,
+ const scoped_refptr<net::IOBuffer>& buffer,
+ int size);
+
+ protected:
+ // ExtensionFunction overrides:
+ virtual ExtensionFunction::ResponseAction Run() override;
+
+ // Override this and do actual work here.
+ virtual ExtensionFunction::ResponseAction Execute() = 0;
+
+ // Takes ownership of peer.
+ int AddPeer(CopresencePeerResource* peer);
+ // Takes ownership of socket.
+ int AddSocket(CopresenceSocketResource* socket);
+
+ // Takes ownership of peer.
+ void ReplacePeer(const std::string& extension_id,
+ int peer_id,
+ CopresencePeerResource* peer);
+
+ CopresencePeerResource* GetPeer(int peer_id);
+ CopresenceSocketResource* GetSocket(int socket_id);
+
+ void RemovePeer(int peer_id);
+ void RemoveSocket(int socket_id);
+
+ virtual ~CopresenceSocketFunction();
+
+ private:
+ void Initialize();
+
+ ApiResourceManager<CopresencePeerResource>* peers_manager_;
+ ApiResourceManager<CopresenceSocketResource>* sockets_manager_;
+};
+
+class CopresenceSocketCreatePeerFunction : public CopresenceSocketFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("copresenceSocket.createPeer",
+ COPRESENCESOCKET_CREATEPEER);
+
+ protected:
+ virtual ~CopresenceSocketCreatePeerFunction() {}
+ virtual ExtensionFunction::ResponseAction Execute() override;
+
+ private:
+ void OnCreated(int peer_id, const std::string& locator);
+};
+
+class CopresenceSocketDestroyPeerFunction : public CopresenceSocketFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("copresenceSocket.destroyPeer",
+ COPRESENCESOCKET_DESTROYPEER);
+
+ protected:
+ virtual ~CopresenceSocketDestroyPeerFunction() {}
+ virtual ExtensionFunction::ResponseAction Execute() override;
+};
+
+class CopresenceSocketSendFunction : public CopresenceSocketFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("copresenceSocket.send", COPRESENCESOCKET_SEND);
+
+ protected:
+ virtual ~CopresenceSocketSendFunction() {}
+ virtual ExtensionFunction::ResponseAction Execute() override;
+};
+
+class CopresenceSocketDisconnectFunction : public CopresenceSocketFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("copresenceSocket.disconnect",
+ COPRESENCESOCKET_DISCONNECT);
+
+ protected:
+ virtual ~CopresenceSocketDisconnectFunction() {}
+ virtual ExtensionFunction::ResponseAction Execute() override;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_COPRESENCE_SOCKET_COPRESENCE_SOCKET_API_H_
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index a524997..e66feda 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -959,6 +959,10 @@ enum HistogramValue {
HOTWORDPRIVATE_SETHOTWORDALWAYSONSEARCHENABLED,
WEBVIEWINTERNAL_LOADDATAWITHBASEURL,
GUESTVIEWINTERNAL_DESTROYGUEST,
+ COPRESENCESOCKET_CREATEPEER,
+ COPRESENCESOCKET_DESTROYPEER,
+ COPRESENCESOCKET_SEND,
+ COPRESENCESOCKET_DISCONNECT,
// Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms.xml.
ENUM_BOUNDARY
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 343000d..537608a 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -89,6 +89,11 @@
"dependencies": ["permission:declarativeWebRequest"],
"contexts": ["blessed_extension"]
},
+ "copresenceSocket": {
+ "channel" : "dev",
+ "dependencies": ["permission:copresence"],
+ "contexts": ["blessed_extension"]
+ },
"dns": {
"dependencies": ["permission:dns"],
"contexts": ["blessed_extension"]
diff --git a/extensions/common/api/copresence_socket.idl b/extensions/common/api/copresence_socket.idl
new file mode 100644
index 0000000..c26d854
--- /dev/null
+++ b/extensions/common/api/copresence_socket.idl
@@ -0,0 +1,135 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use the <code>chrome.copresenceSocket</code> API to create persistent
+// sockets to send data to and receive from data nearby devices.
+namespace copresenceSocket {
+
+ enum TransportType {
+ // Only use the Internet as the transport.
+ online,
+ // Only use an offline transport.
+ offline
+ };
+
+ // The properties for the peer created by the $ref:createPeer function.
+ [noinline_doc] dictionary ConnectionProperties {
+ // Flag indicating whether the socket should use a low latency transport
+ // (if available).
+ boolean? lowLatency;
+
+ // Flag to force the socket to use a particular type of transport.
+ TransportType? type;
+ };
+
+
+ // Result of the <code>createPeer</code> call.
+ [noinline_doc] dictionary PeerInfo {
+ // The ID of the newly created peer.
+ long peerId;
+
+ // An opaque string containing the locator data for this peer. This
+ // locator is needed to connect to this socket.
+ DOMString locator;
+ };
+
+ // Data from an <code>onReceive</code> event.
+ [noinline_doc] dictionary ReceiveInfo {
+ // The socket identifier.
+ long socketId;
+
+ // The data received.
+ ArrayBuffer data;
+ };
+
+ // Status of a socket operation.
+ enum SocketStatus {
+ // There was no error in the previous operation.
+ no_error,
+
+ // The socket was disconnected.
+ disconnected,
+
+ // The socket id provided is invalid.
+ invalid_socket,
+
+ // There was a failure during connection.
+ connect_failure,
+
+ // There was an error while trying to send data.
+ send_failure,
+
+ // There was an error while trying to receive data.
+ receive_failure
+ };
+
+ // Callback from the <code>createPeer</code> method.
+ // |peerInfo| : The result of the socket creation.
+ callback CreateCallback = void (PeerInfo peerInfo);
+
+ // Callback from the <code>connectToPeer</code> method.
+ // |socketId| : ID of the socket created between the local and remote peers.
+ // This ID is only valid if status == no_error.
+ // |status| : Status of the connect operation.
+ callback ConnectCallback = void (long socketId, SocketStatus status);
+
+ // Callback from the <code>send</code> method.
+ // |status| : Status of the send operation.
+ callback SendCallback = void (SocketStatus status);
+
+ // Callback from the <code>disconnect</code> method.
+ callback DisconnectCallback = void ();
+
+ // These functions all report failures via chrome.runtime.lastError.
+ interface Functions {
+ // Peer functions.
+
+ // Creates a peer that can be connected to by a nearby devices.
+ // |callback| : Called when the peer has been created.
+ static void createPeer(CreateCallback callback);
+
+ // Destroys the peer. This will close any connections to this peer
+ // from remote hosts and will prevent any further connections to it.
+ // |peerId|: Peer ID returned by <code>createPeer</code>.
+ static void destroyPeer(long peerId);
+
+ // Socket functions.
+
+ // Sends data on the given Copresence socket.
+ // |socketId| : The socket identifier.
+ // |data| : The data to send.
+ // |callback| : Called when the <code>send</code> operation completes.
+ static void send(long socketId, ArrayBuffer data,
+ optional SendCallback callback);
+
+ // Disconnects and destroys a socket. The socket id is no longer valid and any
+ // pending send callbacks are cancelled as soon at the function is called.
+ // However, the connection is guaranteed to be closed only when the callback
+ // is invoked.
+ // |socketId| : The socket identifier.
+ // |callback| : Called when the <code>disconnect</code> operation completes.
+ static void disconnect(long socketId,
+ optional DisconnectCallback callback);
+ };
+
+ interface Events {
+ // Event raised when data has been received for a given socket.
+ // |info| : The event data.
+ static void onReceive(ReceiveInfo info);
+
+ // Event raised when a peer receives a new connection. A new socket is
+ // created and the id is passed to this event via socketId.
+ // |peerId| : ID of the peer that received this connection.
+ // |socketId| : ID of the new socket that was created which can be used to
+ // communicate on this connection.
+ static void onConnected(long peerId, long socketId);
+
+ // Event raised when there is a status update for a socket. This can be an
+ // error or disconnection. After event is raised, since there has either
+ // been an error or disconnection, no more <code>onReceive</code> events
+ // are raised for this socket and the socketId is invalidated.
+ // |status| : The status update for the socket.
+ static void onSocketStatusUpdated(long socketId, SocketStatus status);
+ };
+};
diff --git a/extensions/common/api/schemas.gypi b/extensions/common/api/schemas.gypi
index a7cc9e9..3ee747f 100644
--- a/extensions/common/api/schemas.gypi
+++ b/extensions/common/api/schemas.gypi
@@ -18,6 +18,7 @@
'bluetooth_private.json',
'bluetooth_socket.idl',
'cast_channel.idl',
+ 'copresence_socket.idl',
'dns.idl',
'events.json',
'extensions_manifest_types.json',
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index e657635..0a80101 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -287,6 +287,7 @@
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:base_prefs',
+ '../components/components.gyp:copresence_sockets',
'../components/components.gyp:keyed_service_content',
'../components/components.gyp:keyed_service_core',
'../components/components.gyp:pref_registry',
@@ -382,6 +383,8 @@
'browser/api/cast_channel/logger.h',
'browser/api/cast_channel/logger_util.cc',
'browser/api/cast_channel/logger_util.h',
+ 'browser/api/copresence_socket/copresence_socket_api.cc',
+ 'browser/api/copresence_socket/copresence_socket_api.h',
'browser/api/declarative/deduping_factory.h',
'browser/api/declarative/declarative_api.cc',
'browser/api/declarative/declarative_api.h',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1cd1f76..b40c638 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -42543,6 +42543,10 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="898" label="HOTWORDPRIVATE_SETHOTWORDALWAYSONSEARCHENABLED"/>
<int value="899" label="WEBVIEWINTERNAL_LOADDATAWITHBASEURL"/>
<int value="900" label="GUESTVIEWINTERNAL_DESTROYGUEST"/>
+ <int value="901" label="COPRESENCESOCKET_CREATEPEER"/>
+ <int value="902" label="COPRESENCESOCKET_DESTROYPEER"/>
+ <int value="903" label="COPRESENCESOCKET_SEND"/>
+ <int value="904" label="COPRESENCESOCKET_DISCONNECT"/>
</enum>
<enum name="ExtensionInstallCause" type="int">