Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/ContextualSearchEventFilter.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/ContextualSearchEventFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/ContextualSearchEventFilter.java |
deleted file mode 100644 |
index 18fceee3e01af3e0e3e75075e3ade859025c330c..0000000000000000000000000000000000000000 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/ContextualSearchEventFilter.java |
+++ /dev/null |
@@ -1,545 +0,0 @@ |
-// 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.compositor.layouts.eventfilter; |
- |
-import android.content.Context; |
-import android.view.GestureDetector; |
-import android.view.MotionEvent; |
-import android.view.ViewConfiguration; |
- |
-import org.chromium.base.VisibleForTesting; |
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; |
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager; |
- |
-import java.util.ArrayList; |
- |
-/** |
- * The {@link GestureEventFilter} used when Contextual Search Layout is being shown. It filters |
- * events that happen in the Search Content View area and propagates them to the appropriate |
- * Content View Core via {@link EventFilterHost}. Events that happen outside that area are |
- * propagated to the {@code ContextualSearchLayout} via {@code LayoutManagerPhone}. |
- */ |
-public class ContextualSearchEventFilter extends GestureEventFilter { |
- |
- /** |
- * The targets that can handle MotionEvents. |
- */ |
- private enum EventTarget { |
- UNDETERMINED, |
- SEARCH_PANEL, |
- SEARCH_CONTENT_VIEW |
- } |
- |
- /** |
- * The direction of the gesture. |
- */ |
- private enum GestureOrientation { |
- UNDETERMINED, |
- HORIZONTAL, |
- VERTICAL |
- } |
- |
- /** |
- * The boost factor that can be applied to prioritize vertical movements over horizontal ones. |
- */ |
- private static final float VERTICAL_DETERMINATION_BOOST = 1.25f; |
- |
- /** |
- * Manager to get the active OverlayPanel from. |
- */ |
- private OverlayPanelManager mPanelManager; |
- |
- /** |
- * The {@link GestureDetector} used to distinguish tap and scroll gestures. |
- */ |
- private final GestureDetector mGestureDetector; |
- |
- /** |
- * The target to propagate events to. |
- */ |
- private EventTarget mEventTarget; |
- |
- /** |
- * Whether the code is in the middle of the process of determining the event target. |
- */ |
- private boolean mIsDeterminingEventTarget; |
- |
- /** |
- * Whether the event target has been determined. |
- */ |
- private boolean mHasDeterminedEventTarget; |
- |
- /** |
- * The previous target the events were propagated to. |
- */ |
- private EventTarget mPreviousEventTarget; |
- |
- /** |
- * Whether the event target has changed since the last touch event. |
- */ |
- private boolean mHasChangedEventTarget; |
- |
- /** |
- * Whether the event target might change. This will be true in cases we know the overscroll |
- * and/or underscroll might happen, which means we'll have to constantly monitor the event |
- * targets in order to determine the exact moment the target has changed. |
- */ |
- private boolean mMayChangeEventTarget; |
- |
- /** |
- * Whether the gesture orientation has been determined. |
- */ |
- private boolean mHasDeterminedGestureOrientation; |
- |
- /** |
- * The current gesture orientation. |
- */ |
- private GestureOrientation mGestureOrientation; |
- |
- /** |
- * Whether the events are being recorded. |
- */ |
- private boolean mIsRecordingEvents; |
- |
- /** |
- * Whether the ACTION_DOWN that initiated the MotionEvent's stream was synthetic. |
- */ |
- private boolean mWasActionDownEventSynthetic; |
- |
- /** |
- * The X coordinate of the synthetic ACTION_DOWN MotionEvent. |
- */ |
- private float mSyntheticActionDownX; |
- |
- /** |
- * The Y coordinate of the synthetic ACTION_DOWN MotionEvent. |
- */ |
- private float mSyntheticActionDownY; |
- |
- /** |
- * The list of recorded events. |
- */ |
- private final ArrayList<MotionEvent> mRecordedEvents = new ArrayList<MotionEvent>(); |
- |
- /** |
- * The initial Y position of the current gesture. |
- */ |
- private float mInitialEventY; |
- |
- /** |
- * The square of ViewConfiguration.getScaledTouchSlop() in pixels used to calculate whether |
- * the finger has moved beyond the established threshold. |
- */ |
- private final float mTouchSlopSquarePx; |
- |
- /** |
- * Creates a {@link GestureEventFilter} with offset touch events. |
- * @param context The {@link Context} for Android. |
- * @param host The {@link EventFilterHost} for this event filter. |
- * @param handler The {@link GestureHandler} for this event filter. |
- * @param panelManager The {@link OverlayPanelManager} responsible for showing panels. |
- */ |
- public ContextualSearchEventFilter(Context context, EventFilterHost host, |
- GestureHandler handler, OverlayPanelManager panelManager) { |
- super(context, host, handler, false, false); |
- |
- mGestureDetector = new GestureDetector(context, new InternalGestureDetector()); |
- mPanelManager = panelManager; |
- |
- // Store the square of the platform touch slop in pixels to use in the scroll detection. |
- // See {@link ContextualSearchEventFilter#isDistanceGreaterThanTouchSlop}. |
- float touchSlopPx = ViewConfiguration.get(context).getScaledTouchSlop(); |
- mTouchSlopSquarePx = touchSlopPx * touchSlopPx; |
- |
- reset(); |
- } |
- |
- /** |
- * Gets the Search Content View's vertical scroll position. If the Search Content View |
- * is not available it returns -1. |
- * @return The Search Content View scroll position. |
- */ |
- @VisibleForTesting |
- protected float getSearchContentViewVerticalScroll() { |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel == null) return 0; |
- |
- return panel.getContentVerticalScroll(); |
- } |
- |
- @Override |
- public boolean onTouchEventInternal(MotionEvent e) { |
- final int action = e.getActionMasked(); |
- |
- if (!mIsDeterminingEventTarget && action == MotionEvent.ACTION_DOWN) { |
- mInitialEventY = e.getY(); |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel != null && panel.isCoordinateInsideContent( |
- e.getX() * mPxToDp, mInitialEventY * mPxToDp)) { |
- // If the DOWN event happened inside the Search Content View, we'll need |
- // to wait until the user has moved the finger beyond a certain threshold, |
- // so we can determine the gesture's orientation and consequently be able |
- // to tell if the Content View will accept the gesture. |
- mIsDeterminingEventTarget = true; |
- mMayChangeEventTarget = true; |
- } else { |
- // If the DOWN event happened outside the Search Content View, then we know |
- // that the Search Panel will start handling the event right away. |
- setEventTarget(EventTarget.SEARCH_PANEL); |
- mMayChangeEventTarget = false; |
- } |
- } |
- |
- // Send the event to the GestureDetector so we can distinguish between scroll and tap. |
- mGestureDetector.onTouchEvent(e); |
- |
- if (mHasDeterminedEventTarget) { |
- // If the event target has been determined, resume pending events, then propagate |
- // the current event to the appropriate target. |
- resumeAndPropagateEvent(e); |
- } else { |
- // If the event target has not been determined, we need to record a copy of the event |
- // until we are able to determine the event target. |
- MotionEvent event = MotionEvent.obtain(e); |
- mRecordedEvents.add(event); |
- mIsRecordingEvents = true; |
- } |
- |
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { |
- reset(); |
- } |
- |
- return true; |
- } |
- |
- /** |
- * Resets the current and previous {@link EventTarget} as well the {@link GestureOrientation} |
- * to the UNDETERMINED state. |
- */ |
- private void reset() { |
- mEventTarget = EventTarget.UNDETERMINED; |
- mIsDeterminingEventTarget = false; |
- mHasDeterminedEventTarget = false; |
- |
- mPreviousEventTarget = EventTarget.UNDETERMINED; |
- mHasChangedEventTarget = false; |
- mMayChangeEventTarget = false; |
- |
- mWasActionDownEventSynthetic = false; |
- |
- mGestureOrientation = GestureOrientation.UNDETERMINED; |
- mHasDeterminedGestureOrientation = false; |
- } |
- |
- /** |
- * Resumes pending events then propagates the given event to the current {@link EventTarget}. |
- * |
- * Resuming events might consist in simply propagating previously recorded events if the |
- * EventTarget was UNDETERMINED when the gesture started. |
- * |
- * For the case where the EventTarget has changed during the course of the gesture, we'll |
- * need to simulate a gesture end in the previous target (by simulating an ACTION_CANCEL |
- * event) and a gesture start in the new target (by simulating an ACTION_DOWN event). |
- * |
- * @param e The {@link MotionEvent} to be propagated after resuming the pending events. |
- */ |
- private void resumeAndPropagateEvent(MotionEvent e) { |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel == null) return; |
- |
- if (mIsRecordingEvents) { |
- resumeRecordedEvents(); |
- } |
- |
- if (mHasChangedEventTarget) { |
- // If the event target has changed since the beginning of the gesture, then we need |
- // to send a ACTION_CANCEL to the previous event target to make sure it no longer |
- // expects events. |
- propagateAndRecycleEvent(copyEvent(e, MotionEvent.ACTION_CANCEL), mPreviousEventTarget); |
- |
- // Similarly we need to send an ACTION_DOWN to the new event target so subsequent |
- // events can be analyzed properly by the Gesture Detector. |
- MotionEvent syntheticActionDownEvent = copyEvent(e, MotionEvent.ACTION_DOWN); |
- |
- // Store the synthetic ACTION_DOWN coordinates to prevent unwanted taps from |
- // happening. See {@link ContextualSearchEventFilter#propagateEventToSearchContentView}. |
- mWasActionDownEventSynthetic = true; |
- mSyntheticActionDownX = syntheticActionDownEvent.getX(); |
- mSyntheticActionDownY = syntheticActionDownEvent.getY() - panel.getContentY() / mPxToDp; |
- |
- propagateAndRecycleEvent(syntheticActionDownEvent, mEventTarget); |
- |
- mHasChangedEventTarget = false; |
- } |
- |
- propagateEvent(e, mEventTarget); |
- } |
- |
- /** |
- * Resumes recorded events by propagating all of them to the current {@link EventTarget}. |
- */ |
- private void resumeRecordedEvents() { |
- for (int i = 0, size = mRecordedEvents.size(); i < size; i++) { |
- propagateAndRecycleEvent(mRecordedEvents.get(i), mEventTarget); |
- } |
- |
- mRecordedEvents.clear(); |
- mIsRecordingEvents = false; |
- } |
- |
- /** |
- * Propagates the given {@link MotionEvent} to the given {@link EventTarget}, recycling it |
- * afterwards. This is intended for synthetic events only, those create by |
- * {@link MotionEvent#obtain} or the helper methods |
- * {@link ContextualSearchEventFilter#lockEventHorizontallty} and |
- * {@link ContextualSearchEventFilter#copyEvent}. |
- * |
- * @param e The {@link MotionEvent} to be propagated. |
- * @param target The {@link EventTarget} to propagate events to. |
- */ |
- private void propagateAndRecycleEvent(MotionEvent e, EventTarget target) { |
- propagateEvent(e, target); |
- e.recycle(); |
- } |
- |
- /** |
- * Propagates the given {@link MotionEvent} to the given {@link EventTarget}. |
- * @param e The {@link MotionEvent} to be propagated. |
- * @param target The {@link EventTarget} to propagate events to. |
- */ |
- private void propagateEvent(MotionEvent e, EventTarget target) { |
- if (target == EventTarget.SEARCH_PANEL) { |
- super.onTouchEventInternal(e); |
- } else if (target == EventTarget.SEARCH_CONTENT_VIEW) { |
- propagateEventToSearchContentView(e); |
- } |
- } |
- |
- /** |
- * Propagates the given {@link MotionEvent} to the Search Content View. |
- * @param e The {@link MotionEvent} to be propagated. |
- */ |
- @VisibleForTesting |
- protected void propagateEventToSearchContentView(MotionEvent e) { |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel == null) return; |
- |
- MotionEvent event = e; |
- int action = event.getActionMasked(); |
- boolean isSyntheticEvent = false; |
- if (mGestureOrientation == GestureOrientation.HORIZONTAL && !panel.isMaximized()) { |
- // Ignores multitouch events to prevent the Search Result Page from from scrolling. |
- if (action == MotionEvent.ACTION_POINTER_UP |
- || action == MotionEvent.ACTION_POINTER_DOWN) { |
- return; |
- } |
- |
- // NOTE(pedrosimonetti): Lock horizontal motion, ignoring all vertical changes, |
- // when the Panel is not maximized. This is to prevent the Search Result Page |
- // from scrolling when side swiping on the expanded Panel. Also, note that the |
- // method {@link ContextualSearchEventFilter#lockEventHorizontallty} will always |
- // return an event with a single pointer, which is necessary to prevent |
- // the app from crashing when the motion involves multiple pointers. |
- // See: crbug.com/486901 |
- event = MotionEvent.obtain( |
- e.getDownTime(), |
- e.getEventTime(), |
- // NOTE(pedrosimonetti): Use getActionMasked() to make sure we're not |
- // send any pointer information to the event, given that getAction() |
- // may have the pointer Id associated to it. |
- e.getActionMasked(), |
- e.getX(), |
- mInitialEventY, |
- e.getMetaState()); |
- |
- isSyntheticEvent = true; |
- } |
- |
- final float contentViewOffsetXPx = panel.getContentX() / mPxToDp; |
- final float contentViewOffsetYPx = panel.getContentY() / mPxToDp; |
- |
- // Adjust the offset to be relative to the Search Contents View. |
- event.offsetLocation(-contentViewOffsetXPx, -contentViewOffsetYPx); |
- |
- boolean wasEventCanceled = false; |
- if (mWasActionDownEventSynthetic && action == MotionEvent.ACTION_UP) { |
- float deltaX = event.getX() - mSyntheticActionDownX; |
- float deltaY = event.getY() - mSyntheticActionDownY; |
- // NOTE(pedrosimonetti): If the ACTION_DOWN event was synthetic and the distance |
- // between it and the ACTION_UP event was short, then we should synthesize an |
- // ACTION_CANCEL event to prevent a Tap gesture from being triggered on the Search |
- // Content View. See crbug.com/408654 |
- if (!isDistanceGreaterThanTouchSlop(deltaX, deltaY)) { |
- event.setAction(MotionEvent.ACTION_CANCEL); |
- mHost.propagateEvent(event); |
- wasEventCanceled = true; |
- } |
- } else if (action == MotionEvent.ACTION_DOWN) { |
- panel.onTouchSearchContentViewAck(); |
- } |
- |
- // Propagate the event to the appropriate view |
- if (!wasEventCanceled) mHost.propagateEvent(event); |
- |
- // Synthetic events should be recycled. |
- if (isSyntheticEvent) event.recycle(); |
- } |
- |
- /** |
- * Creates a {@link MotionEvent} inheriting from a given |e| event. |
- * @param e The {@link MotionEvent} to inherit properties from. |
- * @param action The MotionEvent's Action to be used. |
- * @return A new {@link MotionEvent}. |
- */ |
- private MotionEvent copyEvent(MotionEvent e, int action) { |
- MotionEvent event = MotionEvent.obtain(e); |
- event.setAction(action); |
- return event; |
- } |
- |
- /** |
- * Handles the tap event, determining the event target. |
- * @param e The tap {@link MotionEvent}. |
- * @return Whether the event has been consumed. |
- */ |
- private boolean handleSingleTapUp(MotionEvent e) { |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel != null) { |
- setEventTarget(panel.isCoordinateInsideContent( |
- e.getX() * mPxToDp, e.getY() * mPxToDp) |
- ? EventTarget.SEARCH_CONTENT_VIEW : EventTarget.SEARCH_PANEL); |
- } |
- return false; |
- } |
- |
- /** |
- * Handles the scroll event, determining the gesture orientation and event target, |
- * when appropriate. |
- * @param e1 The first down {@link MotionEvent} that started the scrolling. |
- * @param e2 The move {@link MotionEvent} that triggered the current scroll. |
- * @param distanceY The distance along the Y axis that has been scrolled since the last call |
- * to handleScroll. |
- * @return Whether the event has been consumed. |
- */ |
- private boolean handleScroll(MotionEvent e1, MotionEvent e2, float distanceY) { |
- // Only determines the gesture orientation if it hasn't been determined yet, |
- // affectively "locking" the orientation once the gesture has started. |
- if (!mHasDeterminedGestureOrientation && isDistanceGreaterThanTouchSlop(e1, e2)) { |
- determineGestureOrientation(e1, e2); |
- } |
- |
- // Only determines the event target after determining the gesture orientation and |
- // if it hasn't been determined yet or if changing the event target during the |
- // middle of the gesture is supported. This will allow a smooth transition from |
- // swiping the Panel and scrolling the Search Content View. |
- final boolean mayChangeEventTarget = mMayChangeEventTarget && e2.getPointerCount() == 1; |
- if (mHasDeterminedGestureOrientation |
- && (!mHasDeterminedEventTarget || mayChangeEventTarget)) { |
- determineEventTarget(distanceY); |
- } |
- |
- return false; |
- } |
- |
- /** |
- * Determines the gesture orientation. |
- * @param e1 The first down {@link MotionEvent} that started the scrolling. |
- * @param e2 The move {@link MotionEvent} that triggered the current scroll. |
- */ |
- private void determineGestureOrientation(MotionEvent e1, MotionEvent e2) { |
- float deltaX = Math.abs(e2.getX() - e1.getX()); |
- float deltaY = Math.abs(e2.getY() - e1.getY()); |
- mGestureOrientation = deltaY * VERTICAL_DETERMINATION_BOOST > deltaX |
- ? GestureOrientation.VERTICAL : GestureOrientation.HORIZONTAL; |
- mHasDeterminedGestureOrientation = true; |
- } |
- |
- /** |
- * Determines the target to propagate events to. This will not only update the |
- * {@code mEventTarget} but also save the previous target and determine whether the |
- * target has changed. |
- * @param distanceY The distance along the Y axis that has been scrolled since the last call |
- * to handleScroll. |
- */ |
- private void determineEventTarget(float distanceY) { |
- boolean isVertical = mGestureOrientation == GestureOrientation.VERTICAL; |
- |
- boolean shouldPropagateEventsToSearchPanel; |
- OverlayPanel panel = mPanelManager.getActivePanel(); |
- if (panel != null && panel.isMaximized()) { |
- // Allow overscroll in the Search Content View to move the Search Panel instead |
- // of scrolling the Search Result Page. |
- boolean isMovingDown = distanceY < 0; |
- shouldPropagateEventsToSearchPanel = isVertical |
- && isMovingDown |
- && getSearchContentViewVerticalScroll() == 0; |
- } else { |
- // Only allow horizontal movements to be propagated to the Search Content View |
- // when the Panel is expanded (that is, not maximized). |
- shouldPropagateEventsToSearchPanel = isVertical; |
- |
- // If the gesture is horizontal, then we know that the event target won't change. |
- if (!isVertical) mMayChangeEventTarget = false; |
- } |
- |
- EventTarget target = shouldPropagateEventsToSearchPanel |
- ? EventTarget.SEARCH_PANEL : EventTarget.SEARCH_CONTENT_VIEW; |
- |
- if (target != mEventTarget) { |
- mPreviousEventTarget = mEventTarget; |
- setEventTarget(target); |
- |
- mHasChangedEventTarget = mEventTarget != mPreviousEventTarget |
- && mPreviousEventTarget != EventTarget.UNDETERMINED; |
- } |
- } |
- |
- /** |
- * Sets the {@link EventTarget}. |
- * @param target The {@link EventTarget} to be set. |
- */ |
- private void setEventTarget(EventTarget target) { |
- mEventTarget = target; |
- |
- mIsDeterminingEventTarget = false; |
- mHasDeterminedEventTarget = true; |
- } |
- |
- /** |
- * @param e1 The first down {@link MotionEvent} that started the scrolling. |
- * @param e2 The move {@link MotionEvent} that triggered the current scroll. |
- * @return Whether the distance is greater than the touch slop threshold. |
- */ |
- private boolean isDistanceGreaterThanTouchSlop(MotionEvent e1, MotionEvent e2) { |
- float deltaX = e2.getX() - e1.getX(); |
- float deltaY = e2.getY() - e1.getY(); |
- // Check if the distance between the events |e1| and |e2| is greater than the touch slop. |
- return isDistanceGreaterThanTouchSlop(deltaX, deltaY); |
- } |
- |
- /** |
- * @param deltaX The delta X in pixels. |
- * @param deltaY The delta Y in pixels. |
- * @return Whether the distance is greater than the touch slop threshold. |
- */ |
- private boolean isDistanceGreaterThanTouchSlop(float deltaX, float deltaY) { |
- return deltaX * deltaX + deltaY * deltaY > mTouchSlopSquarePx; |
- } |
- |
- /** |
- * Internal GestureDetector class that is responsible for determining the event target. |
- */ |
- private class InternalGestureDetector extends GestureDetector.SimpleOnGestureListener { |
- @Override |
- public boolean onSingleTapUp(MotionEvent e) { |
- return handleSingleTapUp(e); |
- } |
- |
- @Override |
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { |
- return handleScroll(e1, e2, distanceY); |
- } |
- } |
-} |