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

This commit is contained in:
Mounir Lamouri 2012-03-20 14:09:45 +01:00
parent 6ac09e7cc2
commit d07b010629
18 changed files with 395 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

@ -1843,4 +1843,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 = 26;
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() {
@ -333,4 +336,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

@ -71,7 +71,6 @@ CPPSRCS = \
SandboxHal.cpp \
WindowIdentifier.cpp \
HalWakeLock.cpp \
ScreenOrientationFallback.cpp \
$(NULL)
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
@ -111,6 +110,11 @@ ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) #{
CPPSRCS += FallbackLights.cpp FallbackTime.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

@ -2049,6 +2049,7 @@ abstract public class GeckoApp
unregisterReceiver(mConnectivityReceiver);
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
}
@Override
@ -2082,6 +2083,7 @@ abstract public class GeckoApp
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
GeckoNetworkManager.getInstance().start();
GeckoScreenOrientationListener.getInstance().start();
if (mOwnActivityDepth > 0)
mOwnActivityDepth--;
@ -2168,6 +2170,7 @@ abstract public class GeckoApp
}
GeckoNetworkManager.getInstance().stop();
GeckoScreenOrientationListener.getInstance().stop();
super.onDestroy();

View File

@ -1994,4 +1994,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

@ -92,6 +92,7 @@ public class GeckoEvent {
private static final int ACTIVITY_RESUMING = 24;
private static final int SCREENSHOT = 25;
private static final int SENSOR_ACCURACY = 26;
private static final int SCREENORIENTATION_CHANGED = 27;
public static final int IME_COMPOSITION_END = 0;
public static final int IME_COMPOSITION_BEGIN = 1;
@ -139,6 +140,8 @@ public class GeckoEvent {
public int mNativeWindow;
public short mScreenOrientation;
private GeckoEvent(int evType) {
mType = evType;
}
@ -443,4 +446,10 @@ public class GeckoEvent {
event.mFlags = accuracy;
return event;
}
public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) {
GeckoEvent event = new GeckoEvent(SCREENORIENTATION_CHANGED);
event.mScreenOrientation = aScreenOrientation;
return event;
}
}

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(GeckoEvent.createScreenOrientationEvent(mOrientation));
}
}
public short getScreenOrientation() {
return mOrientation;
}
}

View File

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

View File

@ -60,6 +60,7 @@
#include "nsPresContext.h"
#include "nsIDocShell.h"
#include "nsPIDOMWindow.h"
#include "mozilla/dom/ScreenOrientation.h"
#ifdef DEBUG
#define ALOG_BRIDGE(args...) ALOG(args)
@ -180,6 +181,10 @@ AndroidBridge::Init(JNIEnv *jEnv,
jDisableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableNetworkNotifications", "()V");
jEmitGeckoAccessibilityEvent = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "emitGeckoAccessibilityEvent", "(I[Ljava/lang/String;Ljava/lang/String;ZZZ)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"));
@ -2088,6 +2093,27 @@ AndroidBridge::HideSurface(jobject 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);
}
/* attribute nsIAndroidBrowserApp browserApp; */
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)

View File

@ -85,6 +85,7 @@ class NetworkInformation;
} // namespace hal
namespace dom {
class ScreenOrientationWrapper;
namespace sms {
struct SmsFilterData;
} // namespace sms
@ -417,6 +418,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;
@ -520,6 +529,10 @@ protected:
jmethodID jEnableNetworkNotifications;
jmethodID jDisableNetworkNotifications;
jmethodID jGetScreenOrientation;
jmethodID jEnableScreenOrientationNotifications;
jmethodID jDisableScreenOrientationNotifications;
// stuff we need for CallEglCreateWindowSurface
jclass jEGLSurfaceImplClass;
jclass jEGLContextImplClass;

View File

@ -72,6 +72,7 @@ jfieldID AndroidGeckoEvent::jRangeBackColorField = 0;
jfieldID AndroidGeckoEvent::jLocationField = 0;
jfieldID AndroidGeckoEvent::jBandwidthField = 0;
jfieldID AndroidGeckoEvent::jCanBeMeteredField = 0;
jfieldID AndroidGeckoEvent::jScreenOrientationField = 0;
jclass AndroidPoint::jPointClass = 0;
jfieldID AndroidPoint::jXField = 0;
@ -183,6 +184,7 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
jLocationField = getField("mLocation", "Landroid/location/Location;");
jBandwidthField = getField("mBandwidth", "D");
jCanBeMeteredField = getField("mCanBeMetered", "Z");
jScreenOrientationField = getField("mScreenOrientation", "S");
}
void
@ -523,6 +525,11 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
ReadPointArray(mPoints, jenv, jPoints, 2);
}
case SCREENORIENTATION_CHANGED: {
mScreenOrientation = jenv->GetShortField(jobj, jScreenOrientationField);
break;
}
default:
break;
}

View File

@ -484,6 +484,7 @@ public:
nsGeoPosition* GeoPosition() { return mGeoPosition; }
double Bandwidth() { return mBandwidth; }
bool CanBeMetered() { return mCanBeMetered; }
short ScreenOrientation() { return mScreenOrientation; }
protected:
int mAction;
@ -507,6 +508,7 @@ protected:
nsRefPtr<nsGeoPosition> mGeoPosition;
double mBandwidth;
bool mCanBeMetered;
short mScreenOrientation;
void ReadIntArray(nsTArray<int> &aVals,
JNIEnv *jenv,
@ -558,6 +560,8 @@ protected:
static jfieldID jBandwidthField;
static jfieldID jCanBeMeteredField;
static jfieldID jScreenOrientationField;
public:
enum {
NATIVE_POKE = 0,
@ -586,6 +590,7 @@ public:
ACTIVITY_RESUMING = 24,
SCREENSHOT = 25,
SENSOR_ACCURACY = 26,
SCREENORIENTATION_CHANGED = 27,
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
@ -560,6 +562,11 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
break;
}
case AndroidGeckoEvent::SCREENORIENTATION_CHANGED: {
hal::NotifyScreenOrientationChange(static_cast<dom::ScreenOrientation>(curEvent->ScreenOrientation()));
break;
}
default:
nsWindow::OnGlobalAndroidEvent(curEvent);
}