| Index: chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
|
| diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f560b5f0a276470828e7da10cae8bd660c161ee5
|
| --- /dev/null
|
| +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelEventFilterTest.java
|
| @@ -0,0 +1,492 @@
|
| +// Copyright 2016 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.chrome.browser.compositor.bottombar;
|
| +
|
| +import android.content.Context;
|
| +import android.test.InstrumentationTestCase;
|
| +import android.test.suitebuilder.annotation.SmallTest;
|
| +import android.view.MotionEvent;
|
| +import android.view.ViewConfiguration;
|
| +import android.view.ViewGroup;
|
| +
|
| +import org.chromium.base.test.util.Feature;
|
| +import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilterHost;
|
| +import org.chromium.chrome.browser.compositor.layouts.eventfilter.OverlayPanelEventFilter;
|
| +import org.chromium.content.browser.ContentViewCore;
|
| +
|
| +/**
|
| + * Class responsible for testing the OverlayPanelEventFilter.
|
| + */
|
| +public class OverlayPanelEventFilterTest extends InstrumentationTestCase {
|
| +
|
| + private static final float PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP = 50.f;
|
| + private static final float BAR_HEIGHT_DP = 100.f;
|
| +
|
| + private static final float LAYOUT_WIDTH_DP = 600.f;
|
| + private static final float LAYOUT_HEIGHT_DP = 800.f;
|
| +
|
| + // A small value used to check whether two floats are almost equal.
|
| + private static final float EPSILON = 1e-04f;
|
| +
|
| + private float mTouchSlopDp;
|
| + private float mDpToPx;
|
| +
|
| + private float mAlmostMaximizedContentOffsetYDp;
|
| + private float mMaximizedContentOffsetYDp;
|
| +
|
| + private float mContentVerticalScroll;
|
| +
|
| + private boolean mWasTapDetectedOnContent;
|
| + private boolean mWasScrollDetectedOnContent;
|
| +
|
| + private MockOverlayPanel mPanel;
|
| + private OverlayPanelEventFilterWrapper mEventFilter;
|
| +
|
| + private boolean mShouldLockHorizontalMotionInContent;
|
| + private MotionEvent mEventPropagatedToContent;
|
| + private boolean mEventWasScroll;
|
| + private boolean mEventWasTap;
|
| +
|
| + // --------------------------------------------------------------------------------------------
|
| + // OverlayPanelEventFilterWrapper
|
| + // --------------------------------------------------------------------------------------------
|
| +
|
| + /**
|
| + * Wrapper around OverlayPanelEventFilter used by tests.
|
| + */
|
| + public final class OverlayPanelEventFilterWrapper extends OverlayPanelEventFilter {
|
| + public OverlayPanelEventFilterWrapper(Context context, EventFilterHost host,
|
| + OverlayPanel panel) {
|
| + super(context, host, panel);
|
| + }
|
| +
|
| + @Override
|
| + protected float getContentViewVerticalScroll() {
|
| + return mContentVerticalScroll;
|
| + }
|
| +
|
| + @Override
|
| + protected void propagateEventToContentViewCore(MotionEvent e) {
|
| + mEventPropagatedToContent = MotionEvent.obtain(e);
|
| + super.propagateEventToContentViewCore(e);
|
| + mEventPropagatedToContent.recycle();
|
| + }
|
| +
|
| + @Override
|
| + protected boolean handleSingleTapUp(MotionEvent e) {
|
| + boolean handled = super.handleSingleTapUp(e);
|
| + mEventWasTap = true;
|
| + return handled;
|
| + }
|
| +
|
| + @Override
|
| + protected boolean handleScroll(MotionEvent e1, MotionEvent e2, float distanceY) {
|
| + boolean handled = super.handleScroll(e1, e2, distanceY);
|
| + mEventWasScroll = true;
|
| + return handled;
|
| + }
|
| + }
|
| +
|
| + // --------------------------------------------------------------------------------------------
|
| + // StubbedContentViewCore
|
| + // --------------------------------------------------------------------------------------------
|
| +
|
| + private final class StubbedContentViewCore extends ContentViewCore {
|
| + public StubbedContentViewCore(Context context) {
|
| + super(context);
|
| + }
|
| +
|
| + @Override
|
| + public ViewGroup getContainerView() {
|
| + return new ViewGroup(getContext()) {
|
| + @Override
|
| + public boolean dispatchTouchEvent(MotionEvent e) {
|
| + if (e.getActionMasked() != MotionEvent.ACTION_CANCEL) {
|
| + mWasScrollDetectedOnContent = mEventWasScroll;
|
| + mWasTapDetectedOnContent = mEventWasTap;
|
| +
|
| + // Check that the event offset is correct.
|
| + if (!mShouldLockHorizontalMotionInContent) {
|
| + float propagatedEventY = mEventPropagatedToContent.getY();
|
| + float offsetY = mPanel.getContentY() * mDpToPx;
|
| + assertEquals(propagatedEventY - offsetY, e.getY(), EPSILON);
|
| + }
|
| + } else {
|
| + mWasScrollDetectedOnContent = false;
|
| + mWasTapDetectedOnContent = false;
|
| + }
|
| + return super.dispatchTouchEvent(e);
|
| + }
|
| +
|
| + @Override
|
| + public void onLayout(boolean changed, int l, int t, int r, int b) {}
|
| + };
|
| + }
|
| + }
|
| +
|
| + // --------------------------------------------------------------------------------------------
|
| + // MockOverlayPanel
|
| + // --------------------------------------------------------------------------------------------
|
| +
|
| + /**
|
| + * Mocks an OverlayPanel, so it doesn't create ContentViewCore.
|
| + */
|
| + public final class MockOverlayPanel extends OverlayPanel {
|
| + private boolean mWasTapDetectedOnPanel = false;
|
| + private boolean mWasScrollDetectedOnPanel = false;
|
| + private ContentViewCore mContentViewCore;
|
| +
|
| + public MockOverlayPanel(Context context, OverlayPanelManager panelManager) {
|
| + super(context, null, null, panelManager);
|
| + mContentViewCore = new StubbedContentViewCore(context);
|
| + }
|
| +
|
| + @Override
|
| + public OverlayPanelContent createNewOverlayPanelContent() {
|
| + return new MockOverlayPanelContent();
|
| + }
|
| +
|
| + /**
|
| + * Override creation and destruction of the ContentViewCore as they rely on native methods.
|
| + */
|
| + private class MockOverlayPanelContent extends OverlayPanelContent {
|
| + public MockOverlayPanelContent() {
|
| + super(null, null, null);
|
| + }
|
| +
|
| + @Override
|
| + public void removeLastHistoryEntry(String url, long timeInMs) {}
|
| + }
|
| +
|
| + @Override
|
| + public ContentViewCore getContentViewCore() {
|
| + return mContentViewCore;
|
| + }
|
| +
|
| + public boolean getWasTapDetected() {
|
| + return mWasTapDetectedOnPanel;
|
| + }
|
| +
|
| + public boolean getWasScrollDetected() {
|
| + return mWasScrollDetectedOnPanel;
|
| + }
|
| +
|
| + // GestureHandler overrides.
|
| +
|
| + @Override
|
| + public void onDown(float x, float y, boolean fromMouse, int buttons) {}
|
| +
|
| + @Override
|
| + public void onUpOrCancel() {}
|
| +
|
| + @Override
|
| + public void drag(float x, float y, float dx, float dy, float tx, float ty) {
|
| + mWasScrollDetectedOnPanel = true;
|
| + }
|
| +
|
| + @Override
|
| + public void click(float x, float y, boolean fromMouse, int buttons) {
|
| + mWasTapDetectedOnPanel = true;
|
| + }
|
| +
|
| + @Override
|
| + public void fling(float x, float y, float velocityX, float velocityY) {}
|
| +
|
| + @Override
|
| + public void onLongPress(float x, float y) {}
|
| +
|
| + @Override
|
| + public void onPinch(float x0, float y0, float x1, float y1, boolean firstEvent) {}
|
| + }
|
| +
|
| + // --------------------------------------------------------------------------------------------
|
| + // Test Suite
|
| + // --------------------------------------------------------------------------------------------
|
| +
|
| + @Override
|
| + protected void setUp() throws Exception {
|
| + super.setUp();
|
| +
|
| + Context context = getInstrumentation().getTargetContext();
|
| +
|
| + mDpToPx = context.getResources().getDisplayMetrics().density;
|
| + mTouchSlopDp = ViewConfiguration.get(context).getScaledTouchSlop() / mDpToPx;
|
| +
|
| + mPanel = new MockOverlayPanel(context, new OverlayPanelManager());
|
| + mEventFilter = new OverlayPanelEventFilterWrapper(context, null, mPanel);
|
| +
|
| + mPanel.setSearchBarHeightForTesting(BAR_HEIGHT_DP);
|
| + mPanel.setHeightForTesting(LAYOUT_HEIGHT_DP);
|
| + mPanel.setIsFullWidthSizePanelForTesting(true);
|
| +
|
| + // NOTE(pedrosimonetti): This should be called after calling the method
|
| + // setIsFullWidthSizePanelForTesting(), otherwise it will crash the test.
|
| + mPanel.onSizeChanged(LAYOUT_WIDTH_DP, LAYOUT_HEIGHT_DP);
|
| +
|
| + setContentViewVerticalScroll(0);
|
| +
|
| + mAlmostMaximizedContentOffsetYDp =
|
| + PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP + BAR_HEIGHT_DP;
|
| + mMaximizedContentOffsetYDp = BAR_HEIGHT_DP;
|
| +
|
| + mWasTapDetectedOnContent = false;
|
| + mWasScrollDetectedOnContent = false;
|
| +
|
| + mShouldLockHorizontalMotionInContent = false;
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testTapContentView() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + // Simulate tap.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionUpEvent(0.f, mAlmostMaximizedContentOffsetYDp + 1.f);
|
| +
|
| + assertFalse(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertTrue(mWasTapDetectedOnContent);
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testScrollingContentViewDragsPanel() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + // Simulate swipe up sequence.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp);
|
| + simulateActionUpEvent(0.f, mMaximizedContentOffsetYDp);
|
| +
|
| + assertTrue(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testScrollUpContentView() {
|
| + positionPanelInMaximizedState();
|
| +
|
| + // Simulate swipe up sequence.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp);
|
| + simulateActionUpEvent(0.f, mMaximizedContentOffsetYDp);
|
| +
|
| + assertFalse(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertTrue(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testScrollDownContentView() {
|
| + positionPanelInMaximizedState();
|
| +
|
| + // When the Panel is maximized and the scroll position is greater than zero, a swipe down
|
| + // on the ContentView should trigger a scroll on it.
|
| + setContentViewVerticalScroll(100.f);
|
| +
|
| + // Simulate swipe down sequence.
|
| + simulateActionDownEvent(0.f, mMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionMoveEvent(0.f, mAlmostMaximizedContentOffsetYDp);
|
| + simulateActionUpEvent(0.f, mAlmostMaximizedContentOffsetYDp);
|
| +
|
| + assertFalse(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertTrue(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testDragByOverscrollingContentView() {
|
| + positionPanelInMaximizedState();
|
| +
|
| + // When the Panel is maximized and the scroll position is zero, a swipe down on the
|
| + // ContentView should trigger a swipe on the Panel.
|
| + setContentViewVerticalScroll(0.f);
|
| +
|
| + // Simulate swipe down sequence.
|
| + simulateActionDownEvent(0.f, mMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionMoveEvent(0.f, mAlmostMaximizedContentOffsetYDp);
|
| + simulateActionUpEvent(0.f, mAlmostMaximizedContentOffsetYDp);
|
| +
|
| + assertTrue(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testUnwantedScrollDoesNotHappenInContentView() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + float contentViewOffsetYStart = mAlmostMaximizedContentOffsetYDp + 1.f;
|
| + float contentViewOffsetYEnd = mMaximizedContentOffsetYDp - 1.f;
|
| +
|
| + // Simulate swipe up to maximized position.
|
| + simulateActionDownEvent(0.f, contentViewOffsetYStart);
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp);
|
| + positionPanelInMaximizedState();
|
| +
|
| + // Confirm that the Panel got a scroll event.
|
| + assertTrue(mPanel.getWasScrollDetected());
|
| +
|
| + // Continue the swipe up for one more dp. From now on, the events might be forwarded
|
| + // to the ContentView.
|
| + simulateActionMoveEvent(0.f, contentViewOffsetYEnd);
|
| + simulateActionUpEvent(0.f, contentViewOffsetYEnd);
|
| +
|
| + // But 1 dp is not enough to trigger a scroll in the ContentView, and in this
|
| + // particular case, it should also not trigger a tap because the total displacement
|
| + // of the touch gesture is greater than the touch slop.
|
| + float contentViewOffsetDelta =
|
| + contentViewOffsetYStart - contentViewOffsetYEnd;
|
| + assertTrue(Math.abs(contentViewOffsetDelta) > mTouchSlopDp);
|
| +
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testDragPanelThenContinuouslyScrollContentView() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + // Simulate swipe up to maximized position.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp + 1.f);
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp);
|
| + positionPanelInMaximizedState();
|
| +
|
| + // Confirm that the Panel got a scroll event.
|
| + assertTrue(mPanel.getWasScrollDetected());
|
| +
|
| + // Continue the swipe up for one more dp. From now on, the events might be forwarded
|
| + // to the ContentView.
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp - 1.f);
|
| +
|
| + // Now keep swiping up an amount greater than the touch slop. In this case a scroll
|
| + // should be triggered in the ContentView.
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp - 2 * mTouchSlopDp);
|
| + simulateActionUpEvent(0.f, mMaximizedContentOffsetYDp - 2 * mTouchSlopDp);
|
| +
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertTrue(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testTapPanel() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + // Simulate tap.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp - 1.f);
|
| + simulateActionUpEvent(0.f, mAlmostMaximizedContentOffsetYDp - 1.f);
|
| +
|
| + assertFalse(mPanel.getWasScrollDetected());
|
| + assertTrue(mPanel.getWasTapDetected());
|
| +
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + @SmallTest
|
| + @Feature({"OverlayPanel"})
|
| + public void testScrollPanel() {
|
| + positionPanelInAlmostMaximizedState();
|
| +
|
| + // Simulate swipe up sequence.
|
| + simulateActionDownEvent(0.f, mAlmostMaximizedContentOffsetYDp - 1.f);
|
| + simulateActionMoveEvent(0.f, mMaximizedContentOffsetYDp);
|
| + simulateActionUpEvent(0.f, mMaximizedContentOffsetYDp);
|
| +
|
| + assertTrue(mPanel.getWasScrollDetected());
|
| + assertFalse(mPanel.getWasTapDetected());
|
| +
|
| + assertFalse(mWasScrollDetectedOnContent);
|
| + assertFalse(mWasTapDetectedOnContent);
|
| + }
|
| +
|
| + // --------------------------------------------------------------------------------------------
|
| + // Helpers
|
| + // --------------------------------------------------------------------------------------------
|
| +
|
| + /**
|
| + * Positions the Panel in the almost maximized state.
|
| + */
|
| + private void positionPanelInAlmostMaximizedState() {
|
| + mPanel.setMaximizedForTesting(false);
|
| + mPanel.setOffsetYForTesting(PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP);
|
| + }
|
| +
|
| + /**
|
| + * Positions the Panel in the maximized state.
|
| + */
|
| + private void positionPanelInMaximizedState() {
|
| + mPanel.setMaximizedForTesting(true);
|
| + mPanel.setOffsetYForTesting(0);
|
| + }
|
| +
|
| + /**
|
| + * Sets the vertical scroll position of the ContentView.
|
| + * @param contentViewVerticalScroll The vertical scroll position.
|
| + */
|
| + private void setContentViewVerticalScroll(float contentViewVerticalScroll) {
|
| + mContentVerticalScroll = contentViewVerticalScroll;
|
| + }
|
| +
|
| + /**
|
| + * Simulates a MotionEvent in the OverlayPanelEventFilter.
|
| + * @param action The event's action.
|
| + * @param x The event's x coordinate in dps.
|
| + * @param y The event's y coordinate in dps.
|
| + */
|
| + private void simulateEvent(int action, float x, float y) {
|
| + MotionEvent motionEvent = MotionEvent.obtain(0, 0, action, x * mDpToPx, y * mDpToPx, 0);
|
| + mEventFilter.onTouchEventInternal(motionEvent);
|
| + }
|
| +
|
| + /**
|
| + * Simulates a MotionEvent.ACTION_DOWN in the OverlayPanelEventFilter.
|
| + * @param x The event's x coordinate in dps.
|
| + * @param y The event's y coordinate in dps.
|
| + */
|
| + private void simulateActionDownEvent(float x, float y) {
|
| + simulateEvent(MotionEvent.ACTION_DOWN, x, y);
|
| + }
|
| +
|
| + /**
|
| + * Simulates a MotionEvent.ACTION_MOVE in the OverlayPanelEventFilter.
|
| + * @param x The event's x coordinate in dps.
|
| + * @param y The event's y coordinate in dps.
|
| + */
|
| + private void simulateActionMoveEvent(float x, float y) {
|
| + simulateEvent(MotionEvent.ACTION_MOVE, x, y);
|
| + }
|
| +
|
| + /**
|
| + * Simulates a MotionEvent.ACTION_UP in the OverlayPanelEventFilter.
|
| + * @param x The event's x coordinate in dps.
|
| + * @param y The event's y coordinate in dps.
|
| + */
|
| + private void simulateActionUpEvent(float x, float y) {
|
| + simulateEvent(MotionEvent.ACTION_UP, x, y);
|
| + }
|
| +}
|
|
|