Index: chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEventFilterTest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEventFilterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEventFilterTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b438df3805845c1d89a5a9d15601ee3178253c66 |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchEventFilterTest.java |
@@ -0,0 +1,434 @@ |
+// Copyright 2015 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.contextualsearch; |
+ |
+import android.content.Context; |
+import android.test.InstrumentationTestCase; |
+import android.test.suitebuilder.annotation.SmallTest; |
+import android.view.GestureDetector; |
+import android.view.GestureDetector.SimpleOnGestureListener; |
+import android.view.MotionEvent; |
+import android.view.ViewConfiguration; |
+ |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; |
+import org.chromium.chrome.browser.compositor.eventfilter.MockEventFilterHost; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.ContextualSearchEventFilter; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilterHost; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.GestureHandler; |
+ |
+/** |
+ * Class responsible for testing the ContextualSearchEventFilter. |
+ */ |
+public class ContextualSearchEventFilterTest extends InstrumentationTestCase |
+ implements GestureHandler { |
+ |
+ private static final float SEARCH_PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP = 50.f; |
+ private static final float SEARCH_BAR_HEIGHT_DP = 100.f; |
+ |
+ private float mTouchSlopDp; |
+ private float mDpToPx; |
+ |
+ private float mAlmostMaximizedSearchContentViewOffsetYDp; |
+ private float mMaximizedSearchContentViewOffsetYDp; |
+ |
+ private float mSearchContentViewVerticalScroll; |
+ |
+ private boolean mWasTapDetectedOnSearchPanel; |
+ private boolean mWasScrollDetectedOnSearchPanel; |
+ private boolean mWasTapDetectedOnSearchContentView; |
+ private boolean mWasScrollDetectedOnSearchContentView; |
+ |
+ private ContextualSearchPanel mContextualSearchPanel; |
+ private ContextualSearchEventFilterWrapper mEventFilter; |
+ |
+ private boolean mShouldLockHorizontalMotionInSearchContentView; |
+ private MotionEvent mEventPropagatedToSearchContentView; |
+ |
+ // -------------------------------------------------------------------------------------------- |
+ // MockEventFilterHostWrapper |
+ // -------------------------------------------------------------------------------------------- |
+ |
+ /** |
+ * Wrapper around MockEventFilterHost used to mimic the event forwarding mechanism |
+ * of the EventFilterHost. |
+ */ |
+ public class MockEventFilterHostWrapper extends MockEventFilterHost { |
+ GestureDetector mGestureDetector; |
+ |
+ public MockEventFilterHostWrapper(Context context) { |
+ mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { |
+ @Override |
+ public boolean onSingleTapUp(MotionEvent e) { |
+ mWasTapDetectedOnSearchContentView = true; |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) { |
+ mWasScrollDetectedOnSearchContentView = true; |
+ return true; |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public boolean propagateEvent(MotionEvent e) { |
+ // Check that the event offset is correct. |
+ if (!mShouldLockHorizontalMotionInSearchContentView) { |
+ float propagatedEventY = mEventPropagatedToSearchContentView.getY(); |
+ float offsetY = mContextualSearchPanel.getSearchContentViewOffsetY() * mDpToPx; |
+ assertEquals(propagatedEventY - offsetY, e.getY()); |
+ } |
+ |
+ // Propagates the event to the GestureDetector in order to be able to tell |
+ // if the gesture was properly triggered in the SearchContentView. |
+ return mGestureDetector.onTouchEvent(e); |
+ } |
+ |
+ } |
+ |
+ // -------------------------------------------------------------------------------------------- |
+ // ContextualSearchEventFilterWrapper |
+ // -------------------------------------------------------------------------------------------- |
+ |
+ /** |
+ * Wrapper around ContextualSearchEventFilter used by tests. |
+ */ |
+ public class ContextualSearchEventFilterWrapper extends ContextualSearchEventFilter { |
+ public ContextualSearchEventFilterWrapper(Context context, EventFilterHost host, |
+ GestureHandler handler, ContextualSearchPanel contextualSearchPanel) { |
+ super(context, host, handler, contextualSearchPanel); |
+ } |
+ |
+ @Override |
+ protected float getSearchContentViewVerticalScroll() { |
+ return mSearchContentViewVerticalScroll; |
+ } |
+ |
+ @Override |
+ protected void propagateEventToSearchContentView(MotionEvent e) { |
+ mEventPropagatedToSearchContentView = MotionEvent.obtain(e); |
+ super.propagateEventToSearchContentView(e); |
+ mEventPropagatedToSearchContentView.recycle(); |
+ } |
+ } |
+ |
+ // -------------------------------------------------------------------------------------------- |
+ // 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; |
+ |
+ EventFilterHost eventFilterHost = new MockEventFilterHostWrapper(context); |
+ mContextualSearchPanel = new ContextualSearchPanel(context, null); |
+ mEventFilter = new ContextualSearchEventFilterWrapper(context, eventFilterHost, this, |
+ mContextualSearchPanel); |
+ |
+ mContextualSearchPanel.setSearchBarHeightForTesting(SEARCH_BAR_HEIGHT_DP); |
+ |
+ setSearchContentViewVerticalScroll(0); |
+ |
+ mAlmostMaximizedSearchContentViewOffsetYDp = |
+ SEARCH_PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP + SEARCH_BAR_HEIGHT_DP; |
+ mMaximizedSearchContentViewOffsetYDp = SEARCH_BAR_HEIGHT_DP; |
+ |
+ mWasTapDetectedOnSearchPanel = false; |
+ mWasScrollDetectedOnSearchPanel = false; |
+ mWasTapDetectedOnSearchContentView = false; |
+ mWasScrollDetectedOnSearchContentView = false; |
+ |
+ mShouldLockHorizontalMotionInSearchContentView = false; |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testTapSearchContentView() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ // Simulate tap. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionUpEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp + 1.f); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertTrue(mWasTapDetectedOnSearchContentView); |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testScrollingSearchContentViewDragsSearchPanel() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ // Simulate swipe up sequence. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ simulateActionUpEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testScrollUpSearchContentView() { |
+ positionSearchPanelInMaximizedState(); |
+ |
+ // Simulate swipe up sequence. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ simulateActionUpEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testScrollDownSearchContentView() { |
+ positionSearchPanelInMaximizedState(); |
+ |
+ // When the Panel is maximized and the scroll position is greater than zero, a swipe down |
+ // on the SearchContentView should trigger a scroll on it. |
+ setSearchContentViewVerticalScroll(100.f); |
+ |
+ // Simulate swipe down sequence. |
+ simulateActionDownEvent(0.f, mMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionMoveEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp); |
+ simulateActionUpEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testDragByOverscrollingSearchContentView() { |
+ positionSearchPanelInMaximizedState(); |
+ |
+ // When the Panel is maximized and the scroll position is zero, a swipe down on the |
+ // SearchContentView should trigger a swipe on the SearchPanel. |
+ setSearchContentViewVerticalScroll(0.f); |
+ |
+ // Simulate swipe down sequence. |
+ simulateActionDownEvent(0.f, mMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionMoveEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp); |
+ simulateActionUpEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testUnwantedTapDoesNotHappenInSearchContentView() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ float searchContentViewOffsetYStart = mAlmostMaximizedSearchContentViewOffsetYDp + 1.f; |
+ float searchContentViewOffsetYEnd = mMaximizedSearchContentViewOffsetYDp - 1.f; |
+ |
+ // Simulate swipe up to maximized position. |
+ simulateActionDownEvent(0.f, searchContentViewOffsetYStart); |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ positionSearchPanelInMaximizedState(); |
+ |
+ // Confirm that the SearchPanel got a scroll event. |
+ assertTrue(mWasScrollDetectedOnSearchPanel); |
+ |
+ // Continue the swipe up for one more dp. From now on, the events might be forwarded |
+ // to the SearchContentView. |
+ simulateActionMoveEvent(0.f, searchContentViewOffsetYEnd); |
+ simulateActionUpEvent(0.f, searchContentViewOffsetYEnd); |
+ |
+ // But 1 dp is not enough to trigger a scroll in the SearchContentView, 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 searchContentViewOffsetDelta = |
+ searchContentViewOffsetYStart - searchContentViewOffsetYEnd; |
+ assertTrue(Math.abs(searchContentViewOffsetDelta) > mTouchSlopDp); |
+ |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testDragSearchPanelThenContinuouslyScrollSearchContentView() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ // Simulate swipe up to maximized position. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp + 1.f); |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ positionSearchPanelInMaximizedState(); |
+ |
+ // Confirm that the SearchPanel got a scroll event. |
+ assertTrue(mWasScrollDetectedOnSearchPanel); |
+ |
+ // Continue the swipe up for one more dp. From now on, the events might be forwarded |
+ // to the SearchContentView. |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp - 1.f); |
+ |
+ // Now keep swiping up an amount greater than the touch slop. In this case a scroll |
+ // should be triggered in the SearchContentView. |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp - 2 * mTouchSlopDp); |
+ simulateActionUpEvent(0.f, mMaximizedSearchContentViewOffsetYDp - 2 * mTouchSlopDp); |
+ |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testTapSearchPanel() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ // Simulate tap. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp - 1.f); |
+ simulateActionUpEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp - 1.f); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchPanel); |
+ assertTrue(mWasTapDetectedOnSearchPanel); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"ContextualSearch"}) |
+ public void testScrollSearchPanel() { |
+ positionSearchPanelInAlmostMaximizedState(); |
+ |
+ // Simulate swipe up sequence. |
+ simulateActionDownEvent(0.f, mAlmostMaximizedSearchContentViewOffsetYDp - 1.f); |
+ simulateActionMoveEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ simulateActionUpEvent(0.f, mMaximizedSearchContentViewOffsetYDp); |
+ |
+ assertTrue(mWasScrollDetectedOnSearchPanel); |
+ assertFalse(mWasTapDetectedOnSearchPanel); |
+ |
+ assertFalse(mWasScrollDetectedOnSearchContentView); |
+ assertFalse(mWasTapDetectedOnSearchContentView); |
+ } |
+ |
+ // -------------------------------------------------------------------------------------------- |
+ // Helpers |
+ // -------------------------------------------------------------------------------------------- |
+ |
+ /** |
+ * Positions the SearchPanel in the almost maximized state. |
+ */ |
+ private void positionSearchPanelInAlmostMaximizedState() { |
+ mContextualSearchPanel.setMaximizedForTesting(false); |
+ mContextualSearchPanel.setOffsetYForTesting(SEARCH_PANEL_ALMOST_MAXIMIZED_OFFSET_Y_DP); |
+ } |
+ |
+ /** |
+ * Positions the SearchPanel in the maximized state. |
+ */ |
+ private void positionSearchPanelInMaximizedState() { |
+ mContextualSearchPanel.setMaximizedForTesting(true); |
+ mContextualSearchPanel.setOffsetYForTesting(0); |
+ } |
+ |
+ /** |
+ * Sets the vertical scroll position of the SearchContentView. |
+ * @param searchContentViewVerticalScroll The vertical scroll position. |
+ */ |
+ private void setSearchContentViewVerticalScroll(float searchContentViewVerticalScroll) { |
+ mSearchContentViewVerticalScroll = searchContentViewVerticalScroll; |
+ } |
+ |
+ /** |
+ * Simulates a MotionEvent in the ContextualSearchEventFilter. |
+ * @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 ContextualSearchEventFilter. |
+ * @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 ContextualSearchEventFilter. |
+ * @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 ContextualSearchEventFilter. |
+ * @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); |
+ } |
+ |
+ // -------------------------------------------------------------------------------------------- |
+ // SearchPanel GestureHandler |
+ // -------------------------------------------------------------------------------------------- |
+ |
+ @Override |
+ public void onDown(float x, float y) {} |
+ |
+ @Override |
+ public void onUpOrCancel() {} |
+ |
+ @Override |
+ public void drag(float x, float y, float dx, float dy, float tx, float ty) { |
+ mWasScrollDetectedOnSearchPanel = true; |
+ } |
+ |
+ @Override |
+ public void click(float x, float y) { |
+ mWasTapDetectedOnSearchPanel = 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) {} |
+} |