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.

     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 }

mercurial