Bug 971012 - Use onConfigurationChange for screen orientation change. r=snorp

This commit is contained in:
Eugen Sawin 2014-02-20 18:50:18 +01:00
parent 51f2294632
commit 50d8a2fbf3
6 changed files with 395 additions and 249 deletions

View File

@ -1014,7 +1014,7 @@ abstract public class BrowserApp extends GeckoApp
if (mMainLayoutAnimator != null)
mMainLayoutAnimator.stop();
boolean isSideBar = (HardwareUtils.isTablet() && mOrientation == Configuration.ORIENTATION_LANDSCAPE);
boolean isSideBar = (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE);
final int sidebarWidth = getResources().getDimensionPixelSize(R.dimen.tabs_sidebar_width);
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mTabsPanel.getLayoutParams();

View File

@ -183,7 +183,6 @@ public abstract class GeckoApp
protected MenuPanel mMenuPanel;
protected Menu mMenu;
protected GeckoProfile mProfile;
public static int mOrientation;
protected boolean mIsRestoringActivity;
private ContactService mContactService;
@ -941,7 +940,7 @@ public abstract class GeckoApp
mFullScreenPluginView = null;
GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
GeckoScreenOrientation.getInstance().unlock();
setFullScreen(false);
}
@ -1252,7 +1251,7 @@ public abstract class GeckoApp
super.onCreate(savedInstanceState);
mOrientation = getResources().getConfiguration().orientation;
GeckoScreenOrientation.getInstance().update(getResources().getConfiguration().orientation);
setContentView(getLayout());
@ -1924,6 +1923,10 @@ public abstract class GeckoApp
return uri;
}
protected int getOrientation() {
return GeckoScreenOrientation.getInstance().getAndroidOrientation();
}
@Override
public void onResume()
{
@ -1932,14 +1935,10 @@ public abstract class GeckoApp
super.onResume();
int newOrientation = getResources().getConfiguration().orientation;
if (mOrientation != newOrientation) {
mOrientation = newOrientation;
if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
refreshChrome();
}
GeckoScreenOrientationListener.getInstance().start();
// User may have enabled/disabled accessibility.
GeckoAccessibility.updateAccessibilitySettings(this);
@ -2015,8 +2014,6 @@ public abstract class GeckoApp
}
});
GeckoScreenOrientationListener.getInstance().stop();
if (mAppStateListeners != null) {
for(GeckoAppShell.AppStateListener listener: mAppStateListeners) {
listener.onPause();
@ -2155,14 +2152,16 @@ public abstract class GeckoApp
public void onConfigurationChanged(Configuration newConfig) {
Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale);
LocaleManager.correctLocale(getResources(), newConfig);
super.onConfigurationChanged(newConfig);
if (mOrientation != newConfig.orientation) {
mOrientation = newConfig.orientation;
// onConfigurationChanged is not called for 180 degree orientation changes,
// we will miss such rotations and the screen orientation will not be
// updated.
if (GeckoScreenOrientation.getInstance().update(newConfig.orientation)) {
if (mFormAssistPopup != null)
mFormAssistPopup.hide();
refreshChrome();
}
super.onConfigurationChanged(newConfig);
}
public String getContentProcessName() {

View File

@ -2571,27 +2571,27 @@ public class GeckoAppShell
@WrapElementForJNI(stubName = "GetScreenOrientationWrapper")
public static short getScreenOrientation() {
return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
return GeckoScreenOrientation.getInstance().getScreenOrientation().value;
}
@WrapElementForJNI
public static void enableScreenOrientationNotifications() {
GeckoScreenOrientationListener.getInstance().enableNotifications();
GeckoScreenOrientation.getInstance().enableNotifications();
}
@WrapElementForJNI
public static void disableScreenOrientationNotifications() {
GeckoScreenOrientationListener.getInstance().disableNotifications();
GeckoScreenOrientation.getInstance().disableNotifications();
}
@WrapElementForJNI
public static void lockScreenOrientation(int aOrientation) {
GeckoScreenOrientationListener.getInstance().lockScreenOrientation(aOrientation);
GeckoScreenOrientation.getInstance().lock(aOrientation);
}
@WrapElementForJNI
public static void unlockScreenOrientation() {
GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
GeckoScreenOrientation.getInstance().unlock();
}
@WrapElementForJNI

View File

@ -0,0 +1,376 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.util.Log;
import android.view.Surface;
import android.app.Activity;
import java.util.Arrays;
import java.util.List;
/*
* Updates, locks and unlocks the screen orientation.
*
* Note: Replaces the OnOrientationChangeListener to avoid redundant rotation
* event handling.
*/
public class GeckoScreenOrientation {
private static final String LOGTAG = "GeckoScreenOrientation";
// Make sure that any change in dom/base/ScreenOrientation.h happens here too.
public enum ScreenOrientation {
NONE(0),
PORTRAIT_PRIMARY(1 << 0),
PORTRAIT_SECONDARY(1 << 1),
LANDSCAPE_PRIMARY(1 << 2),
LANDSCAPE_SECONDARY(1 << 3),
DEFAULT(1 << 4);
public final short value;
private ScreenOrientation(int value) {
this.value = (short)value;
}
public static ScreenOrientation get(short value) {
switch (value) {
case (1 << 0): return PORTRAIT_PRIMARY;
case (1 << 1): return PORTRAIT_SECONDARY;
case (1 << 2): return LANDSCAPE_PRIMARY;
case (1 << 3): return LANDSCAPE_SECONDARY;
case (1 << 4): return DEFAULT;
default: return NONE;
}
}
}
// Singleton instance.
private static GeckoScreenOrientation sInstance = null;
// Default screen orientation, used for initialization and unlocking.
private static final ScreenOrientation DEFAULT_SCREEN_ORIENTATION = ScreenOrientation.DEFAULT;
// Default rotation, used when device rotation is unknown.
private static final int DEFAULT_ROTATION = Surface.ROTATION_0;
// Default orientation, used if screen orientation is unspecified.
private ScreenOrientation mDefaultScreenOrientation;
// Last updated screen orientation.
private ScreenOrientation mScreenOrientation;
// Whether the update should notify Gecko about screen orientation changes.
private boolean mShouldNotify = true;
// Configuration screen orientation preference path.
private static final String DEFAULT_SCREEN_ORIENTATION_PREF = "app.orientation.default";
public GeckoScreenOrientation() {
PrefsHelper.getPref(DEFAULT_SCREEN_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
@Override public void prefValue(String pref, String value) {
// Read and update the configuration default preference.
mDefaultScreenOrientation = screenOrientationFromArrayString(value);
setRequestedOrientation(mDefaultScreenOrientation);
}
});
mDefaultScreenOrientation = DEFAULT_SCREEN_ORIENTATION;
update();
}
public static GeckoScreenOrientation getInstance() {
if (sInstance == null) {
sInstance = new GeckoScreenOrientation();
}
return sInstance;
}
/*
* Enable Gecko screen orientation events on update.
*/
public void enableNotifications() {
update();
mShouldNotify = true;
}
/*
* Disable Gecko screen orientation events on update.
*/
public void disableNotifications() {
mShouldNotify = false;
}
/*
* Update screen orientation.
* Retrieve orientation and rotation via GeckoAppShell.
*
* @return Whether the screen orientation has changed.
*/
public boolean update() {
Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
if (activity == null) {
return false;
}
Configuration config = activity.getResources().getConfiguration();
return update(config.orientation);
}
/*
* Update screen orientation given the android orientation.
* Retrieve rotation via GeckoAppShell.
*
* @param aAndroidOrientation
* Android screen orientation from Configuration.orientation.
*
* @return Whether the screen orientation has changed.
*/
public boolean update(int aAndroidOrientation) {
return update(getScreenOrientation(aAndroidOrientation, getRotation()));
}
/*
* Update screen orientation given the screen orientation.
*
* @param aScreenOrientation
* Gecko screen orientation based on android orientation and rotation.
*
* @return Whether the screen orientation has changed.
*/
public boolean update(ScreenOrientation aScreenOrientation) {
if (mScreenOrientation == aScreenOrientation) {
return false;
}
mScreenOrientation = aScreenOrientation;
Log.d(LOGTAG, "updating to new orientation " + mScreenOrientation);
if (mShouldNotify) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mScreenOrientation.value));
}
return true;
}
/*
* @return The Android orientation (Configuration.orientation).
*/
public int getAndroidOrientation() {
return screenOrientationToAndroidOrientation(getScreenOrientation());
}
/*
* @return The Gecko screen orientation derived from Android orientation and
* rotation.
*/
public ScreenOrientation getScreenOrientation() {
return mScreenOrientation;
}
/*
* Lock screen orientation given the Android orientation.
* Retrieve rotation via GeckoAppShell.
*
* @param aAndroidOrientation
* The Android orientation provided by Configuration.orientation.
*/
public void lock(int aAndroidOrientation) {
lock(getScreenOrientation(aAndroidOrientation, getRotation()));
}
/*
* Lock screen orientation given the Gecko screen orientation.
* Retrieve rotation via GeckoAppShell.
*
* @param aScreenOrientation
* Gecko screen orientation derived from Android orientation and
* rotation.
*
* @return Whether the locking was successful.
*/
public boolean lock(ScreenOrientation aScreenOrientation) {
Log.d(LOGTAG, "locking to " + aScreenOrientation);
update(aScreenOrientation);
return setRequestedOrientation(aScreenOrientation);
}
/*
* Unlock and update screen orientation.
*
* @return Whether the unlocking was successful.
*/
public boolean unlock() {
Log.d(LOGTAG, "unlocking");
setRequestedOrientation(mDefaultScreenOrientation);
return update();
}
/*
* Set the given requested orientation for the current activity.
* This is essentially an unlock without an update.
*
* @param aScreenOrientation
* Gecko screen orientation.
*
* @return Whether the requested orientation was set. This can only fail if
* the current activity cannot be retrieved vie GeckoAppShell.
*
*/
private boolean setRequestedOrientation(ScreenOrientation aScreenOrientation) {
int activityOrientation = screenOrientationToActivityInfoOrientation(aScreenOrientation);
Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
if (activity == null) {
Log.w(LOGTAG, "setRequestOrientation: failed to get activity");
}
if (activity.getRequestedOrientation() == activityOrientation) {
return false;
}
activity.setRequestedOrientation(activityOrientation);
return true;
}
/*
* Combine the Android orientation and rotation to the Gecko orientation.
*
* @param aAndroidOrientation
* Android orientation from Configuration.orientation.
* @param aRotation
* Device rotation from Display.getRotation().
*
* @return Gecko screen orientation.
*/
private ScreenOrientation getScreenOrientation(int aAndroidOrientation, int aRotation) {
boolean isPrimary = aRotation == Surface.ROTATION_0 || aRotation == Surface.ROTATION_90;
if (aAndroidOrientation == Configuration.ORIENTATION_PORTRAIT) {
if (isPrimary) {
// Non-rotated portrait device or landscape device rotated
// to primary portrait mode counter-clockwise.
return ScreenOrientation.PORTRAIT_PRIMARY;
}
return ScreenOrientation.PORTRAIT_SECONDARY;
}
if (aAndroidOrientation == Configuration.ORIENTATION_LANDSCAPE) {
if (isPrimary) {
// Non-rotated landscape device or portrait device rotated
// to primary landscape mode counter-clockwise.
return ScreenOrientation.LANDSCAPE_PRIMARY;
}
return ScreenOrientation.LANDSCAPE_SECONDARY;
}
return ScreenOrientation.NONE;
}
/*
* @return Device rotation from Display.getRotation().
*/
private int getRotation() {
Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
if (activity == null) {
Log.w(LOGTAG, "getRotation: failed to get activity");
return DEFAULT_ROTATION;
}
return activity.getWindowManager().getDefaultDisplay().getRotation();
}
/*
* Retrieve the screen orientation from an array string.
*
* @param aArray
* String containing comma-delimited strings.
*
* @return First parsed Gecko screen orientation.
*/
public static ScreenOrientation screenOrientationFromArrayString(String aArray) {
List<String> orientations = Arrays.asList(aArray.split(","));
if (orientations.size() == 0) {
// If nothing is listed, return default.
Log.w(LOGTAG, "screenOrientationFromArrayString: no orientation in string");
return DEFAULT_SCREEN_ORIENTATION;
}
// We don't support multiple orientations yet. To avoid developer
// confusion, just take the first one listed.
return screenOrientationFromString(orientations.get(0));
}
/*
* Retrieve the scren orientation from a string.
*
* @param aStr
* String hopefully containing a screen orientation name.
* @return Gecko screen orientation if matched, DEFAULT_SCREEN_ORIENTATION
* otherwise.
*/
public static ScreenOrientation screenOrientationFromString(String aStr) {
if ("portrait".equals(aStr)) {
return ScreenOrientation.PORTRAIT_PRIMARY;
}
else if ("landscape".equals(aStr)) {
return ScreenOrientation.LANDSCAPE_PRIMARY;
}
else if ("portrait-primary".equals(aStr)) {
return ScreenOrientation.PORTRAIT_PRIMARY;
}
else if ("portrait-secondary".equals(aStr)) {
return ScreenOrientation.PORTRAIT_SECONDARY;
}
else if ("landscape-primary".equals(aStr)) {
return ScreenOrientation.LANDSCAPE_PRIMARY;
}
else if ("landscape-secondary".equals(aStr)) {
return ScreenOrientation.LANDSCAPE_SECONDARY;
}
Log.w(LOGTAG, "screenOrientationFromString: unknown orientation string");
return DEFAULT_SCREEN_ORIENTATION;
}
/*
* Convert Gecko screen orientation to Android orientation.
*
* @param aScreenOrientation
* Gecko screen orientation.
* @return Android orientation. This conversion is lossy, the Android
* orientation does not differentiate between primary and secondary
* orientations.
*/
public static int screenOrientationToAndroidOrientation(ScreenOrientation aScreenOrientation) {
switch (aScreenOrientation) {
case PORTRAIT_PRIMARY:
case PORTRAIT_SECONDARY:
return Configuration.ORIENTATION_PORTRAIT;
case LANDSCAPE_PRIMARY:
case LANDSCAPE_SECONDARY:
return Configuration.ORIENTATION_LANDSCAPE;
case NONE:
case DEFAULT:
default:
return Configuration.ORIENTATION_UNDEFINED;
}
}
/*
* Convert Gecko screen orientation to Android ActivityInfo orientation.
* This is yet another orientation used by Android, but it's more detailed
* than the Android orientation.
* It is required for screen orientation locking and unlocking.
*
* @param aScreenOrientation
* Gecko screen orientation.
* @return Android ActivityInfo orientation.
*/
public static int screenOrientationToActivityInfoOrientation(ScreenOrientation aScreenOrientation) {
switch (aScreenOrientation) {
case PORTRAIT_PRIMARY:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
case PORTRAIT_SECONDARY:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
case LANDSCAPE_PRIMARY:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
case LANDSCAPE_SECONDARY:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
case DEFAULT:
case NONE:
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
default:
return ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
}
}
}

View File

@ -1,229 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.content.pm.ActivityInfo;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.Surface;
import java.util.Arrays;
import java.util.List;
import android.app.Activity;
public class GeckoScreenOrientationListener {
private static final String LOGTAG = "GeckoScreenOrientationListener";
static class OrientationEventListenerImpl extends OrientationEventListener {
public OrientationEventListenerImpl(Context c) {
super(c);
}
@Override
public void onOrientationChanged(int aOrientation) {
GeckoScreenOrientationListener.getInstance().updateScreenOrientation(aOrientation);
}
}
static private GeckoScreenOrientationListener sInstance = null;
// Make sure that any change in dom/base/ScreenOrientation.h happens here too.
static public final short eScreenOrientation_None = 0;
static public final short eScreenOrientation_PortraitPrimary = 1; // PR_BIT(0)
static public final short eScreenOrientation_PortraitSecondary = 2; // PR_BIT(1)
static public final short eScreenOrientation_LandscapePrimary = 4; // PR_BIT(2)
static public final short eScreenOrientation_LandscapeSecondary = 8; // PR_BIT(3)
static public final short eScreenOrientation_Default = 16;// PR_BIT(4)
static private final short DEFAULT_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
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;
// The default orientation to use if nothing is specified
private short mDefaultOrientation;
private static final String DEFAULT_ORIENTATION_PREF = "app.orientation.default";
private GeckoScreenOrientationListener() {
mListener = new OrientationEventListenerImpl(GeckoAppShell.getContext());
PrefsHelper.getPref(DEFAULT_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
@Override public void prefValue(String pref, String value) {
mDefaultOrientation = orientationFromStringArray(value);
unlockScreenOrientation();
}
@Override
public boolean isObserver() {
return true;
}
});
mDefaultOrientation = DEFAULT_ORIENTATION;
}
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();
}
private short orientationFromStringArray(String val) {
List<String> orientations = Arrays.asList(val.split(","));
// if nothing is listed, return unspecified
if (orientations.size() == 0)
return DEFAULT_ORIENTATION;
// we dont' support multiple orientations yet. To avoid developer confusion,
// just take the first one listed
return orientationFromString(orientations.get(0));
}
private short orientationFromString(String val) {
if ("portrait".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
else if ("landscape".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
else if ("portrait-primary".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
else if ("portrait-secondary".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
else if ("landscape-primary".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
else if ("landscape-secondary".equals(val))
return (short)ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
return DEFAULT_ORIENTATION;
}
private void updateScreenOrientation() {
Context context = GeckoAppShell.getContext();
int rotation = mDefaultOrientation;
if (context instanceof Activity) {
rotation = ((Activity)context).getWindowManager().getDefaultDisplay().getRotation();
}
updateScreenOrientation(rotation * 90);
}
private void updateScreenOrientation(int aOrientation) {
short previousOrientation = mOrientation;
if (aOrientation >= 315 || aOrientation < 45) {
mOrientation = eScreenOrientation_PortraitPrimary;
} else if (aOrientation >= 45 && aOrientation < 135) {
mOrientation = eScreenOrientation_LandscapePrimary;
} else if (aOrientation >= 135 && aOrientation < 225) {
mOrientation = eScreenOrientation_PortraitSecondary;
} else if (aOrientation >= 225 && aOrientation < 315) {
mOrientation = eScreenOrientation_LandscapeSecondary;
} else {
Log.e(LOGTAG, "Unexpected value received! (" + aOrientation + ")");
return;
}
if (mShouldNotify && mOrientation != previousOrientation) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mOrientation));
}
}
public short getScreenOrientation() {
return mOrientation;
}
public void lockScreenOrientation(int aOrientation) {
int orientation = 0;
switch (aOrientation) {
case eScreenOrientation_PortraitPrimary:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case eScreenOrientation_PortraitSecondary:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
case eScreenOrientation_PortraitPrimary | eScreenOrientation_PortraitSecondary:
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
break;
case eScreenOrientation_LandscapePrimary:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case eScreenOrientation_LandscapeSecondary:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
break;
case eScreenOrientation_Default:
orientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
break;
default:
Log.e(LOGTAG, "Unexpected value received! (" + aOrientation + ")");
return;
}
if (GeckoAppShell.getContext() instanceof Activity)
((Activity)GeckoAppShell.getContext()).setRequestedOrientation(orientation);
updateScreenOrientation();
}
public void unlockScreenOrientation() {
if (!(GeckoAppShell.getContext() instanceof Activity))
return;
if (((Activity)GeckoAppShell.getContext()).getRequestedOrientation() == mDefaultOrientation)
return;
((Activity)GeckoAppShell.getContext()).setRequestedOrientation(mDefaultOrientation);
updateScreenOrientation();
}
}

View File

@ -154,7 +154,7 @@ gbjar.sources += [
'GeckoMessageReceiver.java',
'GeckoNetworkManager.java',
'GeckoProfile.java',
'GeckoScreenOrientationListener.java',
'GeckoScreenOrientation.java',
'GeckoSmsManager.java',
'GeckoThread.java',
'GeckoUpdateReceiver.java',