Bug 720795 - Screen Orientation API reading and event implementation in Android. r=dougt

This commit is contained in:
Mounir Lamouri 2012-02-09 11:29:44 +01:00
parent 6212b3ee0e
commit 4ed35d32d6
18 changed files with 394 additions and 1 deletions

View File

@ -8,6 +8,9 @@
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

View File

@ -512,6 +512,7 @@ abstract public class GeckoApp
unregisterReceiver(mConnectivityReceiver);
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
}
@Override
@ -531,6 +532,7 @@ abstract public class GeckoApp
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
GeckoNetworkManager.getInstance().start();
GeckoScreenOrientationListener.getInstance().start();
}
@Override
@ -586,6 +588,7 @@ abstract public class GeckoApp
}
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
super.onDestroy();

View File

@ -1829,4 +1829,16 @@ public class GeckoAppShell
// 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();
}
}

View File

@ -80,6 +80,7 @@ public class GeckoEvent {
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;
@ -126,6 +127,8 @@ public class GeckoEvent {
public double mBandwidth;
public boolean mCanBeMetered;
public short mScreenOrientation;
public int mNativeWindow;
public GeckoEvent() {
@ -334,4 +337,9 @@ public class GeckoEvent {
mBandwidth = bandwidth;
mCanBeMetered = canBeMetered;
}
public GeckoEvent(short aScreenOrientation) {
mType = SCREENORIENTATION_CHANGED;
mScreenOrientation = aScreenOrientation;
}
}

View File

@ -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;
}
}

View File

@ -57,6 +57,7 @@ JAVAFILES = \
GeckoBatteryManager.java \
VideoPlayer.java \
GeckoNetworkManager.java \
GeckoScreenOrientationListener.java \
$(NULL)
ifdef MOZ_WEBSMS_BACKEND

View File

@ -69,7 +69,6 @@ CPPSRCS = \
Hal.cpp \
SandboxHal.cpp \
WindowIdentifier.cpp \
ScreenOrientationFallback.cpp \
$(NULL)
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
@ -109,6 +108,11 @@ 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

View File

@ -40,6 +40,7 @@
#include "WindowIdentifier.h"
#include "AndroidBridge.h"
#include "mozilla/dom/network/Constants.h"
#include "mozilla/dom/ScreenOrientation.h"
using mozilla::hal::WindowIdentifier;
@ -181,6 +182,41 @@ 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

View File

@ -2060,6 +2060,7 @@ abstract public class GeckoApp
unregisterReceiver(mConnectivityReceiver);
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
}
@Override
@ -2085,6 +2086,7 @@ abstract public class GeckoApp
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
GeckoNetworkManager.getInstance().start();
GeckoScreenOrientationListener.getInstance().start();
if (mOwnActivityDepth > 0)
mOwnActivityDepth--;
@ -2169,6 +2171,7 @@ abstract public class GeckoApp
}
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
super.onDestroy();

View File

@ -1976,4 +1976,16 @@ public class GeckoAppShell
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();
}
}

View File

@ -87,6 +87,7 @@ public class GeckoEvent {
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;
@ -133,6 +134,8 @@ public class GeckoEvent {
public double mBandwidth;
public boolean mCanBeMetered;
public short mScreenOrientation;
public int mNativeWindow;
public GeckoEvent() {
@ -359,4 +362,9 @@ public class GeckoEvent {
mBandwidth = bandwidth;
mCanBeMetered = canBeMetered;
}
public GeckoEvent(short aScreenOrientation) {
mType = SCREENORIENTATION_CHANGED;
mScreenOrientation = aScreenOrientation;
}
}

View File

@ -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;
}
}

View File

@ -136,6 +136,7 @@ FENNEC_JAVA_FILES = \
ui/SimpleScaleGestureDetector.java \
ui/SubdocumentScrollHelper.java \
GeckoNetworkManager.java \
GeckoScreenOrientationListener.java \
$(NULL)
ifdef MOZ_WEBSMS_BACKEND

View File

@ -51,6 +51,7 @@
#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)
@ -173,6 +174,10 @@ AndroidBridge::Init(JNIEnv *jEnv,
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"));
@ -1959,3 +1964,24 @@ AndroidBridge::HideSurface(jobject surface)
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);
}

View File

@ -79,6 +79,7 @@ class NetworkInformation;
} // namespace hal
namespace dom {
class ScreenOrientationWrapper;
namespace sms {
struct SmsFilterData;
} // namespace sms
@ -388,6 +389,14 @@ public:
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;
@ -487,6 +496,10 @@ protected:
jmethodID jEnableNetworkNotifications;
jmethodID jDisableNetworkNotifications;
jmethodID jGetScreenOrientation;
jmethodID jEnableScreenOrientationNotifications;
jmethodID jDisableScreenOrientationNotifications;
// stuff we need for CallEglCreateWindowSurface
jclass jEGLSurfaceImplClass;
jclass jEGLContextImplClass;

View File

@ -76,6 +76,7 @@ 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;
@ -189,6 +190,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
jAddressField = getField("mAddress", "Landroid/location/Address;");
jBandwidthField = getField("mBandwidth", "D");
jCanBeMeteredField = getField("mCanBeMetered", "Z");
jScreenOrientationField = getField("mScreenOrientation", "S");
}
void
@ -547,6 +549,11 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
break;
}
case SCREENORIENTATION_CHANGED: {
mScreenOrientation = jenv->GetShortField(jobj, jScreenOrientationField);
break;
}
default:
break;
}

View File

@ -462,6 +462,7 @@ public:
nsGeoPositionAddress* GeoAddress() { return mGeoAddress; }
double Bandwidth() { return mBandwidth; }
bool CanBeMetered() { return mCanBeMetered; }
short ScreenOrientation() { return mScreenOrientation; }
protected:
int mAction;
@ -487,6 +488,7 @@ protected:
nsRefPtr<nsGeoPositionAddress> mGeoAddress;
double mBandwidth;
bool mCanBeMetered;
short mScreenOrientation;
void ReadIntArray(nsTArray<int> &aVals,
JNIEnv *jenv,
@ -542,6 +544,8 @@ protected:
static jfieldID jBandwidthField;
static jfieldID jCanBeMeteredField;
static jfieldID jScreenOrientationField;
public:
enum {
NATIVE_POKE = 0,
@ -567,6 +571,7 @@ public:
VISITED = 21,
NETWORK_CHANGED = 22,
PROXIMITY_EVENT = 23,
SCREENORIENTATION_CHANGED = 24,
dummy_java_enum_list_end
};

View File

@ -61,6 +61,8 @@
#include <pthread.h>
#include <wchar.h>
#include "mozilla/dom/ScreenOrientation.h"
#ifdef MOZ_ANDROID_HISTORY
#include "nsAndroidHistory.h"
#endif
@ -483,6 +485,11 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
break;
}
case AndroidGeckoEvent::SCREENORIENTATION_CHANGED: {
hal::NotifyScreenOrientationChange(static_cast<dom::ScreenOrientation>(curEvent->ScreenOrientation()));
break;
}
default:
nsWindow::OnGlobalAndroidEvent(curEvent);
}