OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/sensor/Sensor.h" | 5 #include "modules/sensor/Sensor.h" |
6 | 6 |
7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
8 #include "core/dom/ExceptionCode.h" | 8 #include "core/dom/ExceptionCode.h" |
9 #include "core/dom/ExecutionContextTask.h" | 9 #include "device/generic_sensor/public/interfaces/sensor.mojom-blink.h" |
10 #include "core/events/Event.h" | 10 #include "modules/sensor/SensorErrorEvent.h" |
11 | 11 #include "modules/sensor/SensorPollingStrategy.h" |
| 12 #include "modules/sensor/SensorProviderProxy.h" |
12 #include "modules/sensor/SensorReading.h" | 13 #include "modules/sensor/SensorReading.h" |
| 14 #include "modules/sensor/SensorReadingEvent.h" |
| 15 |
| 16 using namespace device::mojom::blink; |
13 | 17 |
14 namespace blink { | 18 namespace blink { |
15 | 19 |
16 Sensor::~Sensor() | 20 Sensor::Sensor(ExecutionContext* executionContext, const SensorOptions& sensorOp
tions, device::mojom::blink::SensorType type) |
17 { | |
18 } | |
19 | |
20 Sensor::Sensor(ExecutionContext* executionContext, const SensorOptions& sensorOp
tions) | |
21 : ActiveScriptWrappable(this) | 21 : ActiveScriptWrappable(this) |
22 , ActiveDOMObject(executionContext) | 22 , ActiveDOMObject(executionContext) |
23 , PlatformEventController(toDocument(executionContext)->page()) | 23 , PageVisibilityObserver(toDocument(executionContext)->page()) |
24 , m_sensorState(SensorState::Idle) | |
25 , m_sensorReading(nullptr) | |
26 , m_sensorOptions(sensorOptions) | 24 , m_sensorOptions(sensorOptions) |
27 { | 25 , m_type(type) |
| 26 , m_state(Sensor::SensorState::IDLE) |
| 27 { |
| 28 DCHECK(executionContext->isDocument()); |
| 29 } |
| 30 |
| 31 void Sensor::dispose() |
| 32 { |
| 33 stopListening(); |
| 34 } |
| 35 |
| 36 void Sensor::start(ScriptState* scriptState, ExceptionState& exceptionState) |
| 37 { |
| 38 if (m_state != Sensor::SensorState::IDLE && m_state != Sensor::SensorState::
ERRORED) { |
| 39 exceptionState.throwDOMException(InvalidStateError, "Invalid State: Sens
orState is not idle or errored"); |
| 40 return; |
| 41 } |
| 42 |
| 43 initSensorProxyIfNeeded(); |
| 44 |
| 45 if (!m_sensorProxy) { |
| 46 exceptionState.throwDOMException(InvalidStateError, "The Sensor is no lo
nger associated to a frame."); |
| 47 return; |
| 48 } |
| 49 |
| 50 updateState(Sensor::SensorState::ACTIVATING); |
| 51 |
| 52 startListening(); |
| 53 } |
| 54 |
| 55 void Sensor::stop(ScriptState*, ExceptionState& exceptionState) |
| 56 { |
| 57 if (m_state == Sensor::SensorState::IDLE || m_state == Sensor::SensorState::
ERRORED) { |
| 58 exceptionState.throwDOMException(InvalidStateError, "Invalid State: Sens
orState is either idle or errored"); |
| 59 return; |
| 60 } |
| 61 |
| 62 if (!m_sensorProxy) { |
| 63 exceptionState.throwDOMException(InvalidStateError, "The Sensor is no lo
nger associated to a frame."); |
| 64 return; |
| 65 } |
| 66 |
| 67 stopListening(); |
| 68 } |
| 69 |
| 70 static String ToString(Sensor::SensorState state) |
| 71 { |
| 72 switch (state) { |
| 73 case Sensor::SensorState::IDLE: |
| 74 return "idle"; |
| 75 case Sensor::SensorState::ACTIVATING: |
| 76 return "activating"; |
| 77 case Sensor::SensorState::ACTIVE: |
| 78 return "active"; |
| 79 case Sensor::SensorState::ERRORED: |
| 80 return "errored"; |
| 81 default: |
| 82 NOTREACHED(); |
| 83 } |
| 84 return "idle"; |
28 } | 85 } |
29 | 86 |
30 // Getters | 87 // Getters |
31 String Sensor::state() const | 88 String Sensor::state() const |
32 { | 89 { |
33 // TODO(riju): Validate the transitions. | 90 return ToString(m_state); |
34 switch (m_sensorState) { | |
35 case SensorState::Idle: | |
36 return "idle"; | |
37 case SensorState::Activating: | |
38 return "activating"; | |
39 case SensorState::Active: | |
40 return "active"; | |
41 case SensorState::Errored: | |
42 return "errored"; | |
43 } | |
44 NOTREACHED(); | |
45 return "idle"; | |
46 } | 91 } |
47 | 92 |
48 SensorReading* Sensor::reading() const | 93 SensorReading* Sensor::reading() const |
49 { | 94 { |
50 return m_sensorReading.get(); | 95 return m_sensorReading.get(); |
51 } | 96 } |
52 | 97 |
53 void Sensor::start(ScriptState* scriptState, ExceptionState& exceptionState) | 98 DEFINE_TRACE(Sensor) |
54 { | 99 { |
55 | 100 visitor->trace(m_polling); |
56 if (m_sensorState != SensorState::Idle && m_sensorState != SensorState::Erro
red) { | 101 visitor->trace(m_sensorProxy); |
57 exceptionState.throwDOMException(InvalidStateError, "Invalid State: Sens
orState is not idle or errored"); | 102 visitor->trace(m_sensorReading); |
58 return; | 103 ActiveScriptWrappable::trace(visitor); |
59 } | 104 ActiveDOMObject::trace(visitor); |
60 | 105 PageVisibilityObserver::trace(visitor); |
61 updateState(SensorState::Activating); | 106 EventTargetWithInlineData::trace(visitor); |
62 | 107 } |
63 // TODO(riju) : Add Permissions stuff later. | 108 |
64 | 109 void Sensor::initSensorProxyIfNeeded() |
65 m_hasEventListener = true; | 110 { |
66 | 111 if (m_sensorProxy) |
67 // TODO(riju): verify the correct order of onstatechange(active) and the fir
st onchange(event). | 112 return; |
68 startUpdating(); | 113 |
69 } | 114 Document* document = toDocument(getExecutionContext()); |
70 | 115 if (!document->frame()) |
71 void Sensor::stop(ScriptState* scriptState, ExceptionState& exceptionState) | 116 return; |
72 { | 117 |
73 if (m_sensorState == SensorState::Idle || m_sensorState == SensorState::Erro
red) { | 118 m_sensorProxy = SensorProviderProxy::getOrCreateForFrame(document->frame())-
>getOrCreateSensor(m_type); |
74 exceptionState.throwDOMException(InvalidStateError, "Invalid State: Sens
orState is either idle or errored"); | 119 } |
75 return; | 120 |
76 } | 121 void Sensor::addedEventListener(const AtomicString& eventType, RegisteredEventLi
stener&) |
77 | 122 { |
78 m_hasEventListener = false; | 123 if (EventTypeNames::change == eventType) |
79 stopUpdating(); | 124 updatePollingStatus(); |
80 | 125 } |
81 m_sensorReading.clear(); | 126 |
82 updateState(SensorState::Idle); | 127 void Sensor::removedEventListener(const AtomicString& eventType, const Registere
dEventListener&) |
83 } | 128 { |
84 | 129 if (EventTypeNames::change == eventType) |
85 void Sensor::updateState(SensorState newState) | 130 updatePollingStatus(); |
86 { | 131 } |
87 DCHECK(isMainThread()); | 132 |
88 if (m_sensorState == newState) | 133 void Sensor::stop() |
89 return; | 134 { |
90 | 135 stopListening(); |
91 m_sensorState = newState; | 136 } |
92 // Notify context that state changed. | 137 |
93 if (getExecutionContext()) | 138 void Sensor::onSensorInitialized() |
94 getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&S
ensor::notifyStateChange, wrapPersistent(this))); | 139 { |
95 } | 140 if (m_state != Sensor::SensorState::ACTIVATING) |
96 | 141 return; |
97 void Sensor::notifyStateChange() | 142 |
98 { | 143 if (!m_sensorProxy) { |
| 144 reportError(); |
| 145 return; |
| 146 } |
| 147 |
| 148 auto startCallback = WTF::bind(&Sensor::onStartRequestCompleted, wrapWeakPer
sistent(this)); |
| 149 m_sensorProxy->addConfiguration(createSensorOptions(m_sensorOptions), std::m
ove(startCallback)); |
| 150 } |
| 151 |
| 152 void Sensor::onSensorReadingChanged() |
| 153 { |
| 154 if (m_polling) |
| 155 m_polling->onSensorReadingChanged(); |
| 156 } |
| 157 |
| 158 void Sensor::onSensorError() |
| 159 { |
| 160 reportError(); |
| 161 } |
| 162 |
| 163 bool Sensor::hasPendingActivity() const |
| 164 { |
| 165 if (!getExecutionContext() || getExecutionContext()->activeDOMObjectsAreStop
ped()) |
| 166 return false; |
| 167 return hasEventListeners(); |
| 168 } |
| 169 |
| 170 void Sensor::onStartRequestCompleted(bool result) |
| 171 { |
| 172 if (m_state != Sensor::SensorState::ACTIVATING) |
| 173 return; |
| 174 |
| 175 if (!result || !m_sensorProxy) { |
| 176 reportError(); |
| 177 return; |
| 178 } |
| 179 |
| 180 updateState(Sensor::SensorState::ACTIVE); |
| 181 |
| 182 double frequency = m_sensorOptions.hasFrequency() ? m_sensorOptions.frequenc
y() : 1; |
| 183 auto pollCallback = WTF::bind(&Sensor::pollForData, wrapWeakPersistent(this)
); |
| 184 m_polling = SensorPollingStrategy::create(frequency, std::move(pollCallback)
, m_sensorProxy->reportingMode()); |
| 185 updatePollingStatus(); |
| 186 } |
| 187 |
| 188 void Sensor::onStopRequestCompleted(bool result) |
| 189 { |
| 190 if (m_state == Sensor::SensorState::IDLE) |
| 191 return; |
| 192 |
| 193 if (!result) |
| 194 reportError(); |
| 195 |
| 196 if (m_sensorProxy) |
| 197 m_sensorProxy->removeObserver(this); |
| 198 } |
| 199 |
| 200 void Sensor::pageVisibilityChanged() |
| 201 { |
| 202 updatePollingStatus(); |
| 203 } |
| 204 |
| 205 void Sensor::startListening() |
| 206 { |
| 207 if (!m_sensorProxy) |
| 208 return; |
| 209 |
| 210 if (!m_sensorReading) { |
| 211 m_sensorReading = createSensorReading(getExecutionContext()); |
| 212 m_sensorReading->attach(m_sensorProxy); |
| 213 } |
| 214 |
| 215 m_sensorProxy->addObserver(this); |
| 216 if (m_sensorProxy->isInitialized()) { |
| 217 auto callback = WTF::bind(&Sensor::onStartRequestCompleted, wrapWeakPers
istent(this)); |
| 218 m_sensorProxy->addConfiguration(createSensorOptions(m_sensorOptions), st
d::move(callback)); |
| 219 } else { |
| 220 m_sensorProxy->initialize(); |
| 221 } |
| 222 } |
| 223 |
| 224 void Sensor::stopListening() |
| 225 { |
| 226 if (m_sensorReading) { |
| 227 m_sensorReading->detach(); |
| 228 m_sensorReading = nullptr; |
| 229 } |
| 230 |
| 231 updateState(Sensor::SensorState::IDLE); |
| 232 |
| 233 if (!m_sensorProxy) |
| 234 return; |
| 235 |
| 236 if (m_sensorProxy->isInitialized()) { |
| 237 auto callback = WTF::bind(&Sensor::onStopRequestCompleted, wrapWeakPersi
stent(this)); |
| 238 m_sensorProxy->removeConfiguration(createSensorOptions(m_sensorOptions),
std::move(callback)); |
| 239 } else { |
| 240 m_sensorProxy->removeObserver(this); |
| 241 } |
| 242 } |
| 243 |
| 244 void Sensor::pollForData() |
| 245 { |
| 246 if (m_state != Sensor::SensorState::ACTIVE) { |
| 247 DCHECK(m_polling); |
| 248 m_polling->stopPolling(); |
| 249 return; |
| 250 } |
| 251 |
| 252 switch (m_sensorReading->updateInternalData()) { |
| 253 case SensorReading::Updated: |
| 254 dispatchEvent(SensorReadingEvent::create(EventTypeNames::change, m_senso
rReading)); |
| 255 break; |
| 256 case SensorReading::Error: |
| 257 reportError(); |
| 258 break; |
| 259 case SensorReading::Same: |
| 260 break; |
| 261 default: |
| 262 NOTREACHED(); |
| 263 } |
| 264 } |
| 265 |
| 266 void Sensor::updateState(Sensor::SensorState newState) |
| 267 { |
| 268 if (newState == m_state) |
| 269 return; |
| 270 m_state = newState; |
99 dispatchEvent(Event::create(EventTypeNames::statechange)); | 271 dispatchEvent(Event::create(EventTypeNames::statechange)); |
100 } | 272 } |
101 | 273 |
102 void Sensor::suspend() | 274 void Sensor::reportError() |
103 { | 275 { |
104 m_hasEventListener = false; | 276 updateState(Sensor::SensorState::ERRORED); |
105 stopUpdating(); | 277 updatePollingStatus(); |
106 } | 278 // TODO(Mikhail) : Dispatch Sensor Error event. |
107 | 279 } |
108 void Sensor::resume() | 280 |
109 { | 281 void Sensor::updatePollingStatus() |
110 m_hasEventListener = true; | 282 { |
111 startUpdating(); | 283 if (!m_polling) |
112 } | 284 return; |
113 | 285 |
114 void Sensor::stop() | 286 if (m_state != Sensor::SensorState::ACTIVE // Sensor is not active. |
115 { | 287 || !hasEventListeners(EventTypeNames::change) // Noone is listening to '
onchange' event. |
116 m_hasEventListener = false; | 288 || page()->visibilityState() != PageVisibilityStateVisible) { // Page is
not visible. |
117 stopUpdating(); | 289 m_polling->stopPolling(); |
118 } | 290 } else { |
119 | 291 m_polling->startPolling(); |
120 bool Sensor::hasPendingActivity() const | 292 } |
121 { | |
122 // Prevent V8 from garbage collecting the wrapper object if there are | |
123 // event listeners attached to it. | |
124 return hasEventListeners(); | |
125 } | |
126 | |
127 DEFINE_TRACE(Sensor) | |
128 { | |
129 ActiveDOMObject::trace(visitor); | |
130 EventTargetWithInlineData::trace(visitor); | |
131 PlatformEventController::trace(visitor); | |
132 visitor->trace(m_sensorReading); | |
133 } | 293 } |
134 | 294 |
135 } // namespace blink | 295 } // namespace blink |
OLD | NEW |