// Copyright 2013 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.MotionEvent; import org.chromium.base.VisibleForTesting; /** * {@link EventFilter} is an abstract minimal {@link EventFilter}. This class is designed to use or * propagate events from an {@link EventFilterHost} view. */ public abstract class EventFilter { protected final EventFilterHost mHost; protected final float mPxToDp; private boolean mSimulateIntercepting = false; private boolean mAutoOffset = false; protected float mCurrentTouchOffsetX; protected float mCurrentTouchOffsetY; /** * Creates a {@link EventFilter}. * @param context A {@link Context} instance. * @param host The host of this EventFilter. */ public EventFilter(Context context, EventFilterHost host) { this(context, host, true); } /** * Creates a {@link EventFilter}. * @param host The host of this EventFilter. * @param autoOffset Whether or not to automatically offset touch events. EventFilters that * call {@link EventFilterHost#propagateEvent(MotionEvent)} will want to set * this to {@code false} and use {@link #mCurrentTouchOffsetX} and * {@link #mCurrentTouchOffsetY} internally. This is so that propagated * events aren't translated, as the host view needs the original event data. */ public EventFilter(Context context, EventFilterHost host, boolean autoOffset) { mHost = host; mPxToDp = 1.0f / context.getResources().getDisplayMetrics().density; mAutoOffset = autoOffset; } /** * @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent) * @param event The {@link MotionEvent} that started the gesture to be evaluated. * @param isKeyboardShowing Whether the keyboard is currently showing. * @return Whether the filter is going to intercept events. */ public final boolean onInterceptTouchEvent(MotionEvent event, boolean isKeyboardShowing) { MotionEvent sentEvent = event; if (mAutoOffset && (mCurrentTouchOffsetX != 0 || mCurrentTouchOffsetY != 0)) { sentEvent = MotionEvent.obtain(event); sentEvent.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY); } boolean consumed = onInterceptTouchEventInternal(sentEvent, isKeyboardShowing); if (sentEvent != event) sentEvent.recycle(); return consumed; } /** * Sets the offset to apply to MotionEvents. * * @param offsetX How much to offset the X touch events in pixels. * @param offsetY How much to offset the Y touch events in pixels. */ public void setCurrentMotionEventOffsets(float offsetX, float offsetY) { mCurrentTouchOffsetX = offsetX; mCurrentTouchOffsetY = offsetY; } /** * This function has a fairly uncommon behavior, if you change anything please checkout the * java-doc here: * @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent) * @param event The {@link MotionEvent} that started the gesture to be evaluated. * @param isKeyboardShowing Whether the keyboard is currently showing. * @return Whether the filter is going to intercept events. */ protected abstract boolean onInterceptTouchEventInternal( MotionEvent event, boolean isKeyboardShowing); /** * @see android.view.ViewGroup#onTouchEvent(android.view.MotionEvent) * @param event The {@link MotionEvent} that started the gesture to be evaluated. * @return Whether the filter handled the event. */ public final boolean onTouchEvent(MotionEvent event) { if (mAutoOffset) event.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY); return onTouchEventInternal(event); } /** * @see android.view.ViewGroup#onTouchEvent(android.view.MotionEvent) * @param event The {@link MotionEvent} that started the gesture to be evaluated. * @return Whether the filter handled the event. */ protected abstract boolean onTouchEventInternal(MotionEvent event); /** * Simulates an event for testing purpose. This will call onInterceptTouchEvent and * onTouchEvent appropriately. * @param event The {@link MotionEvent} that started the gesture to be evaluated. * @param isKeyboardShowing Whether the keyboard is currently showing. * @return Whether the filter handled the event. */ @VisibleForTesting public boolean simulateTouchEvent(MotionEvent event, boolean isKeyboardShowing) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN || !mSimulateIntercepting) { mSimulateIntercepting = onInterceptTouchEvent(event, isKeyboardShowing); } return onTouchEvent(event); } /** * @return Whether or not touch events will be automatically offset. */ protected boolean autoOffsetEvents() { return mAutoOffset; } }