Bug 1476106 - Part 1 - Make it possible to notify Java listeners from GeckoScreenOrientation, too. r?snorp
Once responsibility for notifying GeckoScreenOrientation of potentially changed
screen orientations moves from GeckoApp into GeckoView, the former will no
longer be able to benefit from the return value of calling GeckoScreen-
Orientation.update(), indicating whether the orientation actually changed or in
fact remained the same.
GeckoApp however requires that information in order to reset/refresh parts of
the UI when the orientation changes, and since GeckoScreenOrientation is already
doing all the work of tracking screen orientation changes, we don't want to have
to partially duplicate those efforts again in GeckoApp.
Instead, we introduce a mechanism for GeckoScreenOrientation to notify
interested parties on the Android app side as well.
The GeckoScreenOrientation.update() call in GeckoApp.onResume() is removed
completely (as opposed to merely removing the refreshChrome() bit) at this stage
already because it is unnecessary. If any screen rotation happened while the
activity was in background, it will receive an onConfigurationChanged() call
anyway before being resumed again.
MozReview-Commit-ID: Ila1evcj8Ud
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2,16 +2,17 @@
* 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 org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
+import org.mozilla.gecko.GeckoScreenOrientation.ScreenOrientation;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.health.HealthRecorder;
import org.mozilla.gecko.health.SessionInformation;
import org.mozilla.gecko.health.StubbedHealthRecorder;
import org.mozilla.gecko.home.HomeConfig.PanelType;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.GeckoMenuInflater;
@@ -107,16 +108,17 @@ import static org.mozilla.gecko.Tabs.INV
import static org.mozilla.gecko.mma.MmaDelegate.DOWNLOAD_MEDIA_SAVED_IMAGE;
import static org.mozilla.gecko.mma.MmaDelegate.READER_AVAILABLE;
public abstract class GeckoApp extends GeckoActivity
implements AnchoredPopup.OnVisibilityChangeListener,
BundleEventListener,
GeckoMenu.Callback,
GeckoMenu.MenuPresenter,
+ GeckoScreenOrientation.OrientationChangeListener,
GeckoSession.ContentDelegate,
ScreenOrientationDelegate,
Tabs.OnTabsChangedListener,
ViewTreeObserver.OnGlobalLayoutListener {
private static final String LOGTAG = "GeckoApp";
private static final long ONE_DAY_MS = TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS);
@@ -976,16 +978,17 @@ public abstract class GeckoApp extends G
earlyStartJavaSampler(intent);
// Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
try {
Class.forName("android.os.AsyncTask");
} catch (ClassNotFoundException e) { }
GeckoAppShell.setScreenOrientationDelegate(this);
+ GeckoScreenOrientation.getInstance().addListener(this);
// Tell Stumbler to register a local broadcast listener to listen for preference intents.
// We do this via intents since we can't easily access Stumbler directly,
// as it might be compiled outside of Fennec.
final Intent stumblerIntent = new Intent(getApplicationContext(), SafeReceiver.class);
stumblerIntent.setAction(INTENT_REGISTER_STUMBLER_LISTENER);
getApplicationContext().sendBroadcast(stumblerIntent);
@@ -1924,21 +1927,16 @@ public abstract class GeckoApp extends G
if (mIsAbortingAppLaunch) {
return;
}
foregrounded = true;
GeckoAppShell.setScreenOrientationDelegate(this);
- int newOrientation = getResources().getConfiguration().orientation;
- if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
- refreshChrome();
- }
-
// We use two times: a pseudo-unique wall-clock time to identify the
// current session across power cycles, and the elapsed realtime to
// track the duration of the session.
final long now = System.currentTimeMillis();
final long realTime = android.os.SystemClock.elapsedRealtime();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
@@ -2128,16 +2126,18 @@ public abstract class GeckoApp extends G
});
}
super.onDestroy();
Tabs.unregisterOnTabsChangedListener(this);
Tabs.getInstance().detachFromContext();
+ GeckoScreenOrientation.getInstance().removeListener(this);
+
if (mShutdownOnDestroy) {
GeckoApplication.shutdown(!mRestartOnShutdown ? null : new Intent(
Intent.ACTION_MAIN, /* uri */ null, getApplicationContext(), getClass()));
}
}
public void showSDKVersionError() {
final String message = getString(R.string.unsupported_sdk_version,
@@ -2175,21 +2175,17 @@ public abstract class GeckoApp extends G
final Locale changed = localeManager.onSystemConfigurationChanged(this, getResources(), newConfig, mLastLocale);
if (changed != null) {
onLocaleChanged(Locales.getLanguageTag(changed));
}
// 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();
- }
+ GeckoScreenOrientation.getInstance().update(newConfig.orientation);
if (mPromptService != null) {
mPromptService.changePromptOrientation(newConfig.orientation);
}
super.onConfigurationChanged(newConfig);
}
@@ -2522,9 +2518,17 @@ public abstract class GeckoApp extends G
// We want to support the Screen Orientation API, and it always makes sense to lock the
// orientation of a browser Activity, so we support locking.
if (getRequestedOrientation() == requestedActivityInfoOrientation) {
return false;
}
setRequestedOrientation(requestedActivityInfoOrientation);
return true;
}
+
+ @Override
+ public void onScreenOrientationChanged(ScreenOrientation newOrientation) {
+ if (mFormAssistPopup != null) {
+ mFormAssistPopup.hide();
+ }
+ refreshChrome();
+ }
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java
@@ -8,17 +8,19 @@ 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.view.WindowManager;
import org.mozilla.gecko.annotation.WrapForJNI;
+import org.mozilla.gecko.util.ThreadUtils;
+import java.util.ArrayList;
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.
@@ -59,27 +61,50 @@ public class GeckoScreenOrientation {
private static GeckoScreenOrientation sInstance;
// Default rotation, used when device rotation is unknown.
private static final int DEFAULT_ROTATION = Surface.ROTATION_0;
// Last updated screen orientation.
private ScreenOrientation mScreenOrientation;
// Whether the update should notify Gecko about screen orientation changes.
private boolean mShouldNotify = true;
+ public interface OrientationChangeListener {
+ void onScreenOrientationChanged(ScreenOrientation newOrientation);
+ }
+
+ private final List<OrientationChangeListener> mListeners;
+
public static GeckoScreenOrientation getInstance() {
if (sInstance == null) {
sInstance = new GeckoScreenOrientation();
}
return sInstance;
}
private GeckoScreenOrientation() {
+ mListeners = new ArrayList<>();
update();
}
+ /**
+ * Add a listener that will be notified when the screen orientation has changed.
+ */
+ public void addListener(OrientationChangeListener aListener) {
+ ThreadUtils.assertOnUiThread();
+ mListeners.add(aListener);
+ }
+
+ /**
+ * Remove a OrientationChangeListener again.
+ */
+ public void removeListener(OrientationChangeListener aListener) {
+ ThreadUtils.assertOnUiThread();
+ mListeners.remove(aListener);
+ }
+
/*
* Enable Gecko screen orientation events on update.
*/
public void enableNotifications() {
update();
mShouldNotify = true;
}
@@ -130,16 +155,17 @@ public class GeckoScreenOrientation {
* @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);
+ notifyListeners(mScreenOrientation);
if (mShouldNotify) {
// Gecko expects a definite screen orientation, so we default to the
// primary orientations.
if (aScreenOrientation == ScreenOrientation.PORTRAIT) {
aScreenOrientation = ScreenOrientation.PORTRAIT_PRIMARY;
} else if (aScreenOrientation == ScreenOrientation.LANDSCAPE) {
aScreenOrientation = ScreenOrientation.LANDSCAPE_PRIMARY;
}
@@ -150,16 +176,33 @@ public class GeckoScreenOrientation {
GeckoThread.queueNativeCall(GeckoScreenOrientation.class, "onOrientationChange",
aScreenOrientation.value, getAngle());
}
}
GeckoAppShell.resetScreenSize();
return true;
}
+ private void notifyListeners(final ScreenOrientation newOrientation) {
+ final Runnable notifier = new Runnable() {
+ @Override
+ public void run() {
+ for (OrientationChangeListener listener : mListeners) {
+ listener.onScreenOrientationChanged(newOrientation);
+ }
+ }
+ };
+
+ if (ThreadUtils.isOnUiThread()) {
+ notifier.run();
+ } else {
+ ThreadUtils.postToUiThread(notifier);
+ }
+ }
+
/*
* @return The Android orientation (Configuration.orientation).
*/
public int getAndroidOrientation() {
return screenOrientationToAndroidOrientation(getScreenOrientation());
}
/*