Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/Hal.h"
6 #include "mozilla/HalSensor.h"
8 #include "nsDeviceSensors.h"
10 #include "nsAutoPtr.h"
11 #include "nsIDOMEvent.h"
12 #include "nsIDOMWindow.h"
13 #include "nsPIDOMWindow.h"
14 #include "nsIDOMDocument.h"
15 #include "nsIServiceManager.h"
16 #include "nsIServiceManager.h"
17 #include "GeneratedEvents.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/Attributes.h"
20 #include "nsIPermissionManager.h"
21 #include "mozilla/dom/DeviceLightEvent.h"
22 #include "mozilla/dom/DeviceProximityEvent.h"
23 #include "mozilla/dom/UserProximityEvent.h"
25 using namespace mozilla;
26 using namespace mozilla::dom;
27 using namespace hal;
29 #undef near
31 // also see sDefaultSensorHint in mobile/android/base/GeckoAppShell.java
32 #define DEFAULT_SENSOR_POLL 100
34 static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
35 nsTArray<nsIDOMWindow*>::NoIndex;
37 class nsDeviceSensorData MOZ_FINAL : public nsIDeviceSensorData
38 {
39 public:
40 NS_DECL_ISUPPORTS
41 NS_DECL_NSIDEVICESENSORDATA
43 nsDeviceSensorData(unsigned long type, double x, double y, double z);
45 private:
46 ~nsDeviceSensorData();
48 protected:
49 unsigned long mType;
50 double mX, mY, mZ;
51 };
53 nsDeviceSensorData::nsDeviceSensorData(unsigned long type, double x, double y, double z)
54 : mType(type), mX(x), mY(y), mZ(z)
55 {
56 }
58 NS_INTERFACE_MAP_BEGIN(nsDeviceSensorData)
59 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDeviceSensorData)
60 NS_INTERFACE_MAP_END
62 NS_IMPL_ADDREF(nsDeviceSensorData)
63 NS_IMPL_RELEASE(nsDeviceSensorData)
65 nsDeviceSensorData::~nsDeviceSensorData()
66 {
67 }
69 NS_IMETHODIMP nsDeviceSensorData::GetType(uint32_t *aType)
70 {
71 NS_ENSURE_ARG_POINTER(aType);
72 *aType = mType;
73 return NS_OK;
74 }
76 NS_IMETHODIMP nsDeviceSensorData::GetX(double *aX)
77 {
78 NS_ENSURE_ARG_POINTER(aX);
79 *aX = mX;
80 return NS_OK;
81 }
83 NS_IMETHODIMP nsDeviceSensorData::GetY(double *aY)
84 {
85 NS_ENSURE_ARG_POINTER(aY);
86 *aY = mY;
87 return NS_OK;
88 }
90 NS_IMETHODIMP nsDeviceSensorData::GetZ(double *aZ)
91 {
92 NS_ENSURE_ARG_POINTER(aZ);
93 *aZ = mZ;
94 return NS_OK;
95 }
97 NS_IMPL_ISUPPORTS(nsDeviceSensors, nsIDeviceSensors)
99 nsDeviceSensors::nsDeviceSensors()
100 {
101 mIsUserProximityNear = false;
102 mLastDOMMotionEventTime = TimeStamp::Now();
103 mEnabled = Preferences::GetBool("device.sensors.enabled", true);
105 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
106 nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
107 mWindowListeners.AppendElement(windows);
108 }
110 mLastDOMMotionEventTime = TimeStamp::Now();
111 }
113 nsDeviceSensors::~nsDeviceSensors()
114 {
115 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
116 if (IsSensorEnabled(i))
117 UnregisterSensorObserver((SensorType)i, this);
118 }
120 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
121 delete mWindowListeners[i];
122 }
123 }
125 NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType, nsIDOMWindow *aWindow, bool *aRetVal)
126 {
127 if (!mEnabled)
128 *aRetVal = false;
129 else
130 *aRetVal = mWindowListeners[aType]->IndexOf(aWindow) != NoIndex;
132 return NS_OK;
133 }
135 NS_IMETHODIMP nsDeviceSensors::AddWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
136 {
137 if (!mEnabled)
138 return NS_OK;
140 if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
141 return NS_OK;
143 if (!IsSensorEnabled(aType)) {
144 RegisterSensorObserver((SensorType)aType, this);
145 }
147 mWindowListeners[aType]->AppendElement(aWindow);
148 return NS_OK;
149 }
151 NS_IMETHODIMP nsDeviceSensors::RemoveWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
152 {
153 if (mWindowListeners[aType]->IndexOf(aWindow) == NoIndex)
154 return NS_OK;
156 mWindowListeners[aType]->RemoveElement(aWindow);
158 if (mWindowListeners[aType]->Length() == 0)
159 UnregisterSensorObserver((SensorType)aType, this);
161 return NS_OK;
162 }
164 NS_IMETHODIMP nsDeviceSensors::RemoveWindowAsListener(nsIDOMWindow *aWindow)
165 {
166 for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
167 RemoveWindowListener((SensorType)i, aWindow);
168 }
169 return NS_OK;
170 }
172 static bool
173 WindowCannotReceiveSensorEvent (nsPIDOMWindow* aWindow)
174 {
175 // Check to see if this window is in the background. If
176 // it is and it does not have the "background-sensors" permission,
177 // don't send any device motion events to it.
178 if (!aWindow || !aWindow->IsCurrentInnerWindow()) {
179 return true;
180 }
182 if (aWindow->GetOuterWindow()->IsBackground()) {
183 nsCOMPtr<nsIPermissionManager> permMgr =
184 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
185 NS_ENSURE_TRUE(permMgr, false);
186 uint32_t permission = nsIPermissionManager::DENY_ACTION;
187 permMgr->TestPermissionFromWindow(aWindow, "background-sensors", &permission);
188 return permission != nsIPermissionManager::ALLOW_ACTION;
189 }
191 return false;
192 }
194 void
195 nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData)
196 {
197 uint32_t type = aSensorData.sensor();
199 const InfallibleTArray<float>& values = aSensorData.values();
200 size_t len = values.Length();
201 double x = len > 0 ? values[0] : 0.0;
202 double y = len > 1 ? values[1] : 0.0;
203 double z = len > 2 ? values[2] : 0.0;
205 nsCOMArray<nsIDOMWindow> windowListeners;
206 for (uint32_t i = 0; i < mWindowListeners[type]->Length(); i++) {
207 windowListeners.AppendObject(mWindowListeners[type]->SafeElementAt(i));
208 }
210 for (uint32_t i = windowListeners.Count(); i > 0 ; ) {
211 --i;
213 nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(windowListeners[i]);
214 if (WindowCannotReceiveSensorEvent(pwindow)) {
215 continue;
216 }
218 nsCOMPtr<nsIDOMDocument> domdoc;
219 windowListeners[i]->GetDocument(getter_AddRefs(domdoc));
221 if (domdoc) {
222 nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(windowListeners[i]);
223 if (type == nsIDeviceSensorData::TYPE_ACCELERATION ||
224 type == nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION ||
225 type == nsIDeviceSensorData::TYPE_GYROSCOPE)
226 FireDOMMotionEvent(domdoc, target, type, x, y, z);
227 else if (type == nsIDeviceSensorData::TYPE_ORIENTATION)
228 FireDOMOrientationEvent(domdoc, target, x, y, z);
229 else if (type == nsIDeviceSensorData::TYPE_PROXIMITY)
230 FireDOMProximityEvent(target, x, y, z);
231 else if (type == nsIDeviceSensorData::TYPE_LIGHT)
232 FireDOMLightEvent(target, x);
234 }
235 }
236 }
238 void
239 nsDeviceSensors::FireDOMLightEvent(mozilla::dom::EventTarget* aTarget,
240 double aValue)
241 {
242 DeviceLightEventInit init;
243 init.mBubbles = true;
244 init.mCancelable = false;
245 init.mValue = aValue;
246 nsRefPtr<DeviceLightEvent> event =
247 DeviceLightEvent::Constructor(aTarget, NS_LITERAL_STRING("devicelight"), init);
249 event->SetTrusted(true);
251 bool defaultActionEnabled;
252 aTarget->DispatchEvent(event, &defaultActionEnabled);
253 }
255 void
256 nsDeviceSensors::FireDOMProximityEvent(mozilla::dom::EventTarget* aTarget,
257 double aValue,
258 double aMin,
259 double aMax)
260 {
261 DeviceProximityEventInit init;
262 init.mBubbles = true;
263 init.mCancelable = false;
264 init.mValue = aValue;
265 init.mMin = aMin;
266 init.mMax = aMax;
267 nsRefPtr<DeviceProximityEvent> event =
268 DeviceProximityEvent::Constructor(aTarget,
269 NS_LITERAL_STRING("deviceproximity"),
270 init);
271 event->SetTrusted(true);
273 bool defaultActionEnabled;
274 aTarget->DispatchEvent(event, &defaultActionEnabled);
276 // Some proximity sensors only support a binary near or
277 // far measurement. In this case, the sensor should report
278 // its maximum range value in the far state and a lesser
279 // value in the near state.
281 bool near = (aValue < aMax);
282 if (mIsUserProximityNear != near) {
283 mIsUserProximityNear = near;
284 FireDOMUserProximityEvent(aTarget, mIsUserProximityNear);
285 }
286 }
288 void
289 nsDeviceSensors::FireDOMUserProximityEvent(mozilla::dom::EventTarget* aTarget,
290 bool aNear)
291 {
292 UserProximityEventInit init;
293 init.mBubbles = true;
294 init.mCancelable = false;
295 init.mNear = aNear;
296 nsRefPtr<UserProximityEvent> event =
297 UserProximityEvent::Constructor(aTarget,
298 NS_LITERAL_STRING("userproximity"),
299 init);
301 event->SetTrusted(true);
303 bool defaultActionEnabled;
304 aTarget->DispatchEvent(event, &defaultActionEnabled);
305 }
307 void
308 nsDeviceSensors::FireDOMOrientationEvent(nsIDOMDocument* domdoc,
309 EventTarget* target,
310 double alpha,
311 double beta,
312 double gamma)
313 {
314 nsCOMPtr<nsIDOMEvent> event;
315 bool defaultActionEnabled = true;
316 domdoc->CreateEvent(NS_LITERAL_STRING("DeviceOrientationEvent"), getter_AddRefs(event));
318 nsCOMPtr<nsIDOMDeviceOrientationEvent> oe = do_QueryInterface(event);
320 if (!oe) {
321 return;
322 }
324 oe->InitDeviceOrientationEvent(NS_LITERAL_STRING("deviceorientation"),
325 true,
326 false,
327 alpha,
328 beta,
329 gamma,
330 true);
332 event->SetTrusted(true);
334 target->DispatchEvent(event, &defaultActionEnabled);
335 }
338 void
339 nsDeviceSensors::FireDOMMotionEvent(nsIDOMDocument *domdoc,
340 EventTarget* target,
341 uint32_t type,
342 double x,
343 double y,
344 double z)
345 {
346 // Attempt to coalesce events
347 bool fireEvent = TimeStamp::Now() > mLastDOMMotionEventTime + TimeDuration::FromMilliseconds(DEFAULT_SENSOR_POLL);
349 switch (type) {
350 case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
351 if (mLastAcceleration.empty()) {
352 mLastAcceleration.construct();
353 }
354 mLastAcceleration.ref().mX.SetValue(x);
355 mLastAcceleration.ref().mY.SetValue(y);
356 mLastAcceleration.ref().mZ.SetValue(z);
357 break;
358 case nsIDeviceSensorData::TYPE_ACCELERATION:
359 if (mLastAccelerationIncluduingGravity.empty()) {
360 mLastAccelerationIncluduingGravity.construct();
361 }
362 mLastAccelerationIncluduingGravity.ref().mX.SetValue(x);
363 mLastAccelerationIncluduingGravity.ref().mY.SetValue(y);
364 mLastAccelerationIncluduingGravity.ref().mZ.SetValue(z);
365 break;
366 case nsIDeviceSensorData::TYPE_GYROSCOPE:
367 if (mLastRotationRate.empty()) {
368 mLastRotationRate.construct();
369 }
370 mLastRotationRate.ref().mAlpha.SetValue(x);
371 mLastRotationRate.ref().mBeta.SetValue(y);
372 mLastRotationRate.ref().mGamma.SetValue(z);
373 break;
374 }
376 if (fireEvent) {
377 if (mLastAcceleration.empty()) {
378 mLastAcceleration.construct();
379 }
380 if (mLastAccelerationIncluduingGravity.empty()) {
381 mLastAccelerationIncluduingGravity.construct();
382 }
383 if (mLastRotationRate.empty()) {
384 mLastRotationRate.construct();
385 }
386 } else if (mLastAcceleration.empty() ||
387 mLastAccelerationIncluduingGravity.empty() ||
388 mLastRotationRate.empty()) {
389 return;
390 }
392 nsCOMPtr<nsIDOMEvent> event;
393 domdoc->CreateEvent(NS_LITERAL_STRING("DeviceMotionEvent"), getter_AddRefs(event));
395 DeviceMotionEvent* me = static_cast<DeviceMotionEvent*>(event.get());
397 ErrorResult rv;
398 me->InitDeviceMotionEvent(NS_LITERAL_STRING("devicemotion"),
399 true,
400 false,
401 mLastAcceleration.ref(),
402 mLastAccelerationIncluduingGravity.ref(),
403 mLastRotationRate.ref(),
404 Nullable<double>(DEFAULT_SENSOR_POLL),
405 rv);
407 event->SetTrusted(true);
409 bool defaultActionEnabled = true;
410 target->DispatchEvent(event, &defaultActionEnabled);
412 mLastRotationRate.destroy();
413 mLastAccelerationIncluduingGravity.destroy();
414 mLastAcceleration.destroy();
415 mLastDOMMotionEventTime = TimeStamp::Now();
416 }