Bug 734324 - implement device motion - rotation rate and acceleration. r=jdm
authorDoug Turner <dougt@dougt.org>
Tue, 13 Mar 2012 16:57:51 -0700
changeset 88994 fdb8a781820a40e2861c18a647b4706830063237
parent 88993 781e874d0ff50b2935db29dfd93dfb1e3f967ee2
child 88995 ed1d52905a6147ba68248b1b96a7b6a0372ebebf
push idunknown
push userunknown
push dateunknown
reviewersjdm
bugs734324
milestone14.0a1
Bug 734324 - implement device motion - rotation rate and acceleration. r=jdm
dom/system/nsDeviceMotion.cpp
dom/system/nsDeviceMotion.h
hal/HalSensor.h
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoEvent.java
mobile/android/base/GeckoHalDefines.java
mobile/android/base/Makefile.in
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsAppShell.cpp
widget/android/nsAppShell.h
xpcom/system/nsIDeviceMotion.idl
--- a/dom/system/nsDeviceMotion.cpp
+++ b/dom/system/nsDeviceMotion.cpp
@@ -247,18 +247,20 @@ nsDeviceMotion::DeviceMotionChanged(PRUi
         pwindow->GetOuterWindow()->IsBackground())
       continue;
 
     nsCOMPtr<nsIDOMDocument> domdoc;
     windowListeners[i]->GetDocument(getter_AddRefs(domdoc));
 
     if (domdoc) {
       nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(windowListeners[i]);
-      if (type == nsIDeviceMotionData::TYPE_ACCELERATION)
-        FireDOMMotionEvent(domdoc, target, x, y, z);
+      if (type == nsIDeviceMotionData::TYPE_ACCELERATION || 
+        type == nsIDeviceMotionData::TYPE_LINEAR_ACCELERATION || 
+        type == nsIDeviceMotionData::TYPE_GYROSCOPE )
+        FireDOMMotionEvent(domdoc, target, type, x, y, z);
       else if (type == nsIDeviceMotionData::TYPE_ORIENTATION)
         FireDOMOrientationEvent(domdoc, target, x, y, z);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -350,38 +352,53 @@ nsDeviceMotion::FireDOMOrientationEvent(
   
   target->DispatchEvent(event, &defaultActionEnabled);
 }
 
 
 void
 nsDeviceMotion::FireDOMMotionEvent(nsIDOMDocument *domdoc,
                                    nsIDOMEventTarget *target,
+                                   PRUint32 type,
                                    double x,
                                    double y,
                                    double z) {
   nsCOMPtr<nsIDOMEvent> event;
   bool defaultActionEnabled = true;
   domdoc->CreateEvent(NS_LITERAL_STRING("DeviceMotionEvent"), getter_AddRefs(event));
 
   nsCOMPtr<nsIDOMDeviceMotionEvent> me = do_QueryInterface(event);
 
   if (!me) {
     return;
 }
 
-  // Currently acceleration as determined includes gravity.
-  nsRefPtr<nsDOMDeviceAcceleration> acceleration = new nsDOMDeviceAcceleration(x, y, z);
+  nsRefPtr<nsDOMDeviceAcceleration> acceleration;
+  nsRefPtr<nsDOMDeviceAcceleration> accelerationIncluduingGravity;
+  nsRefPtr<nsDOMDeviceRotationRate> rotationRate;
+
+  switch (type) {
+  case nsIDeviceMotionData::TYPE_LINEAR_ACCELERATION:
+      acceleration = new nsDOMDeviceAcceleration(x, y, z);
+      break;
+  case nsIDeviceMotionData::TYPE_ACCELERATION:
+      accelerationIncluduingGravity = new nsDOMDeviceAcceleration(x, y, z);
+      break;
+  case nsIDeviceMotionData::TYPE_GYROSCOPE:
+      rotationRate = new nsDOMDeviceRotationRate(x, y, z);
+      break;
+  }
+
 
   me->InitDeviceMotionEvent(NS_LITERAL_STRING("devicemotion"),
                             true,
                             false,
-                            nsnull,
                             acceleration,
-                            nsnull,
+                            accelerationIncluduingGravity,
+                            rotationRate,
                             DEFAULT_SENSOR_POLL);
 
   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
   if (privateEvent)
     privateEvent->SetTrusted(true);
   
   target->DispatchEvent(event, &defaultActionEnabled);
 }
--- a/dom/system/nsDeviceMotion.h
+++ b/dom/system/nsDeviceMotion.h
@@ -82,16 +82,17 @@ private:
   void FireDOMOrientationEvent(class nsIDOMDocument *domDoc, 
                                class nsIDOMEventTarget *target,
                                double alpha,
                                double beta,
                                double gamma);
 
   void FireDOMMotionEvent(class nsIDOMDocument *domDoc, 
                           class nsIDOMEventTarget *target,
+                          PRUint32 type,
                           double x,
                           double y,
                           double z);
   bool mEnabled;
 
   virtual void Startup()  = 0;
   virtual void Shutdown() = 0;
 };
--- a/hal/HalSensor.h
+++ b/hal/HalSensor.h
@@ -49,16 +49,18 @@ namespace hal {
  * Enumeration of sensor types.  They are used to specify type while
  * register or unregister an observer for a sensor of given type.
  */
 enum SensorType {
   SENSOR_UNKNOWN = -1,
   SENSOR_ORIENTATION,
   SENSOR_ACCELERATION,
   SENSOR_PROXIMITY,
+  SENSOR_LINEAR_ACCELERATION,
+  SENSOR_GYROSCOPE,
   NUM_SENSOR_TYPE
 };
 
 class SensorData;
 
 typedef Observer<SensorData> ISensorObserver;
 
 }
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -124,16 +124,22 @@ public class GeckoAppShell
     /* Time (in System.nanoTime() units) when the currently-playing vibration
      * is scheduled to end.  This value is valid only when
      * sVibrationMaybePlaying is true. */
     private static long sVibrationEndTime = 0;
 
     /* Default value of how fast we should hint the Android sensors. */
     private static int sDefaultSensorHint = 100;
 
+    private static Sensor gAccelerometerSensor = null;
+    private static Sensor gLinearAccelerometerSensor = null;
+    private static Sensor gGyroscopeSensor = null;
+    private static Sensor gOrientationSensor = null;
+    private static Sensor gProximitySensor = null;
+
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void nativeInit();
     public static native void nativeRun(String args);
 
     // helper methods
     //    public static native void setSurfaceView(GeckoSurfaceView sv);
@@ -531,41 +537,16 @@ public class GeckoAppShell
 
     // Signal the Java thread that it's time to wake up
     public static void acknowledgeEventSync() {
         CountDownLatch tmp = sGeckoPendingAcks;
         if (tmp != null)
             tmp.countDown();
     }
 
-    static Sensor gAccelerometerSensor = null;
-    static Sensor gOrientationSensor = null;
-
-    public static void enableDeviceMotion(boolean enable) {
-        LayerView v = GeckoApp.mAppContext.getLayerController().getView();
-        SensorManager sm = (SensorManager) v.getContext().getSystemService(Context.SENSOR_SERVICE);
-
-        if (gAccelerometerSensor == null || gOrientationSensor == null) {
-            gAccelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-            gOrientationSensor   = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
-        }
-
-        if (enable) {
-            if (gAccelerometerSensor != null)
-                sm.registerListener(GeckoApp.mAppContext, gAccelerometerSensor, sDefaultSensorHint);
-            if (gOrientationSensor != null)
-                sm.registerListener(GeckoApp.mAppContext, gOrientationSensor,   sDefaultSensorHint);
-        } else {
-            if (gAccelerometerSensor != null)
-                sm.unregisterListener(GeckoApp.mAppContext, gAccelerometerSensor);
-            if (gOrientationSensor != null)
-                sm.unregisterListener(GeckoApp.mAppContext, gOrientationSensor);
-        }
-    }
-
     public static void enableLocation(final boolean enable) {
         getMainHandler().post(new Runnable() { 
                 public void run() {
                     LayerView v = GeckoApp.mAppContext.getLayerController().getView();
 
                     LocationManager lm = (LocationManager)
                         GeckoApp.mAppContext.getSystemService(Context.LOCATION_SERVICE);
 
@@ -583,46 +564,87 @@ public class GeckoAppShell
                         lm.requestLocationUpdates(provider, 100, (float).5, GeckoApp.mAppContext, l);
                     } else {
                         lm.removeUpdates(GeckoApp.mAppContext);
                     }
                 }
             });
     }
 
-    /*
-     * Keep these values consistent with |SensorType| in Hal.h
-     */
-    private static final int SENSOR_ORIENTATION = 1;
-    private static final int SENSOR_ACCELERATION = 2;
-    private static final int SENSOR_PROXIMITY = 3;
-
-    private static Sensor gProximitySensor = null;
-
     public static void enableSensor(int aSensortype) {
         SensorManager sm = (SensorManager)
             GeckoApp.mAppContext.getSystemService(Context.SENSOR_SERVICE);
 
         switch(aSensortype) {
-        case SENSOR_PROXIMITY:
+        case GeckoHalDefines.SENSOR_ORIENTATION:
+            if(gOrientationSensor == null)
+                gOrientationSensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+            if (gOrientationSensor != null)
+                sm.registerListener(GeckoApp.mAppContext, gOrientationSensor, sDefaultSensorHint);
+            break;
+
+        case GeckoHalDefines.SENSOR_ACCELERATION:
+            if(gAccelerometerSensor == null)
+                gAccelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+            if (gAccelerometerSensor != null)
+                sm.registerListener(GeckoApp.mAppContext, gAccelerometerSensor, sDefaultSensorHint);
+            break;
+
+        case GeckoHalDefines.SENSOR_PROXIMITY:
             if(gProximitySensor == null)
                 gProximitySensor = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
-            sm.registerListener(GeckoApp.mAppContext, gProximitySensor,
-                                sDefaultSensorHint);
+            if (gProximitySensor != null)
+                sm.registerListener(GeckoApp.mAppContext, gProximitySensor, sDefaultSensorHint);
             break;
+
+        case GeckoHalDefines.SENSOR_LINEAR_ACCELERATION:
+            if(gLinearAccelerometerSensor == null)
+                gLinearAccelerometerSensor = sm.getDefaultSensor(10);
+            if (gLinearAccelerometerSensor != null)
+                sm.registerListener(GeckoApp.mAppContext, gLinearAccelerometerSensor, sDefaultSensorHint);
+            break;
+
+        case GeckoHalDefines.SENSOR_GYROSCOPE:
+            if(gGyroscopeSensor == null)
+                gGyroscopeSensor = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+            if (gGyroscopeSensor != null)
+                sm.registerListener(GeckoApp.mAppContext, gGyroscopeSensor, sDefaultSensorHint);
+            break;
+
         }
     }
 
     public static void disableSensor(int aSensortype) {
         SensorManager sm = (SensorManager)
             GeckoApp.mAppContext.getSystemService(Context.SENSOR_SERVICE);
 
-        switch(aSensortype) {
-        case SENSOR_PROXIMITY:
-            sm.unregisterListener(GeckoApp.mAppContext, gProximitySensor);
+        switch (aSensortype) {
+        case GeckoHalDefines.SENSOR_ORIENTATION:
+            if (gOrientationSensor != null)
+                sm.unregisterListener(GeckoApp.mAppContext, gOrientationSensor);
+            break;
+
+        case GeckoHalDefines.SENSOR_ACCELERATION:
+            if (gAccelerometerSensor != null)
+                sm.unregisterListener(GeckoApp.mAppContext, gAccelerometerSensor);
+            break;
+
+        case GeckoHalDefines.SENSOR_PROXIMITY:
+            if (gProximitySensor != null)
+                sm.unregisterListener(GeckoApp.mAppContext, gProximitySensor);
+            break;
+
+        case GeckoHalDefines.SENSOR_LINEAR_ACCELERATION:
+            if (gLinearAccelerometerSensor != null)
+                sm.unregisterListener(GeckoApp.mAppContext, gLinearAccelerometerSensor);
+            break;
+
+        case GeckoHalDefines.SENSOR_GYROSCOPE:
+            if (gGyroscopeSensor != null)
+                sm.unregisterListener(GeckoApp.mAppContext, gGyroscopeSensor);
             break;
         }
     }
 
     public static void moveTaskToBack() {
         GeckoApp.mAppContext.moveTaskToBack(true);
     }
 
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -47,34 +47,35 @@ import android.graphics.*;
 import android.widget.*;
 import android.hardware.*;
 import android.location.*;
 import android.util.FloatMath;
 import android.util.DisplayMetrics;
 import android.graphics.PointF;
 import android.text.format.Time;
 import android.os.SystemClock;
+import java.lang.Math;
 import java.lang.System;
 
 import android.util.Log;
 
 /* We're not allowed to hold on to most events given to us
  * so we save the parts of the events we want to use in GeckoEvent.
  * Fields have different meanings depending on the event type.
  */
 
 public class GeckoEvent {
     private static final String LOGTAG = "GeckoEvent";
 
     private static final int INVALID = -1;
     private static final int NATIVE_POKE = 0;
     private static final int KEY_EVENT = 1;
     private static final int MOTION_EVENT = 2;
-    private static final int ORIENTATION_EVENT = 3;
-    private static final int ACCELERATION_EVENT = 4;
+    private static final int SENSOR_EVENT = 3;
+    private static final int UNUSED1_EVENT = 4;
     private static final int LOCATION_EVENT = 5;
     private static final int IME_EVENT = 6;
     private static final int DRAW = 7;
     private static final int SIZE_CHANGED = 8;
     private static final int ACTIVITY_STOPPING = 9;
     private static final int ACTIVITY_PAUSING = 10;
     private static final int ACTIVITY_SHUTDOWN = 11;
     private static final int LOAD_URI = 12;
@@ -116,17 +117,16 @@ public class GeckoEvent {
     public Point[] mPoints;
     public int[] mPointIndicies;
     public int mPointerIndex; // index of the point that has changed
     public float[] mOrientations;
     public float[] mPressures;
     public Point[] mPointRadii;
     public Rect mRect;
     public double mX, mY, mZ;
-    public double mAlpha, mBeta, mGamma;
     public double mDistance;
 
     public int mMetaState, mFlags;
     public int mKeyCode, mUnicodeChar;
     public int mOffset, mCount;
     public String mCharacters, mCharactersExtra;
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
@@ -275,35 +275,56 @@ public class GeckoEvent {
         } catch(Exception ex) {
             Log.e(LOGTAG, "Error creating motion point " + index, ex);
             mPointRadii[index] = new Point(0, 0);
             mPoints[index] = new Point(0, 0);
         }
     }
 
     public static GeckoEvent createSensorEvent(SensorEvent s) {
+        int sensor_type = s.sensor.getType();
         GeckoEvent event = null;
-        int sensor_type = s.sensor.getType();
- 
+
         switch(sensor_type) {
+
         case Sensor.TYPE_ACCELEROMETER:
-            event = new GeckoEvent(ACCELERATION_EVENT);
+            event = new GeckoEvent(SENSOR_EVENT);
+            event.mFlags = GeckoHalDefines.SENSOR_ACCELERATION;
+            event.mX = s.values[0];
+            event.mY = s.values[1];
+            event.mZ = s.values[2];
+            break;
+
+        case 10 /* Requires API Level 9, so just use the raw value - Sensor.TYPE_LINEAR_ACCELEROMETER*/ :
+            event = new GeckoEvent(SENSOR_EVENT);
+            event.mFlags = GeckoHalDefines.SENSOR_LINEAR_ACCELERATION;
             event.mX = s.values[0];
             event.mY = s.values[1];
             event.mZ = s.values[2];
             break;
-            
+
         case Sensor.TYPE_ORIENTATION:
-            event = new GeckoEvent(ORIENTATION_EVENT);
-            event.mAlpha = s.values[0];
-            event.mBeta  = s.values[1];
-            event.mGamma = s.values[2];
+            event = new GeckoEvent(SENSOR_EVENT);
+            event.mFlags = GeckoHalDefines.SENSOR_ORIENTATION;
+            event.mX = s.values[0];
+            event.mY = s.values[1];
+            event.mZ = s.values[2];
+            break;
+
+        case Sensor.TYPE_GYROSCOPE:
+            event = new GeckoEvent(SENSOR_EVENT);
+            event.mFlags = GeckoHalDefines.SENSOR_GYROSCOPE;
+            event.mX = Math.toDegrees(s.values[0]);
+            event.mY = Math.toDegrees(s.values[1]);
+            event.mZ = Math.toDegrees(s.values[2]);
             break;
 
         case Sensor.TYPE_PROXIMITY:
+            // bug 734854 - maybe we can get rid of this event.  is
+            // values[1] and values[2] valid?
             event = new GeckoEvent(PROXIMITY_EVENT);
             event.mDistance = s.values[0];
             break;
         }
         return event;
     }
 
     public static GeckoEvent createLocationEvent(Location l) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/GeckoHalDefines.java
@@ -0,0 +1,49 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+public class GeckoHalDefines
+{
+    /*
+     * Keep these values consistent with |SensorType| in Hal.h
+    */
+    public static final int SENSOR_ORIENTATION = 0;
+    public static final int SENSOR_ACCELERATION = 1;
+    public static final int SENSOR_PROXIMITY = 2;
+    public static final int SENSOR_LINEAR_ACCELERATION = 3;
+    public static final int SENSOR_GYROSCOPE = 4;
+};
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -82,16 +82,17 @@ FENNEC_JAVA_FILES = \
   GeckoAppShell.java \
   GeckoAsyncTask.java \
   GeckoBatteryManager.java \
   GeckoBackgroundThread.java \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoEventListener.java \
   GeckoEventResponder.java \
+  GeckoHalDefines.java \
   GeckoInputConnection.java \
 	GeckoMessageReceiver.java \
   GeckoPreferences.java \
   GeckoProfile.java \
   GeckoStateListDrawable.java \
   GeckoThread.java \
   GlobalHistory.java \
   LinkPreference.java \
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -106,24 +106,19 @@ AndroidBridge::Init(JNIEnv *jEnv,
     mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
 
     jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
     jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Z)V");
     jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
     jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;III)V");
     jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
 
-    jEnableDeviceMotion = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableDeviceMotion", "(Z)V");
     jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
-    jEnableSensor =
-        (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass,
-                                            "enableSensor", "(I)V");
-    jDisableSensor =
-        (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass,
-                                            "disableSensor", "(I)V");
+    jEnableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableSensor", "(I)V");
+    jDisableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableSensor", "(I)V");
     jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
     jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
     jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
     jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
     jGetHandlersForURL = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
     jOpenUriExternal = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
     jGetMimeTypeFromExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
     jGetExtensionFromMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
@@ -306,47 +301,65 @@ AndroidBridge::AcknowledgeEventSync()
     env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
 }
 
 void
 AndroidBridge::EnableDeviceMotion(bool aEnable)
 {
     ALOG_BRIDGE("AndroidBridge::EnableDeviceMotion");
 
-    JNIEnv *env = GetJNIEnv();
-    if (!env)
-        return;
+    // bug 734855 - we probably can make this finer grain based on
+    // the DOM APIs that are being invoked.
+    if (aEnable) {
+        EnableSensor(hal::SENSOR_ORIENTATION);
+        EnableSensor(hal::SENSOR_ACCELERATION);
+        EnableSensor(hal::SENSOR_LINEAR_ACCELERATION);
+        EnableSensor(hal::SENSOR_GYROSCOPE);
+    }
+    else {
+        DisableSensor(hal::SENSOR_ORIENTATION);
+        DisableSensor(hal::SENSOR_ACCELERATION);
+        DisableSensor(hal::SENSOR_LINEAR_ACCELERATION);
+        DisableSensor(hal::SENSOR_GYROSCOPE);
+    }
+}
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableDeviceMotion, aEnable);
-}
 
 void
 AndroidBridge::EnableLocation(bool aEnable)
 {
     ALOG_BRIDGE("AndroidBridge::EnableLocation");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
-    
+
+    AutoLocalJNIFrame jniFrame(env, 1);
     env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable);
 }
 
 void
 AndroidBridge::EnableSensor(int aSensorType) {
     ALOG_BRIDGE("AndroidBridge::EnableSensor");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor,
-                                  aSensorType);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env, 1);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, aSensorType);
 }
 
 void
 AndroidBridge::DisableSensor(int aSensorType) {
     ALOG_BRIDGE("AndroidBridge::DisableSensor");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor,
-                                  aSensorType);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+    AutoLocalJNIFrame jniFrame(env, 1);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor, aSensorType);
 }
 
 void
 AndroidBridge::ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen,
                                     int aSelStart, int aSelLen)
 {
     ALOG_BRIDGE("AndroidBridge::ReturnIMEQueryResult");
 
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -419,17 +419,16 @@ protected:
     nsCOMArray<nsIRunnable> mRunnableQueue;
 
     // other things
     jmethodID jNotifyIME;
     jmethodID jNotifyIMEEnabled;
     jmethodID jNotifyIMEChange;
     jmethodID jNotifyScreenShot;
     jmethodID jAcknowledgeEventSync;
-    jmethodID jEnableDeviceMotion;
     jmethodID jEnableLocation;
     jmethodID jEnableSensor;
     jmethodID jDisableSensor;
     jmethodID jReturnIMEQueryResult;
     jmethodID jNotifyAppShellReady;
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -44,19 +44,16 @@ jclass AndroidGeckoEvent::jGeckoEventCla
 jfieldID AndroidGeckoEvent::jActionField = 0;
 jfieldID AndroidGeckoEvent::jTypeField = 0;
 jfieldID AndroidGeckoEvent::jTimeField = 0;
 jfieldID AndroidGeckoEvent::jPoints = 0;
 jfieldID AndroidGeckoEvent::jPointIndicies = 0;
 jfieldID AndroidGeckoEvent::jPressures = 0;
 jfieldID AndroidGeckoEvent::jPointRadii = 0;
 jfieldID AndroidGeckoEvent::jOrientations = 0;
-jfieldID AndroidGeckoEvent::jAlphaField = 0;
-jfieldID AndroidGeckoEvent::jBetaField = 0;
-jfieldID AndroidGeckoEvent::jGammaField = 0;
 jfieldID AndroidGeckoEvent::jXField = 0;
 jfieldID AndroidGeckoEvent::jYField = 0;
 jfieldID AndroidGeckoEvent::jZField = 0;
 jfieldID AndroidGeckoEvent::jDistanceField = 0;
 jfieldID AndroidGeckoEvent::jRectField = 0;
 jfieldID AndroidGeckoEvent::jNativeWindowField = 0;
 
 jfieldID AndroidGeckoEvent::jCharactersField = 0;
@@ -143,19 +140,16 @@ AndroidGeckoEvent::InitGeckoEventClass(J
     jActionField = getField("mAction", "I");
     jTypeField = getField("mType", "I");
     jTimeField = getField("mTime", "J");
     jPoints = getField("mPoints", "[Landroid/graphics/Point;");
     jPointIndicies = getField("mPointIndicies", "[I");
     jOrientations = getField("mOrientations", "[F");
     jPressures = getField("mPressures", "[F");
     jPointRadii = getField("mPointRadii", "[Landroid/graphics/Point;");
-    jAlphaField = getField("mAlpha", "D");
-    jBetaField = getField("mBeta", "D");
-    jGammaField = getField("mGamma", "D");
     jXField = getField("mX", "D");
     jYField = getField("mY", "D");
     jZField = getField("mZ", "D");
     jDistanceField = getField("mDistance", "D");
     jRectField = getField("mRect", "Landroid/graphics/Rect;");
 
     jCharactersField = getField("mCharacters", "Ljava/lang/String;");
     jCharactersExtraField = getField("mCharactersExtra", "Ljava/lang/String;");
@@ -422,27 +416,22 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
                     jenv->GetIntField(jobj, jRangeBackColorField);
             }
             break;
 
         case DRAW:
             ReadRectField(jenv);
             break;
 
-        case ORIENTATION_EVENT:
-            mAlpha = jenv->GetDoubleField(jobj, jAlphaField);
-            mBeta = jenv->GetDoubleField(jobj, jBetaField);
-            mGamma = jenv->GetDoubleField(jobj, jGammaField);
-            break;
-
-       case ACCELERATION_EVENT:
-            mX = jenv->GetDoubleField(jobj, jXField);
-            mY = jenv->GetDoubleField(jobj, jYField);
-            mZ = jenv->GetDoubleField(jobj, jZField);
-            break;
+        case SENSOR_EVENT:
+             mX = jenv->GetDoubleField(jobj, jXField);
+             mY = jenv->GetDoubleField(jobj, jYField);
+             mZ = jenv->GetDoubleField(jobj, jZField);
+             mFlags = jenv->GetIntField(jobj, jFlagsField);
+             break;
 
         case LOCATION_EVENT: {
             jobject location = jenv->GetObjectField(jobj, jLocationField);
             mGeoPosition = AndroidLocation::CreateGeoPosition(jenv, location);
             break;
         }
 
         case LOAD_URI: {
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -415,19 +415,16 @@ public:
     int Action() { return mAction; }
     int Type() { return mType; }
     int64_t Time() { return mTime; }
     nsTArray<nsIntPoint> Points() { return mPoints; }
     nsTArray<int> PointIndicies() { return mPointIndicies; }
     nsTArray<float> Pressures() { return mPressures; }
     nsTArray<float> Orientations() { return mOrientations; }
     nsTArray<nsIntPoint> PointRadii() { return mPointRadii; }
-    double Alpha() { return mAlpha; }
-    double Beta() { return mBeta; }
-    double Gamma() { return mGamma; }
     double X() { return mX; }
     double Y() { return mY; }
     double Z() { return mZ; }
     double Distance() { return mDistance; }
     const nsIntRect& Rect() { return mRect; }
     nsAString& Characters() { return mCharacters; }
     nsAString& CharactersExtra() { return mCharactersExtra; }
     int KeyCode() { return mKeyCode; }
@@ -455,17 +452,16 @@ protected:
     nsTArray<float> mOrientations;
     nsTArray<float> mPressures;
     nsIntRect mRect;
     int mFlags, mMetaState;
     int mKeyCode, mUnicodeChar;
     int mOffset, mCount;
     int mRangeType, mRangeStyles;
     int mRangeForeColor, mRangeBackColor;
-    double mAlpha, mBeta, mGamma;
     double mX, mY, mZ;
     double mDistance;
     int mPointerIndex;
     nsString mCharacters, mCharactersExtra;
     nsRefPtr<nsGeoPosition> mGeoPosition;
     double mBandwidth;
     bool mCanBeMetered;
 
@@ -489,19 +485,16 @@ protected:
     static jfieldID jActionField;
     static jfieldID jTypeField;
     static jfieldID jTimeField;
     static jfieldID jPoints;
     static jfieldID jPointIndicies;
     static jfieldID jOrientations;
     static jfieldID jPressures;
     static jfieldID jPointRadii;
-    static jfieldID jAlphaField;
-    static jfieldID jBetaField;
-    static jfieldID jGammaField;
     static jfieldID jXField;
     static jfieldID jYField;
     static jfieldID jZField;
     static jfieldID jDistanceField;
     static jfieldID jRectField;
     static jfieldID jNativeWindowField;
 
     static jfieldID jCharactersField;
@@ -522,18 +515,18 @@ protected:
     static jfieldID jBandwidthField;
     static jfieldID jCanBeMeteredField;
 
 public:
     enum {
         NATIVE_POKE = 0,
         KEY_EVENT = 1,
         MOTION_EVENT = 2,
-        ORIENTATION_EVENT = 3,
-        ACCELERATION_EVENT = 4,
+        SENSOR_EVENT = 3,
+        UNUSED1_EVENT = 4,
         LOCATION_EVENT = 5,
         IME_EVENT = 6,
         DRAW = 7,
         SIZE_CHANGED = 8,
         ACTIVITY_STOPPING = 9,
         ACTIVITY_PAUSING = 10,
         ACTIVITY_SHUTDOWN = 11,
         LOAD_URI = 12,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -91,17 +91,17 @@ nsAppShell *nsAppShell::gAppShell = nsnu
 NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
 
 nsAppShell::nsAppShell()
     : mQueueLock("nsAppShell.mQueueLock"),
       mCondLock("nsAppShell.mCondLock"),
       mQueueCond(mCondLock, "nsAppShell.mQueueCond"),
       mNumDraws(0),
       mNumViewports(0),
-      mPendingOrientationEvents(false)
+      mPendingSensorEvents(false)
 {
     gAppShell = this;
 }
 
 nsAppShell::~nsAppShell()
 {
     gAppShell = nsnull;
 }
@@ -331,30 +331,51 @@ nsAppShell::ProcessNextNativeEvent(bool 
         NativeEventCallback();
         break;
 
     case AndroidGeckoEvent::SENSOR_ACCURACY:
         if (curEvent->Flags() == 0)
             gDeviceMotionSystem->NeedsCalibration();
         break;
 
-    case AndroidGeckoEvent::ACCELERATION_EVENT:
-        gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_ACCELERATION,
-                                                 -curEvent->X(),
-                                                 curEvent->Y(),
-                                                 curEvent->Z());
-        break;
+    case AndroidGeckoEvent::SENSOR_EVENT:
+        mPendingSensorEvents = false;
+        switch (curEvent->Flags()) {
+        case hal::SENSOR_ORIENTATION:
+            gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_ORIENTATION,
+                                                     curEvent->X(),
+                                                     -curEvent->Y(),
+                                                     -curEvent->Z());
+            break;
+
+        case hal::SENSOR_ACCELERATION:
+            gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_ACCELERATION,
+                                                     -curEvent->X(),
+                                                     curEvent->Y(),
+                                                     curEvent->Z());
+            break;
 
-    case AndroidGeckoEvent::ORIENTATION_EVENT:
-        gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_ORIENTATION,
-                                                 curEvent->Alpha(),
-                                                 -curEvent->Beta(),
-                                                 -curEvent->Gamma());
-        mPendingOrientationEvents = false;
-        break;
+        case hal::SENSOR_LINEAR_ACCELERATION:
+            gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_LINEAR_ACCELERATION,
+                                                     -curEvent->X(),
+                                                     curEvent->Y(),
+                                                     curEvent->Z());
+            break;
+
+        case hal::SENSOR_GYROSCOPE:
+            gDeviceMotionSystem->DeviceMotionChanged(nsIDeviceMotionData::TYPE_GYROSCOPE,
+                                                     -curEvent->X(),
+                                                     curEvent->Y(),
+                                                     curEvent->Z());
+            break;
+
+        default:
+            __android_log_print(ANDROID_LOG_ERROR, "Gecko", "### SENSOR_EVENT fired, but type wasn't known %d", curEvent->Flags());
+        }
+         break;
 
     case AndroidGeckoEvent::LOCATION_EVENT: {
         if (!gLocationCallback)
             break;
 
         nsGeoPosition* p = curEvent->GeoPosition();
         if (p)
             gLocationCallback->Update(curEvent->GeoPosition());
@@ -598,20 +619,20 @@ nsAppShell::PostEvent(AndroidGeckoEvent 
             AndroidGeckoEvent *event;
             for (int i = mEventQueue.Length()-1; i >=1; i--) {
                 event = mEventQueue[i];
                 if (event->Type() == AndroidGeckoEvent::SURFACE_CREATED) {
                     mEventQueue.RemoveElementAt(i);
                     delete event;
                 }
             }
-        } else if (ae->Type() == AndroidGeckoEvent::ORIENTATION_EVENT) {
-            if (!mPendingOrientationEvents)
-                 mEventQueue.AppendElement(ae);
-            mPendingOrientationEvents = true;
+        } else if (ae->Type() == AndroidGeckoEvent::SENSOR_EVENT) {
+            if (!mPendingSensorEvents)
+                mEventQueue.AppendElement(ae);
+            mPendingSensorEvents = true;
         } else {
             mEventQueue.AppendElement(ae);
         }
 
         if (ae->Type() == AndroidGeckoEvent::DRAW) {
             mNumDraws++;
             mLastDrawEvent = ae;
         } else if (ae->Type() == AndroidGeckoEvent::VIEWPORT) {
--- a/widget/android/nsAppShell.h
+++ b/widget/android/nsAppShell.h
@@ -105,13 +105,13 @@ protected:
     mozilla::AndroidGeckoEvent *mLastDrawEvent;
     nsTArray<mozilla::AndroidGeckoEvent *> mEventQueue;
     nsInterfaceHashtable<nsStringHashKey, nsIObserver> mObserversHash;
 
     mozilla::AndroidGeckoEvent *PopNextEvent();
     mozilla::AndroidGeckoEvent *PeekNextEvent();
 
     nsCOMPtr<nsIAndroidBrowserApp> mBrowserApp;
-    bool mPendingOrientationEvents;
+    bool mPendingSensorEvents;
 };
 
 #endif // nsAppShell_h__
 
--- a/xpcom/system/nsIDeviceMotion.idl
+++ b/xpcom/system/nsIDeviceMotion.idl
@@ -38,16 +38,18 @@
 
 interface nsIDOMWindow;
 
 [scriptable, uuid(1B406E32-CF42-471E-A470-6FD600BF4C7B)]
 interface nsIDeviceMotionData : nsISupports
 {
   const unsigned long TYPE_ACCELERATION = 0;
   const unsigned long TYPE_ORIENTATION = 1;
+  const unsigned long TYPE_LINEAR_ACCELERATION = 2;
+  const unsigned long TYPE_GYROSCOPE = 3;
 
   readonly attribute unsigned long type;
 
   readonly attribute double x;
   readonly attribute double y;
   readonly attribute double z;
 };