dom/system/nsDeviceSensors.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial