Bug 720795 - Screen Orientation API reading and event implementation in Android. r=dougt
authorMounir Lamouri <mounir.lamouri@gmail.com>
Thu, 09 Feb 2012 11:29:44 +0100
changeset 89374 4a763183482f8bdfbafd63f05bb4798c0c188646
parent 89373 e965486f4b5079ab6cd0e386a4d8861b53717de8
child 89375 79121553f728dc598fb7cda39fa069c9c2dd56b3
push id783
push userlsblakk@mozilla.com
push dateTue, 24 Apr 2012 17:33:42 +0000
treeherdermozilla-beta@11faed19f136 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt
bugs720795
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 720795 - Screen Orientation API reading and event implementation in Android. r=dougt
dom/base/ScreenOrientation.h
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/GeckoEvent.java
embedding/android/GeckoScreenOrientationListener.java
embedding/android/Makefile.in
hal/Makefile.in
hal/android/AndroidHal.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoEvent.java
mobile/android/base/GeckoScreenOrientationListener.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
--- a/dom/base/ScreenOrientation.h
+++ b/dom/base/ScreenOrientation.h
@@ -3,16 +3,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ScreenOrientation_h
 #define mozilla_dom_ScreenOrientation_h
 
 namespace mozilla {
 namespace dom {
 
+// Make sure that any change here is also made in
+// * mobile/android/base/GeckoScreenOrientationListener.java
+// * embedding/android/GeckoScreenOrientationListener.java
 enum ScreenOrientation {
   eScreenOrientation_Current            = 0,
   eScreenOrientation_PortraitPrimary    = 1,  // 00000001
   eScreenOrientation_PortraitSecondary  = 2,  // 00000010
   eScreenOrientation_Portrait           = 3,  // 00000011
   eScreenOrientation_LandscapePrimary   = 4,  // 00000100
   eScreenOrientation_LandscapeSecondary = 8,  // 00001000
   eScreenOrientation_Landscape          = 12, // 00001100
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -507,16 +507,17 @@ abstract public class GeckoApp
         // Whatever we do here should be fast, because we're blocking
         // the next activity from showing up until we finish.
 
         // onPause will be followed by either onResume or onStop.
         super.onPause();
 
         unregisterReceiver(mConnectivityReceiver);
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
     }
 
     @Override
     public void onResume()
     {
         Log.i(LOG_FILE_NAME, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
@@ -526,16 +527,17 @@ abstract public class GeckoApp
 
         // Just in case. Normally we start in onNewIntent
         if (checkLaunchState(LaunchState.PreLaunch) ||
             checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
         GeckoNetworkManager.getInstance().start();
+        GeckoScreenOrientationListener.getInstance().start();
     }
 
     @Override
     public void onStop()
     {
         Log.i(LOG_FILE_NAME, "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
@@ -581,16 +583,17 @@ abstract public class GeckoApp
 
         if (SmsManager.getInstance() != null) {
             SmsManager.getInstance().stop();
             if (isFinishing())
                 SmsManager.getInstance().shutdown();
         }
 
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
 
         super.onDestroy();
 
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
     public void onConfigurationChanged(android.content.res.Configuration newConfig)
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -1824,9 +1824,21 @@ public class GeckoAppShell
     }
 
     public static void disableNetworkNotifications() {
         GeckoNetworkManager.getInstance().disableNotifications();
     }
 
     // This is only used in Native Fennec.
     public static void setPreventPanning(final boolean aPreventPanning) { }
+
+    public static short getScreenOrientation() {
+        return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
+    }
+
+    public static void enableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().enableNotifications();
+    }
+
+    public static void disableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().disableNotifications();
+    }
 }
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -75,16 +75,17 @@ public class GeckoEvent {
     public static final int GECKO_EVENT_SYNC = 15;
     public static final int ACTIVITY_START = 17;
     public static final int SAVE_STATE = 18;
     public static final int BROADCAST = 19;
     public static final int VIEWPORT = 20;
     public static final int VISITED = 21;
     public static final int NETWORK_CHANGED = 22;
     public static final int PROXIMITY_EVENT = 23;
+    public static final int SCREENORIENTATION_CHANGED = 24;
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
@@ -121,16 +122,18 @@ public class GeckoEvent {
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
     public Location mLocation;
     public Address  mAddress;
 
     public double mBandwidth;
     public boolean mCanBeMetered;
 
+    public short mScreenOrientation;
+
     public int mNativeWindow;
 
     public GeckoEvent() {
         mType = NATIVE_POKE;
     }
 
     public GeckoEvent(int evType) {
         mType = evType;
@@ -329,9 +332,14 @@ public class GeckoEvent {
         mCharacters = uri;
     }
 
     public GeckoEvent(double bandwidth, boolean canBeMetered) {
         mType = NETWORK_CHANGED;
         mBandwidth = bandwidth;
         mCanBeMetered = canBeMetered;
     }
+
+    public GeckoEvent(short aScreenOrientation) {
+        mType = SCREENORIENTATION_CHANGED;
+        mScreenOrientation = aScreenOrientation;
+    }
 }
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoScreenOrientationListener.java
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+public class GeckoScreenOrientationListener
+{
+  static class OrientationEventListenerImpl extends OrientationEventListener {
+    public OrientationEventListenerImpl(Context c) {
+      super(c);
+    }
+
+    @Override
+    public void onOrientationChanged(int aOrientation) {
+      GeckoScreenOrientationListener.getInstance().updateScreenOrientation();
+    }
+  }
+
+  static private GeckoScreenOrientationListener sInstance = null;
+
+  // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
+  static public final short eScreenOrientation_PortraitPrimary    = 1;
+  static public final short eScreenOrientation_PortraitSecondary  = 2;
+  static public final short eScreenOrientation_LandscapePrimary   = 4;
+  static public final short eScreenOrientation_LandscapeSecondary = 8;
+
+  private short mOrientation;
+  private OrientationEventListenerImpl mListener = null;
+
+  // Whether the listener should be listening to changes.
+  private boolean mShouldBeListening = false;
+  // Whether the listener should notify Gecko that a change happened.
+  private boolean mShouldNotify      = false;
+
+  private GeckoScreenOrientationListener() {
+    mListener = new OrientationEventListenerImpl(GeckoApp.mAppContext);
+  }
+
+  public static GeckoScreenOrientationListener getInstance() {
+    if (sInstance == null) {
+      sInstance = new GeckoScreenOrientationListener();
+    }
+
+    return sInstance;
+  }
+
+  public void start() {
+    mShouldBeListening = true;
+    updateScreenOrientation();
+
+    if (mShouldNotify) {
+      startListening();
+    }
+  }
+
+  public void stop() {
+    mShouldBeListening = false;
+
+    if (mShouldNotify) {
+      stopListening();
+    }
+  }
+
+  public void enableNotifications() {
+    updateScreenOrientation();
+    mShouldNotify = true;
+
+    if (mShouldBeListening) {
+      startListening();
+    }
+  }
+
+  public void disableNotifications() {
+    mShouldNotify = false;
+
+    if (mShouldBeListening) {
+      stopListening();
+    }
+  }
+
+  private void startListening() {
+    mListener.enable();
+  }
+
+  private void stopListening() {
+    mListener.disable();
+  }
+
+  // NOTE: this is public so OrientationEventListenerImpl can access it.
+  // Unfortunately, Java doesn't know about friendship.
+  public void updateScreenOrientation() {
+    int rotation = GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getRotation();
+    short previousOrientation = mOrientation;
+
+    if (rotation == Surface.ROTATION_0) {
+      mOrientation = eScreenOrientation_PortraitPrimary;
+    } else if (rotation == Surface.ROTATION_180) {
+      mOrientation = eScreenOrientation_PortraitSecondary;
+    } else if (rotation == Surface.ROTATION_270) {
+      mOrientation = eScreenOrientation_LandscapeSecondary;
+    } else if (rotation == Surface.ROTATION_90) {
+      mOrientation = eScreenOrientation_LandscapePrimary;
+    } else {
+      Log.e("GeckoScreenOrientationListener", "Unexpected value received! (" + rotation + ")");
+      return;
+    }
+
+    if (mShouldNotify && mOrientation != previousOrientation) {
+      GeckoAppShell.sendEventToGecko(new GeckoEvent(mOrientation));
+    }
+  }
+
+  public short getScreenOrientation() {
+    return mOrientation;
+  }
+}
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -52,16 +52,17 @@ JAVAFILES = \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceInfo.java \
   GeckoBatteryManager.java \
   VideoPlayer.java \
   GeckoNetworkManager.java \
+  GeckoScreenOrientationListener.java \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 JAVAFILES += GeckoSmsManager.java
 endif
 
 PROCESSEDJAVAFILES = \
   App.java \
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -64,17 +64,16 @@ EXPORTS_mozilla = \
   HalSensor.h \
   HalTypes.h \
   $(NULL)
 
 CPPSRCS = \
   Hal.cpp \
   SandboxHal.cpp \
   WindowIdentifier.cpp \
-  ScreenOrientationFallback.cpp \
   $(NULL)
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
   AndroidHal.cpp \
   AndroidSensor.cpp \
   $(NULL)
 else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
@@ -104,14 +103,19 @@ CPPSRCS += \
   FallbackSensor.cpp \
   $(NULL)
 endif
 
 ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) #{
 CPPSRCS += FallbackLights.cpp
 endif #}
 
+# Screen Orientation backend
+ifneq (android,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += ScreenOrientationFallback.cpp
+endif
+
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 CFLAGS          += $(MOZ_DBUS_GLIB_CFLAGS)
 CXXFLAGS        += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -35,16 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "WindowIdentifier.h"
 #include "AndroidBridge.h"
 #include "mozilla/dom/network/Constants.h"
+#include "mozilla/dom/ScreenOrientation.h"
 
 using mozilla::hal::WindowIdentifier;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32> &pattern, const WindowIdentifier &)
@@ -176,11 +177,46 @@ GetCurrentNetworkInformation(hal::Networ
 void
 Reboot()
 {}
 
 void
 PowerOff()
 {}
 
+void
+EnableScreenOrientationNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->EnableScreenOrientationNotifications();
+}
+
+void
+DisableScreenOrientationNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->DisableScreenOrientationNotifications();
+}
+
+void
+GetCurrentScreenOrientation(dom::ScreenOrientation* aScreenOrientation)
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  dom::ScreenOrientationWrapper orientationWrapper;
+  bridge->GetScreenOrientation(orientationWrapper);
+  *aScreenOrientation = orientationWrapper.orientation;
+}
+
 } // hal_impl
 } // mozilla
 
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -2055,16 +2055,17 @@ abstract public class GeckoApp
         // Whatever we do here should be fast, because we're blocking
         // the next activity from showing up until we finish.
 
         // onPause will be followed by either onResume or onStop.
         super.onPause();
 
         unregisterReceiver(mConnectivityReceiver);
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
     }
 
     @Override
     public void onResume()
     {
         Log.i(LOGTAG, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
@@ -2080,16 +2081,17 @@ abstract public class GeckoApp
         }
 
         // Just in case. Normally we start in onNewIntent
         if (checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
         GeckoNetworkManager.getInstance().start();
+        GeckoScreenOrientationListener.getInstance().start();
 
         if (mOwnActivityDepth > 0)
             mOwnActivityDepth--;
     }
 
     @Override
     public void onStop()
     {
@@ -2164,16 +2166,17 @@ abstract public class GeckoApp
 
         if (SmsManager.getInstance() != null) {
             SmsManager.getInstance().stop();
             if (isFinishing())
                 SmsManager.getInstance().shutdown();
         }
 
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
 
         super.onDestroy();
 
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
     public void onContentChanged() {
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -1971,9 +1971,21 @@ public class GeckoAppShell
             if (op<oLen) out[op++] = (byte)o1;
             if (op<oLen) out[op++] = (byte)o2; }
         return out; 
     }
 
     public static byte[] decodeBase64(String s, int flags) {
         return decodeBase64(s.getBytes(), flags);
     }
+
+    public static short getScreenOrientation() {
+        return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
+    }
+
+    public static void enableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().enableNotifications();
+    }
+
+    public static void disableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().disableNotifications();
+    }
 }
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -82,16 +82,17 @@ public class GeckoEvent {
     public static final int SURFACE_DESTROYED = 14;
     public static final int GECKO_EVENT_SYNC = 15;
     public static final int ACTIVITY_START = 17;
     public static final int BROADCAST = 19;
     public static final int VIEWPORT = 20;
     public static final int VISITED = 21;
     public static final int NETWORK_CHANGED = 22;
     public static final int PROXIMITY_EVENT = 23;
+    public static final int SCREENORIENTATION_CHANGED = 24;
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
@@ -128,16 +129,18 @@ public class GeckoEvent {
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
     public Location mLocation;
     public Address  mAddress;
 
     public double mBandwidth;
     public boolean mCanBeMetered;
 
+    public short mScreenOrientation;
+
     public int mNativeWindow;
 
     public GeckoEvent() {
         mType = NATIVE_POKE;
     }
 
     public GeckoEvent(int evType) {
         mType = evType;
@@ -354,9 +357,14 @@ public class GeckoEvent {
         mCharacters = data;
     }
 
     public GeckoEvent(double bandwidth, boolean canBeMetered) {
         mType = NETWORK_CHANGED;
         mBandwidth = bandwidth;
         mCanBeMetered = canBeMetered;
     }
+
+    public GeckoEvent(short aScreenOrientation) {
+        mType = SCREENORIENTATION_CHANGED;
+        mScreenOrientation = aScreenOrientation;
+    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/GeckoScreenOrientationListener.java
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+public class GeckoScreenOrientationListener
+{
+  static class OrientationEventListenerImpl extends OrientationEventListener {
+    public OrientationEventListenerImpl(Context c) {
+      super(c);
+    }
+
+    @Override
+    public void onOrientationChanged(int aOrientation) {
+      GeckoScreenOrientationListener.getInstance().updateScreenOrientation();
+    }
+  }
+
+  static private GeckoScreenOrientationListener sInstance = null;
+
+  // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
+  static public final short eScreenOrientation_PortraitPrimary    = 1;
+  static public final short eScreenOrientation_PortraitSecondary  = 2;
+  static public final short eScreenOrientation_LandscapePrimary   = 4;
+  static public final short eScreenOrientation_LandscapeSecondary = 8;
+
+  private short mOrientation;
+  private OrientationEventListenerImpl mListener = null;
+
+  // Whether the listener should be listening to changes.
+  private boolean mShouldBeListening = false;
+  // Whether the listener should notify Gecko that a change happened.
+  private boolean mShouldNotify      = false;
+
+  private GeckoScreenOrientationListener() {
+    mListener = new OrientationEventListenerImpl(GeckoApp.mAppContext);
+  }
+
+  public static GeckoScreenOrientationListener getInstance() {
+    if (sInstance == null) {
+      sInstance = new GeckoScreenOrientationListener();
+    }
+
+    return sInstance;
+  }
+
+  public void start() {
+    mShouldBeListening = true;
+    updateScreenOrientation();
+
+    if (mShouldNotify) {
+      startListening();
+    }
+  }
+
+  public void stop() {
+    mShouldBeListening = false;
+
+    if (mShouldNotify) {
+      stopListening();
+    }
+  }
+
+  public void enableNotifications() {
+    updateScreenOrientation();
+    mShouldNotify = true;
+
+    if (mShouldBeListening) {
+      startListening();
+    }
+  }
+
+  public void disableNotifications() {
+    mShouldNotify = false;
+
+    if (mShouldBeListening) {
+      stopListening();
+    }
+  }
+
+  private void startListening() {
+    mListener.enable();
+  }
+
+  private void stopListening() {
+    mListener.disable();
+  }
+
+  // NOTE: this is public so OrientationEventListenerImpl can access it.
+  // Unfortunately, Java doesn't know about friendship.
+  public void updateScreenOrientation() {
+    int rotation = GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getRotation();
+    short previousOrientation = mOrientation;
+
+    if (rotation == Surface.ROTATION_0) {
+      mOrientation = eScreenOrientation_PortraitPrimary;
+    } else if (rotation == Surface.ROTATION_180) {
+      mOrientation = eScreenOrientation_PortraitSecondary;
+    } else if (rotation == Surface.ROTATION_270) {
+      mOrientation = eScreenOrientation_LandscapeSecondary;
+    } else if (rotation == Surface.ROTATION_90) {
+      mOrientation = eScreenOrientation_LandscapePrimary;
+    } else {
+      Log.e("GeckoScreenOrientationListener", "Unexpected value received! (" + rotation + ")");
+      return;
+    }
+
+    if (mShouldNotify && mOrientation != previousOrientation) {
+      GeckoAppShell.sendEventToGecko(new GeckoEvent(mOrientation));
+    }
+  }
+
+  public short getScreenOrientation() {
+    return mOrientation;
+  }
+}
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -131,16 +131,17 @@ FENNEC_JAVA_FILES = \
   gfx/TileLayer.java \
   gfx/ViewportMetrics.java \
   gfx/WidgetTileLayer.java \
   ui/Axis.java \
   ui/PanZoomController.java \
   ui/SimpleScaleGestureDetector.java \
   ui/SubdocumentScrollHelper.java \
   GeckoNetworkManager.java \
+  GeckoScreenOrientationListener.java \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 FENNEC_JAVA_FILES += GeckoSmsManager.java
 endif
 
 FENNEC_PP_JAVA_FILES = \
   App.java \
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -46,16 +46,17 @@
 #include "AndroidBridge.h"
 #include "nsAppShell.h"
 #include "nsOSHelperAppService.h"
 #include "nsWindow.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
 #include "nsIThreadManager.h"
 #include "mozilla/dom/sms/PSms.h"
+#include "mozilla/dom/ScreenOrientation.h"
 
 #ifdef DEBUG
 #define ALOG_BRIDGE(args...) ALOG(args)
 #else
 #define ALOG_BRIDGE(args...)
 #endif
 
 #define IME_FULLSCREEN_PREF "widget.ime.android.landscape_fullscreen"
@@ -168,16 +169,20 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jCreateMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;IIZIJ)V");
     jGetNextMessageinList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNextMessageInList", "(IIJ)V");
     jClearMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "clearMessageList", "(I)V");
 
     jGetCurrentNetworkInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentNetworkInformation", "()[D");
     jEnableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableNetworkNotifications", "()V");
     jDisableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableNetworkNotifications", "()V");
 
+    jGetScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getScreenOrientation", "()S");
+    jEnableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableScreenOrientationNotifications", "()V");
+    jDisableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableScreenOrientationNotifications", "()V");
+
     jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
     jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
     jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
     InitAndroidJavaWrappers(jEnv);
@@ -1954,8 +1959,29 @@ AndroidBridge::HideSurface(jobject surfa
   jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
 
   jmethodID method = env->GetStaticMethodID(cls,
                                             "hideSurface",
                                             "(Landroid/view/Surface;)V");
   env->CallStaticVoidMethod(cls, method, surface);
 #endif
 }
+
+void
+AndroidBridge::GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation)
+{
+    ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
+    aOrientation.orientation = static_cast<dom::ScreenOrientation>(mJNIEnv->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientation));
+}
+
+void
+AndroidBridge::EnableScreenOrientationNotifications()
+{
+    ALOG_BRIDGE("AndroidBridge::EnableScreenOrientationNotifications");
+    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications);
+}
+
+void
+AndroidBridge::DisableScreenOrientationNotifications()
+{
+    ALOG_BRIDGE("AndroidBridge::DisableScreenOrientationNotifications");
+    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications);
+}
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -74,16 +74,17 @@ extern jclass GetGeckoAppShellClass();
 namespace mozilla {
 
 namespace hal {
 class BatteryInformation;
 class NetworkInformation;
 } // namespace hal
 
 namespace dom {
+class ScreenOrientationWrapper;
 namespace sms {
 struct SmsFilterData;
 } // namespace sms
 } // namespace dom
 
 // The order and number of the members in this structure must correspond
 // to the attrsAppearance array in GeckoAppShell.getSystemColors()
 typedef struct AndroidSystemColors {
@@ -383,16 +384,24 @@ public:
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
     jobject CreateSurface();
     void DestroySurface(jobject surface);
     void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend);
     void HideSurface(jobject surface);
 
+    // This method doesn't take a ScreenOrientation because it's an enum and
+    // that would require including the header which requires include IPC
+    // headers which requires including basictypes.h which requires a lot of
+    // changes...
+    void GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation);
+    void EnableScreenOrientationNotifications();
+    void DisableScreenOrientationNotifications();
+
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
@@ -482,16 +491,20 @@ protected:
     jmethodID jCreateMessageList;
     jmethodID jGetNextMessageinList;
     jmethodID jClearMessageList;
 
     jmethodID jGetCurrentNetworkInformation;
     jmethodID jEnableNetworkNotifications;
     jmethodID jDisableNetworkNotifications;
 
+    jmethodID jGetScreenOrientation;
+    jmethodID jEnableScreenOrientationNotifications;
+    jmethodID jDisableScreenOrientationNotifications;
+
     // stuff we need for CallEglCreateWindowSurface
     jclass jEGLSurfaceImplClass;
     jclass jEGLContextImplClass;
     jclass jEGLConfigImplClass;
     jclass jEGLDisplayImplClass;
     jclass jEGLContextClass;
     jclass jEGL10Class;
 
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -71,16 +71,17 @@ jfieldID AndroidGeckoEvent::jPointerInde
 jfieldID AndroidGeckoEvent::jRangeTypeField = 0;
 jfieldID AndroidGeckoEvent::jRangeStylesField = 0;
 jfieldID AndroidGeckoEvent::jRangeForeColorField = 0;
 jfieldID AndroidGeckoEvent::jRangeBackColorField = 0;
 jfieldID AndroidGeckoEvent::jLocationField = 0;
 jfieldID AndroidGeckoEvent::jAddressField = 0;
 jfieldID AndroidGeckoEvent::jBandwidthField = 0;
 jfieldID AndroidGeckoEvent::jCanBeMeteredField = 0;
+jfieldID AndroidGeckoEvent::jScreenOrientationField = 0;
 
 jclass AndroidPoint::jPointClass = 0;
 jfieldID AndroidPoint::jXField = 0;
 jfieldID AndroidPoint::jYField = 0;
 
 jclass AndroidRect::jRectClass = 0;
 jfieldID AndroidRect::jBottomField = 0;
 jfieldID AndroidRect::jLeftField = 0;
@@ -184,16 +185,17 @@ AndroidGeckoEvent::InitGeckoEventClass(J
     jRangeTypeField = getField("mRangeType", "I");
     jRangeStylesField = getField("mRangeStyles", "I");
     jRangeForeColorField = getField("mRangeForeColor", "I");
     jRangeBackColorField = getField("mRangeBackColor", "I");
     jLocationField = getField("mLocation", "Landroid/location/Location;");
     jAddressField = getField("mAddress", "Landroid/location/Address;");
     jBandwidthField = getField("mBandwidth", "D");
     jCanBeMeteredField = getField("mCanBeMetered", "Z");
+    jScreenOrientationField = getField("mScreenOrientation", "S");
 }
 
 void
 AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
 {
 #ifndef MOZ_JAVA_COMPOSITOR
     initInit();
 
@@ -542,16 +544,21 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
             break;
         }
 
         case PROXIMITY_EVENT: {
             mDistance = jenv->GetDoubleField(jobj, jDistanceField);
             break;
         }
 
+        case SCREENORIENTATION_CHANGED: {
+            mScreenOrientation = jenv->GetShortField(jobj, jScreenOrientationField);
+            break;
+        }
+
         default:
             break;
     }
 
 #ifndef DEBUG_ANDROID_EVENTS
     ALOG("AndroidGeckoEvent: %p : %d", (void*)jobj, mType);
 #endif
 }
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -457,16 +457,17 @@ public:
     int RangeType() { return mRangeType; }
     int RangeStyles() { return mRangeStyles; }
     int RangeForeColor() { return mRangeForeColor; }
     int RangeBackColor() { return mRangeBackColor; }
     nsGeoPosition* GeoPosition() { return mGeoPosition; }
     nsGeoPositionAddress* GeoAddress() { return mGeoAddress; }
     double Bandwidth() { return mBandwidth; }
     bool CanBeMetered() { return mCanBeMetered; }
+    short ScreenOrientation() { return mScreenOrientation; }
 
 protected:
     int mAction;
     int mType;
     int64_t mTime;
     nsTArray<nsIntPoint> mPoints;
     nsTArray<nsIntPoint> mPointRadii;
     nsTArray<int> mPointIndicies;
@@ -482,16 +483,17 @@ protected:
     double mX, mY, mZ;
     double mDistance;
     int mPointerIndex;
     nsString mCharacters, mCharactersExtra;
     nsRefPtr<nsGeoPosition> mGeoPosition;
     nsRefPtr<nsGeoPositionAddress> mGeoAddress;
     double mBandwidth;
     bool mCanBeMetered;
+    short mScreenOrientation;
 
     void ReadIntArray(nsTArray<int> &aVals,
                       JNIEnv *jenv,
                       jfieldID field,
                       PRUint32 count);
     void ReadFloatArray(nsTArray<float> &aVals,
                         JNIEnv *jenv,
                         jfieldID field,
@@ -537,16 +539,18 @@ protected:
     static jfieldID jRangeForeColorField;
     static jfieldID jRangeBackColorField;
     static jfieldID jLocationField;
     static jfieldID jAddressField;
 
     static jfieldID jBandwidthField;
     static jfieldID jCanBeMeteredField;
 
+    static jfieldID jScreenOrientationField;
+
 public:
     enum {
         NATIVE_POKE = 0,
         KEY_EVENT = 1,
         MOTION_EVENT = 2,
         ORIENTATION_EVENT = 3,
         ACCELERATION_EVENT = 4,
         LOCATION_EVENT = 5,
@@ -562,16 +566,17 @@ public:
         GECKO_EVENT_SYNC = 15,
         FORCED_RESIZE = 16,
         ACTIVITY_START = 17,
         BROADCAST = 19,
         VIEWPORT = 20,
         VISITED = 21,
         NETWORK_CHANGED = 22,
         PROXIMITY_EVENT = 23,
+        SCREENORIENTATION_CHANGED = 24,
         dummy_java_enum_list_end
     };
 
     enum {
         IME_COMPOSITION_END = 0,
         IME_COMPOSITION_BEGIN = 1,
         IME_SET_TEXT = 2,
         IME_GET_TEXT = 3,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -56,16 +56,18 @@
 #include "prenv.h"
 
 #include "AndroidBridge.h"
 #include "nsDeviceMotionSystem.h"
 #include <android/log.h>
 #include <pthread.h>
 #include <wchar.h>
 
+#include "mozilla/dom/ScreenOrientation.h"
+
 #ifdef MOZ_ANDROID_HISTORY
 #include "nsAndroidHistory.h"
 #endif
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #include "prlog.h"
 #endif
@@ -478,16 +480,21 @@ nsAppShell::ProcessNextNativeEvent(bool 
     }
 
     case AndroidGeckoEvent::NETWORK_CHANGED: {
         hal::NotifyNetworkChange(hal::NetworkInformation(curEvent->Bandwidth(),
                                                          curEvent->CanBeMetered()));
         break;
     }
 
+    case AndroidGeckoEvent::SCREENORIENTATION_CHANGED: {
+        hal::NotifyScreenOrientationChange(static_cast<dom::ScreenOrientation>(curEvent->ScreenOrientation()));
+        break;
+    }
+
     default:
         nsWindow::OnGlobalAndroidEvent(curEvent);
     }
 
     EVLOG("nsAppShell: -- done event %p %d", (void*)curEvent.get(), curEvent->Type());
 
     return true;
 }