Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / serial / serial_event_dispatcher.cc
blob930c1efe29446066ec68e84034ffaf19f6850615
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/serial/serial_event_dispatcher.h"
7 #include "base/lazy_instance.h"
8 #include "extensions/browser/api/serial/serial_connection.h"
9 #include "extensions/browser/event_router.h"
10 #include "extensions/browser/extensions_browser_client.h"
12 namespace extensions {
14 namespace core_api {
16 namespace {
18 bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
19 return error == serial::RECEIVE_ERROR_DEVICE_LOST ||
20 error == serial::RECEIVE_ERROR_SYSTEM_ERROR ||
21 error == serial::RECEIVE_ERROR_DISCONNECTED;
24 } // namespace
26 static base::LazyInstance<BrowserContextKeyedAPIFactory<SerialEventDispatcher> >
27 g_factory = LAZY_INSTANCE_INITIALIZER;
29 // static
30 BrowserContextKeyedAPIFactory<SerialEventDispatcher>*
31 SerialEventDispatcher::GetFactoryInstance() {
32 return g_factory.Pointer();
35 // static
36 SerialEventDispatcher* SerialEventDispatcher::Get(
37 content::BrowserContext* context) {
38 return BrowserContextKeyedAPIFactory<SerialEventDispatcher>::Get(context);
41 SerialEventDispatcher::SerialEventDispatcher(content::BrowserContext* context)
42 : thread_id_(SerialConnection::kThreadId), context_(context) {
43 ApiResourceManager<SerialConnection>* manager =
44 ApiResourceManager<SerialConnection>::Get(context_);
45 DCHECK(manager) << "No serial connection manager.";
46 connections_ = manager->data_;
49 SerialEventDispatcher::~SerialEventDispatcher() {
52 SerialEventDispatcher::ReceiveParams::ReceiveParams() {
55 SerialEventDispatcher::ReceiveParams::~ReceiveParams() {
58 void SerialEventDispatcher::PollConnection(const std::string& extension_id,
59 int connection_id) {
60 DCHECK_CURRENTLY_ON(thread_id_);
62 ReceiveParams params;
63 params.thread_id = thread_id_;
64 params.browser_context_id = context_;
65 params.extension_id = extension_id;
66 params.connections = connections_;
67 params.connection_id = connection_id;
69 StartReceive(params);
72 // static
73 void SerialEventDispatcher::StartReceive(const ReceiveParams& params) {
74 DCHECK_CURRENTLY_ON(params.thread_id);
76 SerialConnection* connection =
77 params.connections->Get(params.extension_id, params.connection_id);
78 if (!connection)
79 return;
80 DCHECK(params.extension_id == connection->owner_extension_id());
82 if (connection->paused())
83 return;
85 connection->Receive(base::Bind(&ReceiveCallback, params));
88 // static
89 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams& params,
90 const std::vector<char>& data,
91 serial::ReceiveError error) {
92 DCHECK_CURRENTLY_ON(params.thread_id);
94 // Note that an error (e.g. timeout) does not necessarily mean that no data
95 // was read, so we may fire an onReceive regardless of any error code.
96 if (data.size() > 0) {
97 serial::ReceiveInfo receive_info;
98 receive_info.connection_id = params.connection_id;
99 receive_info.data = data;
100 scoped_ptr<base::ListValue> args = serial::OnReceive::Create(receive_info);
101 scoped_ptr<extensions::Event> event(
102 new extensions::Event(serial::OnReceive::kEventName, args.Pass()));
103 PostEvent(params, event.Pass());
106 if (error != serial::RECEIVE_ERROR_NONE) {
107 serial::ReceiveErrorInfo error_info;
108 error_info.connection_id = params.connection_id;
109 error_info.error = error;
110 scoped_ptr<base::ListValue> args =
111 serial::OnReceiveError::Create(error_info);
112 scoped_ptr<extensions::Event> event(
113 new extensions::Event(serial::OnReceiveError::kEventName, args.Pass()));
114 PostEvent(params, event.Pass());
115 if (ShouldPauseOnReceiveError(error)) {
116 SerialConnection* connection =
117 params.connections->Get(params.extension_id, params.connection_id);
118 if (connection)
119 connection->set_paused(true);
123 // Queue up the next read operation.
124 BrowserThread::PostTask(
125 params.thread_id, FROM_HERE, base::Bind(&StartReceive, params));
128 // static
129 void SerialEventDispatcher::PostEvent(const ReceiveParams& params,
130 scoped_ptr<extensions::Event> event) {
131 DCHECK_CURRENTLY_ON(params.thread_id);
133 BrowserThread::PostTask(BrowserThread::UI,
134 FROM_HERE,
135 base::Bind(&DispatchEvent,
136 params.browser_context_id,
137 params.extension_id,
138 base::Passed(event.Pass())));
141 // static
142 void SerialEventDispatcher::DispatchEvent(void* browser_context_id,
143 const std::string& extension_id,
144 scoped_ptr<extensions::Event> event) {
145 DCHECK_CURRENTLY_ON(BrowserThread::UI);
147 content::BrowserContext* context =
148 reinterpret_cast<content::BrowserContext*>(browser_context_id);
149 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
150 return;
152 EventRouter* router = EventRouter::Get(context);
153 if (router)
154 router->DispatchEventToExtension(extension_id, event.Pass());
157 } // namespace core_api
159 } // namespace extensions