Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/system/nsDeviceSensors.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/Hal.h"
8
#include "mozilla/HalSensor.h"
9
10
#include "nsContentUtils.h"
11
#include "nsDeviceSensors.h"
12
13
#include "nsIDOMWindow.h"
14
#include "nsPIDOMWindow.h"
15
#include "nsIScriptObjectPrincipal.h"
16
#include "nsIServiceManager.h"
17
#include "nsIServiceManager.h"
18
#include "mozilla/Preferences.h"
19
#include "mozilla/Attributes.h"
20
#include "mozilla/Services.h"
21
#include "nsIPermissionManager.h"
22
#include "mozilla/dom/DeviceLightEvent.h"
23
#include "mozilla/dom/DeviceOrientationEvent.h"
24
#include "mozilla/dom/DeviceProximityEvent.h"
25
#include "mozilla/dom/Event.h"
26
#include "mozilla/dom/UserProximityEvent.h"
27
#include "mozilla/ErrorResult.h"
28
29
#include <cmath>
30
31
using namespace mozilla;
32
using namespace mozilla::dom;
33
using namespace hal;
34
35
#undef near
36
37
0
#define DEFAULT_SENSOR_POLL 100
38
39
static bool gPrefSensorsEnabled = false;
40
static bool gPrefMotionSensorEnabled = false;
41
static bool gPrefOrientationSensorEnabled = false;
42
static bool gPrefProximitySensorEnabled = false;
43
static bool gPrefAmbientLightSensorEnabled = false;
44
45
static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
46
  nsTArray<nsIDOMWindow*>::NoIndex;
47
48
class nsDeviceSensorData final : public nsIDeviceSensorData
49
{
50
public:
51
  NS_DECL_ISUPPORTS
52
  NS_DECL_NSIDEVICESENSORDATA
53
54
  nsDeviceSensorData(unsigned long type, double x, double y, double z);
55
56
private:
57
  ~nsDeviceSensorData();
58
59
protected:
60
  unsigned long mType;
61
  double mX, mY, mZ;
62
};
63
64
nsDeviceSensorData::nsDeviceSensorData(unsigned long type, double x, double y, double z)
65
  : mType(type), mX(x), mY(y), mZ(z)
66
0
{
67
0
}
68
69
0
NS_INTERFACE_MAP_BEGIN(nsDeviceSensorData)
70
0
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDeviceSensorData)
71
0
NS_INTERFACE_MAP_END
72
73
NS_IMPL_ADDREF(nsDeviceSensorData)
74
NS_IMPL_RELEASE(nsDeviceSensorData)
75
76
nsDeviceSensorData::~nsDeviceSensorData()
77
0
{
78
0
}
79
80
NS_IMETHODIMP nsDeviceSensorData::GetType(uint32_t *aType)
81
0
{
82
0
  NS_ENSURE_ARG_POINTER(aType);
83
0
  *aType = mType;
84
0
  return NS_OK;
85
0
}
86
87
NS_IMETHODIMP nsDeviceSensorData::GetX(double *aX)
88
0
{
89
0
  NS_ENSURE_ARG_POINTER(aX);
90
0
  *aX = mX;
91
0
  return NS_OK;
92
0
}
93
94
NS_IMETHODIMP nsDeviceSensorData::GetY(double *aY)
95
0
{
96
0
  NS_ENSURE_ARG_POINTER(aY);
97
0
  *aY = mY;
98
0
  return NS_OK;
99
0
}
100
101
NS_IMETHODIMP nsDeviceSensorData::GetZ(double *aZ)
102
0
{
103
0
  NS_ENSURE_ARG_POINTER(aZ);
104
0
  *aZ = mZ;
105
0
  return NS_OK;
106
0
}
107
108
NS_IMPL_ISUPPORTS(nsDeviceSensors, nsIDeviceSensors)
109
110
nsDeviceSensors::nsDeviceSensors()
111
0
{
112
0
  mIsUserProximityNear = false;
113
0
  mLastDOMMotionEventTime = TimeStamp::Now();
114
0
  Preferences::AddBoolVarCache(&gPrefSensorsEnabled,
115
0
                              "device.sensors.enabled",
116
0
                              true);
117
0
  Preferences::AddBoolVarCache(&gPrefMotionSensorEnabled,
118
0
                              "device.sensors.motion.enabled",
119
0
                              true);
120
0
  Preferences::AddBoolVarCache(&gPrefOrientationSensorEnabled,
121
0
                              "device.sensors.orientation.enabled",
122
0
                              true);
123
0
  Preferences::AddBoolVarCache(&gPrefProximitySensorEnabled,
124
0
                              "device.sensors.proximity.enabled",
125
0
                              false);
126
0
  Preferences::AddBoolVarCache(&gPrefAmbientLightSensorEnabled,
127
0
                              "device.sensors.ambientLight.enabled",
128
0
                              false);
129
0
130
0
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
131
0
    nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
132
0
    mWindowListeners.AppendElement(windows);
133
0
  }
134
0
135
0
  mLastDOMMotionEventTime = TimeStamp::Now();
136
0
}
137
138
nsDeviceSensors::~nsDeviceSensors()
139
0
{
140
0
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
141
0
    if (IsSensorEnabled(i))
142
0
      UnregisterSensorObserver((SensorType)i, this);
143
0
  }
144
0
145
0
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
146
0
    delete mWindowListeners[i];
147
0
  }
148
0
}
149
150
NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType, nsIDOMWindow *aWindow, bool *aRetVal)
151
0
{
152
0
  if (!IsSensorAllowedByPref(aType, aWindow))
153
0
    *aRetVal = false;
154
0
  else
155
0
    *aRetVal = mWindowListeners[aType]->IndexOf(aWindow) != NoIndex;
156
0
157
0
  return NS_OK;
158
0
}
159
160
class DeviceSensorTestEvent : public Runnable
161
{
162
public:
163
  DeviceSensorTestEvent(nsDeviceSensors* aTarget, uint32_t aType)
164
    : mozilla::Runnable("DeviceSensorTestEvent")
165
    , mTarget(aTarget)
166
    , mType(aType)
167
0
  {
168
0
  }
169
170
  NS_IMETHOD Run() override
171
0
  {
172
0
    SensorData sensorData;
173
0
    sensorData.sensor() = static_cast<SensorType>(mType);
174
0
    sensorData.timestamp() = PR_Now();
175
0
    sensorData.values().AppendElement(0.5f);
176
0
    sensorData.values().AppendElement(0.5f);
177
0
    sensorData.values().AppendElement(0.5f);
178
0
    sensorData.values().AppendElement(0.5f);
179
0
    mTarget->Notify(sensorData);
180
0
    return NS_OK;
181
0
  }
182
183
private:
184
  RefPtr<nsDeviceSensors> mTarget;
185
  uint32_t mType;
186
};
187
188
static bool sTestSensorEvents = false;
189
190
NS_IMETHODIMP nsDeviceSensors::AddWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
191
0
{
192
0
  if (!IsSensorAllowedByPref(aType, aWindow))
193
0
    return NS_OK;
194
0
195
0
  if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
196
0
    return NS_OK;
197
0
198
0
  if (!IsSensorEnabled(aType)) {
199
0
    RegisterSensorObserver((SensorType)aType, this);
200
0
  }
201
0
202
0
  mWindowListeners[aType]->AppendElement(aWindow);
203
0
204
0
  static bool sPrefCacheInitialized = false;
205
0
  if (!sPrefCacheInitialized) {
206
0
    sPrefCacheInitialized = true;
207
0
    Preferences::AddBoolVarCache(&sTestSensorEvents,
208
0
                                 "device.sensors.test.events",
209
0
                                 false);
210
0
  }
211
0
212
0
  if (sTestSensorEvents) {
213
0
    nsCOMPtr<nsIRunnable> event = new DeviceSensorTestEvent(this, aType);
214
0
    NS_DispatchToCurrentThread(event);
215
0
  }
216
0
217
0
  return NS_OK;
218
0
}
219
220
NS_IMETHODIMP nsDeviceSensors::RemoveWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
221
0
{
222
0
  if (mWindowListeners[aType]->IndexOf(aWindow) == NoIndex)
223
0
    return NS_OK;
224
0
225
0
  mWindowListeners[aType]->RemoveElement(aWindow);
226
0
227
0
  if (mWindowListeners[aType]->Length() == 0)
228
0
    UnregisterSensorObserver((SensorType)aType, this);
229
0
230
0
  return NS_OK;
231
0
}
232
233
NS_IMETHODIMP nsDeviceSensors::RemoveWindowAsListener(nsIDOMWindow *aWindow)
234
0
{
235
0
  for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
236
0
    RemoveWindowListener((SensorType)i, aWindow);
237
0
  }
238
0
  return NS_OK;
239
0
}
240
241
static bool
242
WindowCannotReceiveSensorEvent (nsPIDOMWindowInner* aWindow)
243
0
{
244
0
  // Check to see if this window is in the background.
245
0
  if (!aWindow || !aWindow->IsCurrentInnerWindow()) {
246
0
    return true;
247
0
  }
248
0
249
0
  bool disabled = aWindow->GetOuterWindow()->IsBackground() ||
250
0
    !aWindow->IsTopLevelWindowActive();
251
0
  if (disabled) {
252
0
    return true;
253
0
  }
254
0
255
0
  // Check to see if this window is a cross-origin iframe
256
0
  nsCOMPtr<nsPIDOMWindowOuter> top = aWindow->GetScriptableTop();
257
0
  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
258
0
  nsCOMPtr<nsIScriptObjectPrincipal> topSop = do_QueryInterface(top);
259
0
  if (!sop || !topSop) {
260
0
    return true;
261
0
  }
262
0
263
0
  nsIPrincipal* principal = sop->GetPrincipal();
264
0
  nsIPrincipal* topPrincipal = topSop->GetPrincipal();
265
0
  if (!principal || !topPrincipal) {
266
0
    return true;
267
0
  }
268
0
269
0
  return !principal->Subsumes(topPrincipal);
270
0
}
271
272
// Holds the device orientation in Euler angle degrees (azimuth, pitch, roll).
273
struct Orientation
274
{
275
  enum OrientationReference
276
  {
277
    kRelative = 0,
278
    kAbsolute
279
  };
280
281
  static Orientation RadToDeg(const Orientation& aOrient)
282
0
  {
283
0
    const static double kRadToDeg = 180.0 / M_PI;
284
0
    return { aOrient.alpha * kRadToDeg,
285
0
             aOrient.beta * kRadToDeg,
286
0
             aOrient.gamma * kRadToDeg };
287
0
  }
288
289
  double alpha;
290
  double beta;
291
  double gamma;
292
};
293
294
static Orientation
295
0
RotationVectorToOrientation(double aX, double aY, double aZ, double aW) {
296
0
  double mat[9];
297
0
298
0
  mat[0] = 1 - 2*aY*aY - 2*aZ*aZ;
299
0
  mat[1] = 2*aX*aY - 2*aZ*aW;
300
0
  mat[2] = 2*aX*aZ + 2*aY*aW;
301
0
302
0
  mat[3] = 2*aX*aY + 2*aZ*aW;
303
0
  mat[4] = 1 - 2*aX*aX - 2*aZ*aZ;
304
0
  mat[5] = 2*aY*aZ - 2*aX*aW;
305
0
306
0
  mat[6] = 2*aX*aZ - 2*aY*aW;
307
0
  mat[7] = 2*aY*aZ + 2*aX*aW;
308
0
  mat[8] = 1 - 2*aX*aX - 2*aY*aY;
309
0
310
0
  Orientation orient;
311
0
312
0
  if (mat[8] > 0) {
313
0
    orient.alpha = atan2(-mat[1], mat[4]);
314
0
    orient.beta = asin(mat[7]);
315
0
    orient.gamma = atan2(-mat[6], mat[8]);
316
0
  } else if (mat[8] < 0) {
317
0
    orient.alpha = atan2(mat[1], -mat[4]);
318
0
    orient.beta = -asin(mat[7]);
319
0
    orient.beta += (orient.beta >= 0) ? -M_PI : M_PI;
320
0
    orient.gamma = atan2(mat[6], -mat[8]);
321
0
  } else {
322
0
    if (mat[6] > 0) {
323
0
      orient.alpha = atan2(-mat[1], mat[4]);
324
0
      orient.beta = asin(mat[7]);
325
0
      orient.gamma = -M_PI_2;
326
0
    } else if (mat[6] < 0) {
327
0
      orient.alpha = atan2(mat[1], -mat[4]);
328
0
      orient.beta = -asin(mat[7]);
329
0
      orient.beta += (orient.beta >= 0) ? -M_PI : M_PI;
330
0
      orient.gamma = -M_PI_2;
331
0
    } else {
332
0
      orient.alpha = atan2(mat[3], mat[0]);
333
0
      orient.beta = (mat[7] > 0) ? M_PI_2 : -M_PI_2;
334
0
      orient.gamma = 0;
335
0
    }
336
0
  }
337
0
338
0
  if (orient.alpha < 0) {
339
0
    orient.alpha += 2*M_PI;
340
0
  }
341
0
342
0
  return Orientation::RadToDeg(orient);
343
0
}
344
345
void
346
nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData)
347
0
{
348
0
  uint32_t type = aSensorData.sensor();
349
0
350
0
  const InfallibleTArray<float>& values = aSensorData.values();
351
0
  size_t len = values.Length();
352
0
  double x = len > 0 ? values[0] : 0.0;
353
0
  double y = len > 1 ? values[1] : 0.0;
354
0
  double z = len > 2 ? values[2] : 0.0;
355
0
  double w = len > 3 ? values[3] : 0.0;
356
0
  PRTime timestamp = aSensorData.timestamp();
357
0
358
0
  nsCOMArray<nsIDOMWindow> windowListeners;
359
0
  for (uint32_t i = 0; i < mWindowListeners[type]->Length(); i++) {
360
0
    windowListeners.AppendObject(mWindowListeners[type]->SafeElementAt(i));
361
0
  }
362
0
363
0
  for (uint32_t i = windowListeners.Count(); i > 0 ; ) {
364
0
    --i;
365
0
366
0
    nsCOMPtr<nsPIDOMWindowInner> pwindow = do_QueryInterface(windowListeners[i]);
367
0
    if (WindowCannotReceiveSensorEvent(pwindow)) {
368
0
        continue;
369
0
    }
370
0
371
0
    if (nsCOMPtr<nsIDocument> doc = pwindow->GetDoc()) {
372
0
      nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(windowListeners[i]);
373
0
      if (type == nsIDeviceSensorData::TYPE_ACCELERATION ||
374
0
        type == nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION ||
375
0
        type == nsIDeviceSensorData::TYPE_GYROSCOPE) {
376
0
        FireDOMMotionEvent(doc, target, type, timestamp, x, y, z);
377
0
      } else if (type == nsIDeviceSensorData::TYPE_ORIENTATION) {
378
0
        FireDOMOrientationEvent(target, x, y, z, Orientation::kAbsolute);
379
0
      } else if (type == nsIDeviceSensorData::TYPE_ROTATION_VECTOR) {
380
0
        const Orientation orient = RotationVectorToOrientation(x, y, z, w);
381
0
        FireDOMOrientationEvent(target, orient.alpha, orient.beta, orient.gamma,
382
0
                                Orientation::kAbsolute);
383
0
      } else if (type == nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR) {
384
0
        const Orientation orient = RotationVectorToOrientation(x, y, z, w);
385
0
        FireDOMOrientationEvent(target, orient.alpha, orient.beta, orient.gamma,
386
0
                                Orientation::kRelative);
387
0
      } else if (type == nsIDeviceSensorData::TYPE_PROXIMITY) {
388
0
        FireDOMProximityEvent(target, x, y, z);
389
0
      } else if (type == nsIDeviceSensorData::TYPE_LIGHT) {
390
0
        FireDOMLightEvent(target, x);
391
0
      }
392
0
    }
393
0
  }
394
0
}
395
396
void
397
nsDeviceSensors::FireDOMLightEvent(mozilla::dom::EventTarget* aTarget,
398
                                   double aValue)
399
0
{
400
0
  DeviceLightEventInit init;
401
0
  init.mBubbles = true;
402
0
  init.mCancelable = false;
403
0
  init.mValue = round(aValue);
404
0
  RefPtr<DeviceLightEvent> event =
405
0
    DeviceLightEvent::Constructor(aTarget, NS_LITERAL_STRING("devicelight"), init);
406
0
407
0
  event->SetTrusted(true);
408
0
409
0
  aTarget->DispatchEvent(*event);
410
0
}
411
412
void
413
nsDeviceSensors::FireDOMProximityEvent(mozilla::dom::EventTarget* aTarget,
414
                                       double aValue,
415
                                       double aMin,
416
                                       double aMax)
417
0
{
418
0
  DeviceProximityEventInit init;
419
0
  init.mBubbles = true;
420
0
  init.mCancelable = false;
421
0
  init.mValue = aValue;
422
0
  init.mMin = aMin;
423
0
  init.mMax = aMax;
424
0
  RefPtr<DeviceProximityEvent> event =
425
0
    DeviceProximityEvent::Constructor(aTarget,
426
0
                                      NS_LITERAL_STRING("deviceproximity"),
427
0
                                      init);
428
0
  event->SetTrusted(true);
429
0
430
0
  aTarget->DispatchEvent(*event);
431
0
432
0
  // Some proximity sensors only support a binary near or
433
0
  // far measurement. In this case, the sensor should report
434
0
  // its maximum range value in the far state and a lesser
435
0
  // value in the near state.
436
0
437
0
  bool near = (aValue < aMax);
438
0
  if (mIsUserProximityNear != near) {
439
0
    mIsUserProximityNear = near;
440
0
    FireDOMUserProximityEvent(aTarget, mIsUserProximityNear);
441
0
  }
442
0
}
443
444
void
445
nsDeviceSensors::FireDOMUserProximityEvent(mozilla::dom::EventTarget* aTarget,
446
                                           bool aNear)
447
0
{
448
0
  UserProximityEventInit init;
449
0
  init.mBubbles = true;
450
0
  init.mCancelable = false;
451
0
  init.mNear = aNear;
452
0
  RefPtr<UserProximityEvent> event =
453
0
    UserProximityEvent::Constructor(aTarget,
454
0
                                    NS_LITERAL_STRING("userproximity"),
455
0
                                    init);
456
0
457
0
  event->SetTrusted(true);
458
0
459
0
  aTarget->DispatchEvent(*event);
460
0
}
461
462
void
463
nsDeviceSensors::FireDOMOrientationEvent(EventTarget* aTarget,
464
                                         double aAlpha,
465
                                         double aBeta,
466
                                         double aGamma,
467
                                         bool aIsAbsolute)
468
0
{
469
0
  DeviceOrientationEventInit init;
470
0
  init.mBubbles = true;
471
0
  init.mCancelable = false;
472
0
  init.mAlpha.SetValue(aAlpha);
473
0
  init.mBeta.SetValue(aBeta);
474
0
  init.mGamma.SetValue(aGamma);
475
0
  init.mAbsolute = aIsAbsolute;
476
0
477
0
  auto Dispatch = [&](EventTarget* aEventTarget, const nsAString& aType)
478
0
  {
479
0
    RefPtr<DeviceOrientationEvent> event =
480
0
      DeviceOrientationEvent::Constructor(aEventTarget, aType, init);
481
0
    event->SetTrusted(true);
482
0
    aEventTarget->DispatchEvent(*event);
483
0
  };
484
0
485
0
  Dispatch(aTarget, aIsAbsolute ? NS_LITERAL_STRING("absolutedeviceorientation") :
486
0
                                  NS_LITERAL_STRING("deviceorientation"));
487
0
488
0
  // This is used to determine whether relative events have been dispatched
489
0
  // during the current session, in which case we don't dispatch the additional
490
0
  // compatibility events.
491
0
  static bool sIsDispatchingRelativeEvents = false;
492
0
  sIsDispatchingRelativeEvents = sIsDispatchingRelativeEvents || !aIsAbsolute;
493
0
494
0
  // Android devices with SENSOR_GAME_ROTATION_VECTOR support dispatch
495
0
  // relative events for "deviceorientation" by default, while other platforms
496
0
  // and devices without such support dispatch absolute events by default.
497
0
  if (aIsAbsolute && !sIsDispatchingRelativeEvents) {
498
0
    // For absolute events on devices without support for relative events,
499
0
    // we need to additionally dispatch type "deviceorientation" to keep
500
0
    // backwards-compatibility.
501
0
    Dispatch(aTarget, NS_LITERAL_STRING("deviceorientation"));
502
0
  }
503
0
}
504
505
void
506
nsDeviceSensors::FireDOMMotionEvent(nsIDocument *doc,
507
                                    EventTarget* target,
508
                                    uint32_t type,
509
                                    PRTime timestamp,
510
                                    double x,
511
                                    double y,
512
                                    double z)
513
0
{
514
0
  // Attempt to coalesce events
515
0
  TimeDuration sensorPollDuration =
516
0
    TimeDuration::FromMilliseconds(DEFAULT_SENSOR_POLL);
517
0
  bool fireEvent =
518
0
    (TimeStamp::Now() > mLastDOMMotionEventTime + sensorPollDuration) ||
519
0
    sTestSensorEvents;
520
0
521
0
  switch (type) {
522
0
  case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
523
0
    if (!mLastAcceleration) {
524
0
      mLastAcceleration.emplace();
525
0
    }
526
0
    mLastAcceleration->mX.SetValue(x);
527
0
    mLastAcceleration->mY.SetValue(y);
528
0
    mLastAcceleration->mZ.SetValue(z);
529
0
    break;
530
0
  case nsIDeviceSensorData::TYPE_ACCELERATION:
531
0
    if (!mLastAccelerationIncludingGravity) {
532
0
      mLastAccelerationIncludingGravity.emplace();
533
0
    }
534
0
    mLastAccelerationIncludingGravity->mX.SetValue(x);
535
0
    mLastAccelerationIncludingGravity->mY.SetValue(y);
536
0
    mLastAccelerationIncludingGravity->mZ.SetValue(z);
537
0
    break;
538
0
  case nsIDeviceSensorData::TYPE_GYROSCOPE:
539
0
    if (!mLastRotationRate) {
540
0
      mLastRotationRate.emplace();
541
0
    }
542
0
    mLastRotationRate->mAlpha.SetValue(x);
543
0
    mLastRotationRate->mBeta.SetValue(y);
544
0
    mLastRotationRate->mGamma.SetValue(z);
545
0
    break;
546
0
  }
547
0
548
0
  if (fireEvent) {
549
0
    if (!mLastAcceleration) {
550
0
      mLastAcceleration.emplace();
551
0
    }
552
0
    if (!mLastAccelerationIncludingGravity) {
553
0
      mLastAccelerationIncludingGravity.emplace();
554
0
    }
555
0
    if (!mLastRotationRate) {
556
0
      mLastRotationRate.emplace();
557
0
    }
558
0
  } else if (!mLastAcceleration ||
559
0
             !mLastAccelerationIncludingGravity ||
560
0
             !mLastRotationRate) {
561
0
    return;
562
0
  }
563
0
564
0
  IgnoredErrorResult ignored;
565
0
  RefPtr<Event> event = doc->CreateEvent(NS_LITERAL_STRING("DeviceMotionEvent"),
566
0
                                         CallerType::System, ignored);
567
0
  if (!event) {
568
0
    return;
569
0
  }
570
0
571
0
  DeviceMotionEvent* me = static_cast<DeviceMotionEvent*>(event.get());
572
0
573
0
  me->InitDeviceMotionEvent(NS_LITERAL_STRING("devicemotion"),
574
0
                            true,
575
0
                            false,
576
0
                            *mLastAcceleration,
577
0
                            *mLastAccelerationIncludingGravity,
578
0
                            *mLastRotationRate,
579
0
                            Nullable<double>(DEFAULT_SENSOR_POLL),
580
0
                            Nullable<uint64_t>(timestamp));
581
0
582
0
  event->SetTrusted(true);
583
0
584
0
  target->DispatchEvent(*event);
585
0
586
0
  mLastRotationRate.reset();
587
0
  mLastAccelerationIncludingGravity.reset();
588
0
  mLastAcceleration.reset();
589
0
  mLastDOMMotionEventTime = TimeStamp::Now();
590
0
}
591
592
bool
593
nsDeviceSensors::IsSensorAllowedByPref(uint32_t aType, nsIDOMWindow* aWindow)
594
0
{
595
0
  // checks "device.sensors.enabled" master pref
596
0
  if (!gPrefSensorsEnabled) {
597
0
    return false;
598
0
  }
599
0
600
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aWindow);
601
0
  nsCOMPtr<nsIDocument> doc;
602
0
  if (window) {
603
0
    doc = window->GetExtantDoc();
604
0
  }
605
0
606
0
  switch (aType) {
607
0
  case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
608
0
  case nsIDeviceSensorData::TYPE_ACCELERATION:
609
0
  case nsIDeviceSensorData::TYPE_GYROSCOPE:
610
0
    // checks "device.sensors.motion.enabled" pref
611
0
    if (!gPrefMotionSensorEnabled) {
612
0
      return false;
613
0
    } else if (doc) {
614
0
      doc->WarnOnceAbout(nsIDocument::eMotionEvent);
615
0
    }
616
0
    break;
617
0
  case nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR:
618
0
  case nsIDeviceSensorData::TYPE_ORIENTATION:
619
0
  case nsIDeviceSensorData::TYPE_ROTATION_VECTOR:
620
0
    // checks "device.sensors.orientation.enabled" pref
621
0
    if (!gPrefOrientationSensorEnabled) {
622
0
      return false;
623
0
    } else if (doc) {
624
0
      doc->WarnOnceAbout(nsIDocument::eOrientationEvent);
625
0
    }
626
0
    break;
627
0
  case nsIDeviceSensorData::TYPE_PROXIMITY:
628
0
    // checks "device.sensors.proximity.enabled" pref
629
0
    if (!gPrefProximitySensorEnabled) {
630
0
      return false;
631
0
    } else if (doc) {
632
0
      doc->WarnOnceAbout(nsIDocument::eProximityEvent, true);
633
0
    }
634
0
    break;
635
0
  case nsIDeviceSensorData::TYPE_LIGHT:
636
0
    // checks "device.sensors.ambientLight.enabled" pref
637
0
    if (!gPrefAmbientLightSensorEnabled) {
638
0
      return false;
639
0
    } else if (doc) {
640
0
      doc->WarnOnceAbout(nsIDocument::eAmbientLightEvent, true);
641
0
    }
642
0
    break;
643
0
  default:
644
0
    MOZ_ASSERT_UNREACHABLE("Device sensor type not recognised");
645
0
    return false;
646
0
  }
647
0
648
0
  if (!window) {
649
0
    return true;
650
0
  }
651
0
652
0
  return !nsContentUtils::ShouldResistFingerprinting(window->GetDocShell());
653
0
}