summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java273
1 files changed, 273 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java
new file mode 100644
index 0000000000..ce7a48c4da
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenOrientation.java
@@ -0,0 +1,273 @@
+/* -*- 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 static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import java.util.ArrayList;
+import java.util.List;
+import org.mozilla.gecko.util.ThreadUtils;
+
+/*
+ * 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 hal/HalScreenConfiguration.h happens here too.
+ public enum ScreenOrientation {
+ NONE(0),
+ PORTRAIT_PRIMARY(1 << 0),
+ PORTRAIT_SECONDARY(1 << 1),
+ PORTRAIT(PORTRAIT_PRIMARY.value | PORTRAIT_SECONDARY.value),
+ LANDSCAPE_PRIMARY(1 << 2),
+ LANDSCAPE_SECONDARY(1 << 3),
+ LANDSCAPE(LANDSCAPE_PRIMARY.value | LANDSCAPE_SECONDARY.value),
+ ANY(
+ PORTRAIT_PRIMARY.value
+ | PORTRAIT_SECONDARY.value
+ | LANDSCAPE_PRIMARY.value
+ | LANDSCAPE_SECONDARY.value),
+ DEFAULT(1 << 4);
+
+ public final short value;
+
+ ScreenOrientation(final int value) {
+ this.value = (short) value;
+ }
+
+ private static final ScreenOrientation[] sValues = ScreenOrientation.values();
+
+ public static ScreenOrientation get(final int value) {
+ for (final ScreenOrientation orient : sValues) {
+ if (orient.value == value) {
+ return orient;
+ }
+ }
+ return NONE;
+ }
+ }
+
+ // Singleton instance.
+ 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 with Gecko value space.
+ private ScreenOrientation mScreenOrientation = ScreenOrientation.PORTRAIT_PRIMARY;
+
+ 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(final OrientationChangeListener aListener) {
+ ThreadUtils.assertOnUiThread();
+ mListeners.add(aListener);
+ }
+
+ /** Remove a OrientationChangeListener again. */
+ public void removeListener(final OrientationChangeListener aListener) {
+ ThreadUtils.assertOnUiThread();
+ mListeners.remove(aListener);
+ }
+
+ /*
+ * Update screen orientation.
+ * Retrieve orientation and rotation via GeckoAppShell.
+ *
+ * @return Whether the screen orientation has changed.
+ */
+ public boolean update() {
+ // Check whether we have the application context for fenix/a-c unit test.
+ final Context appContext = GeckoAppShell.getApplicationContext();
+ if (appContext == null) {
+ return false;
+ }
+ final Rect rect = GeckoAppShell.getScreenSizeIgnoreOverride();
+ final int orientation =
+ rect.width() >= rect.height() ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ return update(getScreenOrientation(orientation, getRotation()));
+ }
+
+ /*
+ * Update screen orientation.
+ * Retrieve orientation and rotation via Display.
+ *
+ * @param aDisplay The Display that has screen orientation information
+ *
+ * @return Whether the screen orientation has changed.
+ */
+ public boolean update(final Display aDisplay) {
+ return update(getScreenOrientation(aDisplay));
+ }
+
+ /*
+ * 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(final 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 synchronized boolean update(final ScreenOrientation aScreenOrientation) {
+ // Gecko expects a definite screen orientation, so we default to the
+ // primary orientations.
+ final ScreenOrientation screenOrientation;
+ if ((aScreenOrientation.value & ScreenOrientation.PORTRAIT_PRIMARY.value) != 0) {
+ screenOrientation = ScreenOrientation.PORTRAIT_PRIMARY;
+ } else if ((aScreenOrientation.value & ScreenOrientation.PORTRAIT_SECONDARY.value) != 0) {
+ screenOrientation = ScreenOrientation.PORTRAIT_SECONDARY;
+ } else if ((aScreenOrientation.value & ScreenOrientation.LANDSCAPE_PRIMARY.value) != 0) {
+ screenOrientation = ScreenOrientation.LANDSCAPE_PRIMARY;
+ } else if ((aScreenOrientation.value & ScreenOrientation.LANDSCAPE_SECONDARY.value) != 0) {
+ screenOrientation = ScreenOrientation.LANDSCAPE_SECONDARY;
+ } else {
+ screenOrientation = ScreenOrientation.PORTRAIT_PRIMARY;
+ }
+ if (mScreenOrientation == screenOrientation) {
+ return false;
+ }
+ mScreenOrientation = screenOrientation;
+ Log.d(LOGTAG, "updating to new orientation " + mScreenOrientation);
+ notifyListeners(mScreenOrientation);
+ ScreenManagerHelper.refreshScreenInfo();
+ return true;
+ }
+
+ private void notifyListeners(final ScreenOrientation newOrientation) {
+ final Runnable notifier =
+ new Runnable() {
+ @Override
+ public void run() {
+ for (final OrientationChangeListener listener : mListeners) {
+ listener.onScreenOrientationChanged(newOrientation);
+ }
+ }
+ };
+
+ if (ThreadUtils.isOnUiThread()) {
+ notifier.run();
+ } else {
+ ThreadUtils.runOnUiThread(notifier);
+ }
+ }
+
+ /*
+ * @return The Gecko screen orientation derived from Android orientation and
+ * rotation.
+ */
+ public ScreenOrientation getScreenOrientation() {
+ return mScreenOrientation;
+ }
+
+ /*
+ * 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(
+ final int aAndroidOrientation, final int aRotation) {
+ final boolean isPrimary = aRotation == Surface.ROTATION_0 || aRotation == Surface.ROTATION_90;
+ if (aAndroidOrientation == 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 == 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;
+ }
+
+ /*
+ * Get the Gecko orientation from Display.
+ *
+ * @param aDisplay The display that has orientation information.
+ *
+ * @return Gecko screen orientation.
+ */
+ private ScreenOrientation getScreenOrientation(final Display aDisplay) {
+ final Rect rect = GeckoAppShell.getScreenSizeIgnoreOverride();
+ final int orientation =
+ rect.width() >= rect.height() ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ return getScreenOrientation(orientation, aDisplay.getRotation());
+ }
+
+ /*
+ * @return Device rotation converted to an angle.
+ */
+ public short getAngle() {
+ switch (getRotation()) {
+ case Surface.ROTATION_0:
+ return 0;
+ case Surface.ROTATION_90:
+ return 90;
+ case Surface.ROTATION_180:
+ return 180;
+ case Surface.ROTATION_270:
+ return 270;
+ default:
+ Log.w(LOGTAG, "getAngle: unexpected rotation value");
+ return 0;
+ }
+ }
+
+ /*
+ * @return Device rotation.
+ */
+ private int getRotation() {
+ return GeckoAppShell.getRotation();
+ }
+}