| Index: content/public/android/java/src/org/chromium/content/browser/ScreenOrientationListener.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ScreenOrientationListener.java b/content/public/android/java/src/org/chromium/content/browser/ScreenOrientationListener.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7e12861b129d8745c3025f5efc9c841fa0009e3a
|
| --- /dev/null
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ScreenOrientationListener.java
|
| @@ -0,0 +1,286 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.content.browser;
|
| +
|
| +import android.content.ComponentCallbacks;
|
| +import android.content.Context;
|
| +import android.content.res.Configuration;
|
| +import android.hardware.display.DisplayManager;
|
| +import android.hardware.display.DisplayManager.DisplayListener;
|
| +import android.os.Build;
|
| +import android.view.Surface;
|
| +import android.view.WindowManager;
|
| +
|
| +import org.chromium.base.ObserverList;
|
| +import org.chromium.base.ThreadUtils;
|
| +
|
| +/**
|
| + * ScreenOrientationListener is a class that informs its observers when the
|
| + * screen orientation changes.
|
| + */
|
| +class ScreenOrientationListener {
|
| +
|
| + /**
|
| + * Observes changes in screen orientation.
|
| + */
|
| + public interface ScreenOrientationObserver {
|
| + /**
|
| + * Called whenever the screen orientation changes.
|
| + *
|
| + * @param orientation The orientation angle of the screen.
|
| + */
|
| + void onScreenOrientationChanged(int orientation);
|
| + }
|
| +
|
| + /**
|
| + * ScreenOrientationListenerBackend is an interface that abstract the
|
| + * mechanism used for the actual screen orientation listening. The reason
|
| + * being that from Android API Level 17 DisplayListener will be used. Before
|
| + * that, an unreliable solution based on onConfigurationChanged has to be
|
| + * used.
|
| + */
|
| + private interface ScreenOrientationListenerBackend {
|
| +
|
| + /**
|
| + * Starts to listen for screen orientation changes. This will be called
|
| + * when the first observer is added.
|
| + */
|
| + void startListening();
|
| +
|
| + /**
|
| + * Stops to listen for screen orientation changes. This will be called
|
| + * when the last observer is removed.
|
| + */
|
| + void stopListening();
|
| + }
|
| +
|
| + /**
|
| + * ScreenOrientationConfigurationListener implements ScreenOrientationListenerBackend
|
| + * to use ComponentCallbacks in order to listen for screen orientation
|
| + * changes.
|
| + *
|
| + * This method is known to not correctly detect 180 degrees changes but it
|
| + * is the only method that will work before API Level 17 (excluding polling).
|
| + */
|
| + private class ScreenOrientationConfigurationListener
|
| + implements ScreenOrientationListenerBackend, ComponentCallbacks {
|
| +
|
| + // ScreenOrientationListenerBackend implementation:
|
| +
|
| + @Override
|
| + public void startListening() {
|
| + mAppContext.registerComponentCallbacks(this);
|
| + }
|
| +
|
| + @Override
|
| + public void stopListening() {
|
| + mAppContext.unregisterComponentCallbacks(this);
|
| + }
|
| +
|
| + // ComponentCallbacks implementation:
|
| +
|
| + @Override
|
| + public void onConfigurationChanged(Configuration newConfig) {
|
| + notifyObservers();
|
| + }
|
| +
|
| + @Override
|
| + public void onLowMemory() {
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * ScreenOrientationDisplayListener implements ScreenOrientationListenerBackend
|
| + * to use DisplayListener in order to listen for screen orientation changes.
|
| + *
|
| + * This method is reliable but DisplayListener is only available for API Level 17+.
|
| + */
|
| + private class ScreenOrientationDisplayListener
|
| + implements ScreenOrientationListenerBackend, DisplayListener {
|
| +
|
| + // ScreenOrientationListenerBackend implementation:
|
| +
|
| + @Override
|
| + public void startListening() {
|
| + DisplayManager displayManager =
|
| + (DisplayManager) mAppContext.getSystemService(Context.DISPLAY_SERVICE);
|
| + displayManager.registerDisplayListener(this, null);
|
| + }
|
| +
|
| + @Override
|
| + public void stopListening() {
|
| + DisplayManager displayManager =
|
| + (DisplayManager) mAppContext.getSystemService(Context.DISPLAY_SERVICE);
|
| + displayManager.unregisterDisplayListener(this);
|
| + }
|
| +
|
| + // DisplayListener implementation:
|
| +
|
| + @Override
|
| + public void onDisplayAdded(int displayId) {
|
| + }
|
| +
|
| + @Override
|
| + public void onDisplayRemoved(int displayId) {
|
| + }
|
| +
|
| + @Override
|
| + public void onDisplayChanged(int displayId) {
|
| + notifyObservers();
|
| + }
|
| +
|
| + }
|
| +
|
| + private static final String TAG = "ScreenOrientationListener";
|
| +
|
| + // List of observers to notify when the screen orientation changes.
|
| + private final ObserverList<ScreenOrientationObserver> mObservers =
|
| + new ObserverList<ScreenOrientationObserver>();
|
| +
|
| + // Number of observers currently in |mObservers|.
|
| + // TODO(mlamouri): hopefully, we can get ObserverList to provide that,
|
| + // http://crbug.com/347558
|
| + private int mObserverCount;
|
| +
|
| + // mOrientation will be updated every time the orientation changes. When not
|
| + // listening for changes, the value will be invalid and will be updated when
|
| + // starting to listen again.
|
| + private int mOrientation;
|
| +
|
| + // Current application context derived from the first context being received.
|
| + private Context mAppContext;
|
| +
|
| + private ScreenOrientationListenerBackend mBackend;
|
| +
|
| + private static ScreenOrientationListener sInstance;
|
| +
|
| + /**
|
| + * Returns a ScreenOrientationListener implementation based on the device's
|
| + * supported API level.
|
| + */
|
| + public static ScreenOrientationListener getInstance() {
|
| + ThreadUtils.assertOnUiThread();
|
| +
|
| + if (sInstance == null) {
|
| + sInstance = new ScreenOrientationListener();
|
| + }
|
| +
|
| + return sInstance;
|
| + }
|
| +
|
| + private ScreenOrientationListener() {
|
| + mBackend = Build.VERSION.SDK_INT >= 17 ?
|
| + new ScreenOrientationDisplayListener() :
|
| + new ScreenOrientationConfigurationListener();
|
| + }
|
| +
|
| + /**
|
| + * Add |observer| in the ScreenOrientationListener observer list and
|
| + * immediately call |onScreenOrientationChanged| on it with the current
|
| + * orientation value.
|
| + *
|
| + * @param observer The observer that will get notified.
|
| + * @param context The context associated with this observer.
|
| + */
|
| + public void addObserver(ScreenOrientationObserver observer, Context context) {
|
| + if (mAppContext == null) {
|
| + mAppContext = context.getApplicationContext();
|
| + }
|
| +
|
| + assert mAppContext == context.getApplicationContext();
|
| + assert mAppContext != null;
|
| +
|
| + // TODO(mlamouri): we should check if the observer was really added,
|
| + // http://crbug.com/347557
|
| + if (mObservers.hasObserver(observer)) {
|
| + return;
|
| + }
|
| + mObservers.addObserver(observer);
|
| + mObserverCount++;
|
| +
|
| + // If we got our first observer, we should start listening.
|
| + if (mObserverCount == 1) {
|
| + updateOrientation();
|
| + mBackend.startListening();
|
| + }
|
| +
|
| + // We need to send the current value to the added observer as soon as
|
| + // possible but outside of the current stack.
|
| + final ScreenOrientationObserver obs = observer;
|
| + ThreadUtils.assertOnUiThread();
|
| + ThreadUtils.postOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + obs.onScreenOrientationChanged(mOrientation);
|
| + }
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Remove the |observer| from the ScreenOrientationListener observer list.
|
| + *
|
| + * @param observer The observer that will no longer receive notification.
|
| + */
|
| + public void removeObserver(ScreenOrientationObserver observer) {
|
| + // TODO(mlamouri): we should check if the observer was really removed,
|
| + // http://crbug.com/347557
|
| + if (!mObservers.hasObserver(observer)) {
|
| + return;
|
| + }
|
| + mObservers.removeObserver(observer);
|
| + mObserverCount--;
|
| +
|
| + if (mObserverCount == 0) {
|
| + // The last observer was removed, we should just stop listening.
|
| + mBackend.stopListening();
|
| + }
|
| +
|
| + assert mObserverCount >= 0;
|
| + }
|
| +
|
| + /**
|
| + * This should be called by classes extending ScreenOrientationListener when
|
| + * it is possible that there is a screen orientation change. If there is an
|
| + * actual change, the observers will get notified.
|
| + */
|
| + private void notifyObservers() {
|
| + int previousOrientation = mOrientation;
|
| + updateOrientation();
|
| +
|
| + if (mOrientation == previousOrientation) {
|
| + return;
|
| + }
|
| +
|
| + for (ScreenOrientationObserver observer : mObservers) {
|
| + observer.onScreenOrientationChanged(mOrientation);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Updates |mOrientation| based on the default display rotation.
|
| + */
|
| + private void updateOrientation() {
|
| + WindowManager windowManager =
|
| + (WindowManager) mAppContext.getSystemService(Context.WINDOW_SERVICE);
|
| +
|
| + switch (windowManager.getDefaultDisplay().getRotation()) {
|
| + case Surface.ROTATION_0:
|
| + mOrientation = 0;
|
| + break;
|
| + case Surface.ROTATION_90:
|
| + mOrientation = 90;
|
| + break;
|
| + case Surface.ROTATION_180:
|
| + mOrientation = 180;
|
| + break;
|
| + case Surface.ROTATION_270:
|
| + mOrientation = -90;
|
| + break;
|
| + default:
|
| + throw new IllegalStateException(
|
| + "Display.getRotation() shouldn't return that value");
|
| + }
|
| + }
|
| +}
|
|
|