Commit 631df257 authored by mlamouri@chromium.org's avatar mlamouri@chromium.org

Create ScreenOrientationListener and make it SDK-dependant.

This CL is adding a ScreenOrientationListener abstract class with one
implementation that is based on the current mechanism used for listening
to screen orientation changes. The other implementation is based on
DisplayListener but this API is only available from API Level 17.

BUG=342714, 346696

Review URL: https://codereview.chromium.org/179783003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255750 0039d316-1c4b-4281-b951-d872f2087c98
parent fe3f8f6a
...@@ -32,10 +32,8 @@ import android.view.HapticFeedbackConstants; ...@@ -32,10 +32,8 @@ import android.view.HapticFeedbackConstants;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.Surface;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
...@@ -56,6 +54,7 @@ import org.chromium.base.ObserverList; ...@@ -56,6 +54,7 @@ import org.chromium.base.ObserverList;
import org.chromium.base.ObserverList.RewindableIterator; import org.chromium.base.ObserverList.RewindableIterator;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.content.R; import org.chromium.content.R;
import org.chromium.content.browser.ScreenOrientationListener.ScreenOrientationObserver;
import org.chromium.content.browser.accessibility.AccessibilityInjector; import org.chromium.content.browser.accessibility.AccessibilityInjector;
import org.chromium.content.browser.accessibility.BrowserAccessibilityManager; import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
import org.chromium.content.browser.input.AdapterInputConnection; import org.chromium.content.browser.input.AdapterInputConnection;
...@@ -89,7 +88,8 @@ import java.util.Map; ...@@ -89,7 +88,8 @@ import java.util.Map;
* being tied to the view system. * being tied to the view system.
*/ */
@JNINamespace("content") @JNINamespace("content")
public class ContentViewCore implements NavigationClient, AccessibilityStateChangeListener { public class ContentViewCore
implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
private static final String TAG = "ContentViewCore"; private static final String TAG = "ContentViewCore";
...@@ -708,8 +708,6 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -708,8 +708,6 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
resetGestureDetectors(); resetGestureDetectors();
} }
}; };
sendOrientationChangeEvent();
} }
@CalledByNative @CalledByNative
...@@ -823,6 +821,7 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -823,6 +821,7 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
mRetainedJavaScriptObjects.clear(); mRetainedJavaScriptObjects.clear();
unregisterAccessibilityContentObserver(); unregisterAccessibilityContentObserver();
mGestureStateListeners.clear(); mGestureStateListeners.clear();
ScreenOrientationListener.getInstance().removeObserver(this);
} }
private void unregisterAccessibilityContentObserver() { private void unregisterAccessibilityContentObserver() {
...@@ -1445,6 +1444,8 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -1445,6 +1444,8 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
@SuppressWarnings("javadoc") @SuppressWarnings("javadoc")
public void onAttachedToWindow() { public void onAttachedToWindow() {
setAccessibilityState(mAccessibilityManager.isEnabled()); setAccessibilityState(mAccessibilityManager.isEnabled());
ScreenOrientationListener.getInstance().addObserver(this, mContext);
} }
/** /**
...@@ -1457,6 +1458,8 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -1457,6 +1458,8 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
hidePopupDialog(); hidePopupDialog();
mZoomControlsDelegate.dismissZoomPicker(); mZoomControlsDelegate.dismissZoomPicker();
unregisterAccessibilityContentObserver(); unregisterAccessibilityContentObserver();
ScreenOrientationListener.getInstance().removeObserver(this);
} }
/** /**
...@@ -1509,15 +1512,7 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -1509,15 +1512,7 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
mInputMethodManagerWrapper.restartInput(mContainerView); mInputMethodManagerWrapper.restartInput(mContainerView);
} }
mContainerViewInternals.super_onConfigurationChanged(newConfig); mContainerViewInternals.super_onConfigurationChanged(newConfig);
// Make sure the size is up to date in JavaScript's window.onorientationchanged.
mContainerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
mContainerView.removeOnLayoutChangeListener(this);
sendOrientationChangeEvent();
}
});
// To request layout has side effect, but it seems OK as it only happen in // To request layout has side effect, but it seems OK as it only happen in
// onConfigurationChange and layout has to be changed in most case. // onConfigurationChange and layout has to be changed in most case.
mContainerView.requestLayout(); mContainerView.requestLayout();
...@@ -1943,32 +1938,12 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -1943,32 +1938,12 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
} }
/** /**
* Get the screen orientation from the OS and push it to WebKit. * Send the screen orientation value to the renderer.
*
* TODO(husky): Add a hook for mock orientations.
*/ */
private void sendOrientationChangeEvent() { private void sendOrientationChangeEvent(int orientation) {
if (mNativeContentViewCore == 0) return; if (mNativeContentViewCore == 0) return;
WindowManager windowManager = nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation);
(WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
switch (windowManager.getDefaultDisplay().getRotation()) {
case Surface.ROTATION_90:
nativeSendOrientationChangeEvent(mNativeContentViewCore, 90);
break;
case Surface.ROTATION_180:
nativeSendOrientationChangeEvent(mNativeContentViewCore, 180);
break;
case Surface.ROTATION_270:
nativeSendOrientationChangeEvent(mNativeContentViewCore, -90);
break;
case Surface.ROTATION_0:
nativeSendOrientationChangeEvent(mNativeContentViewCore, 0);
break;
default:
Log.w(TAG, "Unknown rotation!");
break;
}
} }
/** /**
...@@ -3142,6 +3117,11 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan ...@@ -3142,6 +3117,11 @@ public class ContentViewCore implements NavigationClient, AccessibilityStateChan
updateGestureStateListener(GestureEventType.FLING_END); updateGestureStateListener(GestureEventType.FLING_END);
} }
@Override
public void onScreenOrientationChanged(int orientation) {
sendOrientationChangeEvent(orientation);
}
private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl); private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl); private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl);
......
// 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");
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment