EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.content.browser.third_party]

COVERAGE SUMMARY FOR SOURCE FILE [GestureDetector.java]

nameclass, %method, %block, %line, %
GestureDetector.java100% (3/3)55%  (18/33)73%  (641/874)70%  (146.1/209)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class GestureDetector$SimpleOnGestureListener100% (1/1)30%  (3/10)37%  (7/19)30%  (3/10)
onDoubleTapEvent (MotionEvent): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
onFling (MotionEvent, MotionEvent, float, float): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
onLongPress (MotionEvent): void 0%   (0/1)0%   (0/1)0%   (0/1)
onScroll (MotionEvent, MotionEvent, float, float): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
onShowPress (MotionEvent): void 0%   (0/1)0%   (0/1)0%   (0/1)
onSingleTapConfirmed (MotionEvent): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
onSingleTapUp (MotionEvent): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
GestureDetector$SimpleOnGestureListener (): void 100% (1/1)100% (3/3)100% (1/1)
onDoubleTap (MotionEvent): boolean 100% (1/1)100% (2/2)100% (1/1)
onDown (MotionEvent): boolean 100% (1/1)100% (2/2)100% (1/1)
     
class GestureDetector$GestureHandler100% (1/1)67%  (2/3)59%  (35/59)60%  (9/15)
GestureDetector$GestureHandler (GestureDetector, Handler): void 0%   (0/1)0%   (0/8)0%   (0/3)
handleMessage (Message): void 100% (1/1)64%  (29/45)67%  (6/9)
GestureDetector$GestureHandler (GestureDetector): void 100% (1/1)100% (6/6)100% (3/3)
     
class GestureDetector100% (1/1)65%  (13/20)75%  (599/796)73%  (134.1/184)
GestureDetector (Context, GestureDetector$OnGestureListener, Handler, boolean... 0%   (0/1)0%   (0/6)0%   (0/2)
GestureDetector (GestureDetector$OnGestureListener): void 0%   (0/1)0%   (0/6)0%   (0/2)
GestureDetector (GestureDetector$OnGestureListener, Handler): void 0%   (0/1)0%   (0/6)0%   (0/2)
access$200 (GestureDetector): void 0%   (0/1)0%   (0/3)0%   (0/1)
cancelTaps (): void 0%   (0/1)0%   (0/28)0%   (0/9)
dispatchLongPress (): void 0%   (0/1)0%   (0/13)0%   (0/4)
isLongpressEnabled (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
GestureDetector (Context, GestureDetector$OnGestureListener, Handler): void 100% (1/1)75%  (24/32)89%  (8/9)
onTouchEvent (MotionEvent): boolean 100% (1/1)79%  (425/537)78%  (88.3/113)
init (Context): void 100% (1/1)89%  (41/46)92%  (12/13)
isConsideredDoubleTap (MotionEvent, MotionEvent, MotionEvent): boolean 100% (1/1)91%  (42/46)71%  (5/7)
cancel (): void 100% (1/1)92%  (34/37)92%  (11/12)
<static initializer> 100% (1/1)100% (7/7)100% (3/3)
GestureDetector (Context, GestureDetector$OnGestureListener): void 100% (1/1)100% (6/6)100% (2/2)
access$000 (GestureDetector): MotionEvent 100% (1/1)100% (3/3)100% (1/1)
access$100 (GestureDetector): GestureDetector$OnGestureListener 100% (1/1)100% (3/3)100% (1/1)
access$300 (GestureDetector): GestureDetector$OnDoubleTapListener 100% (1/1)100% (3/3)100% (1/1)
access$400 (GestureDetector): boolean 100% (1/1)100% (3/3)100% (1/1)
setIsLongpressEnabled (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setOnDoubleTapListener (GestureDetector$OnDoubleTapListener): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17// This is a copy of Android GestureDetector.java from AOSP 4.2.  We include it in Chromium in order
18// to have JB-style behavior on ICS devices.  Some edits for NDK v16 compliance were needed; they're
19// noted explicitly below.
20 
21// New imports in Chromium for NDK compliance.
22package org.chromium.content.browser.third_party;
23import android.view.MotionEvent;
24import android.view.VelocityTracker;
25import android.view.ViewConfiguration;
26 
27/*  Commented out in Chromium for NDK compliance
28package android.view;
29*/
30 
31import android.content.Context;
32import android.os.Build;
33import android.os.Handler;
34import android.os.Message;
35 
36/**
37 * Detects various gestures and events using the supplied {@link MotionEvent}s.
38 * The {@link OnGestureListener} callback will notify users when a particular
39 * motion event has occurred. This class should only be used with {@link MotionEvent}s
40 * reported via touch (don't use for trackball events).
41 *
42 * To use this class:
43 * <ul>
44 *  <li>Create an instance of the {@code GestureDetector} for your {@link View}
45 *  <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call
46 *          {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback
47 *          will be executed when the events occur.
48 * </ul>
49 */
50public class GestureDetector {
51    /**
52     * The listener that is used to notify when gestures occur.
53     * If you want to listen for all the different gestures then implement
54     * this interface. If you only want to listen for a subset it might
55     * be easier to extend {@link SimpleOnGestureListener}.
56     */
57    public interface OnGestureListener {
58 
59        /**
60         * Notified when a tap occurs with the down {@link MotionEvent}
61         * that triggered it. This will be triggered immediately for
62         * every down event. All other events should be preceded by this.
63         *
64         * @param e The down motion event.
65         */
66        boolean onDown(MotionEvent e);
67 
68        /**
69         * The user has performed a down {@link MotionEvent} and not performed
70         * a move or up yet. This event is commonly used to provide visual
71         * feedback to the user to let them know that their action has been
72         * recognized i.e. highlight an element.
73         *
74         * @param e The down motion event
75         */
76        void onShowPress(MotionEvent e);
77 
78        /**
79         * Notified when a tap occurs with the up {@link MotionEvent}
80         * that triggered it.
81         *
82         * @param e The up motion event that completed the first tap
83         * @return true if the event is consumed, else false
84         */
85        boolean onSingleTapUp(MotionEvent e);
86 
87        /**
88         * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
89         * current move {@link MotionEvent}. The distance in x and y is also supplied for
90         * convenience.
91         *
92         * @param e1 The first down motion event that started the scrolling.
93         * @param e2 The move motion event that triggered the current onScroll.
94         * @param distanceX The distance along the X axis that has been scrolled since the last
95         *              call to onScroll. This is NOT the distance between {@code e1}
96         *              and {@code e2}.
97         * @param distanceY The distance along the Y axis that has been scrolled since the last
98         *              call to onScroll. This is NOT the distance between {@code e1}
99         *              and {@code e2}.
100         * @return true if the event is consumed, else false
101         */
102        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
103 
104        /**
105         * Notified when a long press occurs with the initial on down {@link MotionEvent}
106         * that trigged it.
107         *
108         * @param e The initial on down motion event that started the longpress.
109         */
110        void onLongPress(MotionEvent e);
111 
112        /**
113         * Notified of a fling event when it occurs with the initial on down {@link MotionEvent}
114         * and the matching up {@link MotionEvent}. The calculated velocity is supplied along
115         * the x and y axis in pixels per second.
116         *
117         * @param e1 The first down motion event that started the fling.
118         * @param e2 The move motion event that triggered the current onFling.
119         * @param velocityX The velocity of this fling measured in pixels per second
120         *              along the x axis.
121         * @param velocityY The velocity of this fling measured in pixels per second
122         *              along the y axis.
123         * @return true if the event is consumed, else false
124         */
125        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
126    }
127 
128    /**
129     * The listener that is used to notify when a double-tap or a confirmed
130     * single-tap occur.
131     */
132    public interface OnDoubleTapListener {
133        /**
134         * Notified when a single-tap occurs.
135         * <p>
136         * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
137         * will only be called after the detector is confident that the user's
138         * first tap is not followed by a second tap leading to a double-tap
139         * gesture.
140         *
141         * @param e The down motion event of the single-tap.
142         * @return true if the event is consumed, else false
143         */
144        boolean onSingleTapConfirmed(MotionEvent e);
145 
146        /**
147         * Notified when a double-tap occurs.
148         *
149         * @param e The down motion event of the first tap of the double-tap.
150         * @return true if the event is consumed, else false
151         */
152        boolean onDoubleTap(MotionEvent e);
153 
154        /**
155         * Notified when an event within a double-tap gesture occurs, including
156         * the down, move, and up events.
157         *
158         * @param e The motion event that occurred during the double-tap gesture.
159         * @return true if the event is consumed, else false
160         */
161        boolean onDoubleTapEvent(MotionEvent e);
162    }
163 
164    /**
165     * A convenience class to extend when you only want to listen for a subset
166     * of all the gestures. This implements all methods in the
167     * {@link OnGestureListener} and {@link OnDoubleTapListener} but does
168     * nothing and return {@code false} for all applicable methods.
169     */
170    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
171        public boolean onSingleTapUp(MotionEvent e) {
172            return false;
173        }
174 
175        public void onLongPress(MotionEvent e) {
176        }
177 
178        public boolean onScroll(MotionEvent e1, MotionEvent e2,
179                float distanceX, float distanceY) {
180            return false;
181        }
182 
183        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
184                float velocityY) {
185            return false;
186        }
187 
188        public void onShowPress(MotionEvent e) {
189        }
190 
191        public boolean onDown(MotionEvent e) {
192            return false;
193        }
194 
195        public boolean onDoubleTap(MotionEvent e) {
196            return false;
197        }
198 
199        public boolean onDoubleTapEvent(MotionEvent e) {
200            return false;
201        }
202 
203        public boolean onSingleTapConfirmed(MotionEvent e) {
204            return false;
205        }
206    }
207 
208    private int mTouchSlopSquare;
209    private int mDoubleTapTouchSlopSquare;
210    private int mDoubleTapSlopSquare;
211    private int mMinimumFlingVelocity;
212    private int mMaximumFlingVelocity;
213 
214    private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
215    private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
216    private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
217 
218    // constants for Message.what used by GestureHandler below
219    private static final int SHOW_PRESS = 1;
220    private static final int LONG_PRESS = 2;
221    private static final int TAP = 3;
222 
223    private final Handler mHandler;
224    private final OnGestureListener mListener;
225    private OnDoubleTapListener mDoubleTapListener;
226 
227    private boolean mStillDown;
228    private boolean mInLongPress;
229    private boolean mAlwaysInTapRegion;
230    private boolean mAlwaysInBiggerTapRegion;
231 
232    private MotionEvent mCurrentDownEvent;
233    private MotionEvent mPreviousUpEvent;
234 
235    /**
236     * True when the user is still touching for the second tap (down, move, and
237     * up events). Can only be true if there is a double tap listener attached.
238     */
239    private boolean mIsDoubleTapping;
240 
241    private float mLastFocusX;
242    private float mLastFocusY;
243    private float mDownFocusX;
244    private float mDownFocusY;
245 
246    private boolean mIsLongpressEnabled;
247 
248    /**
249     * Determines speed during touch scrolling
250     */
251    private VelocityTracker mVelocityTracker;
252 
253    /**
254     * Consistency verifier for debugging purposes.
255     */
256/*  Commented out in Chromium for NDK compliance
257    private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
258            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
259                    new InputEventConsistencyVerifier(this, 0) : null;
260*/
261 
262    private class GestureHandler extends Handler {
263        GestureHandler() {
264            super();
265        }
266 
267        GestureHandler(Handler handler) {
268            super(handler.getLooper());
269        }
270 
271        @Override
272        public void handleMessage(Message msg) {
273            switch (msg.what) {
274            case SHOW_PRESS:
275                mListener.onShowPress(mCurrentDownEvent);
276                break;
277                
278            case LONG_PRESS:
279                dispatchLongPress();
280                break;
281                
282            case TAP:
283                // If the user's finger is still down, do not count it as a tap
284                if (mDoubleTapListener != null && !mStillDown) {
285                    mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
286                }
287                break;
288 
289            default:
290                throw new RuntimeException("Unknown message " + msg); //never
291            }
292        }
293    }
294 
295    /**
296     * Creates a GestureDetector with the supplied listener.
297     * This variant of the constructor should be used from a non-UI thread 
298     * (as it allows specifying the Handler).
299     * 
300     * @param listener the listener invoked for all the callbacks, this must
301     * not be null.
302     * @param handler the handler to use
303     *
304     * @throws NullPointerException if either {@code listener} or
305     * {@code handler} is null.
306     *
307     * @deprecated Use {@link #GestureDetector(android.content.Context,
308     *      android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
309     */
310    @Deprecated
311    public GestureDetector(OnGestureListener listener, Handler handler) {
312        this(null, listener, handler);
313    }
314 
315    /**
316     * Creates a GestureDetector with the supplied listener.
317     * You may only use this constructor from a UI thread (this is the usual situation).
318     * @see android.os.Handler#Handler()
319     * 
320     * @param listener the listener invoked for all the callbacks, this must
321     * not be null.
322     * 
323     * @throws NullPointerException if {@code listener} is null.
324     *
325     * @deprecated Use {@link #GestureDetector(android.content.Context,
326     *      android.view.GestureDetector.OnGestureListener)} instead.
327     */
328    @Deprecated
329    public GestureDetector(OnGestureListener listener) {
330        this(null, listener, null);
331    }
332 
333    /**
334     * Creates a GestureDetector with the supplied listener.
335     * You may only use this constructor from a UI thread (this is the usual situation).
336     * @see android.os.Handler#Handler()
337     *
338     * @param context the application's context
339     * @param listener the listener invoked for all the callbacks, this must
340     * not be null.
341     *
342     * @throws NullPointerException if {@code listener} is null.
343     */
344    public GestureDetector(Context context, OnGestureListener listener) {
345        this(context, listener, null);
346    }
347 
348    /**
349     * Creates a GestureDetector with the supplied listener.
350     * You may only use this constructor from a UI thread (this is the usual situation).
351     * @see android.os.Handler#Handler()
352     *
353     * @param context the application's context
354     * @param listener the listener invoked for all the callbacks, this must
355     * not be null.
356     * @param handler the handler to use     
357     *
358     * @throws NullPointerException if {@code listener} is null.
359     */
360    public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
361        if (handler != null) {
362            mHandler = new GestureHandler(handler);
363        } else {
364            mHandler = new GestureHandler();
365        }
366        mListener = listener;
367        if (listener instanceof OnDoubleTapListener) {
368            setOnDoubleTapListener((OnDoubleTapListener) listener);
369        }
370        init(context);
371    }
372    
373    /**
374     * Creates a GestureDetector with the supplied listener.
375     * You may only use this constructor from a UI thread (this is the usual situation).
376     * @see android.os.Handler#Handler()
377     *
378     * @param context the application's context
379     * @param listener the listener invoked for all the callbacks, this must
380     * not be null.
381     * @param handler the handler to use
382     *
383     * @throws NullPointerException if {@code listener} is null.
384     */
385    public GestureDetector(Context context, OnGestureListener listener, Handler handler,
386            boolean unused) {
387        this(context, listener, handler);
388    }
389 
390    private void init(Context context) {
391        if (mListener == null) {
392            throw new NullPointerException("OnGestureListener must not be null");
393        }
394        mIsLongpressEnabled = true;
395 
396        // Fallback to support pre-donuts releases
397        int touchSlop, doubleTapSlop, doubleTapTouchSlop;
398/*  Commented out in Chromium for NDK compliance
399        if (context == null) {
400            //noinspection deprecation
401            touchSlop = ViewConfiguration.getTouchSlop();
402            doubleTapTouchSlop = touchSlop; // Hack rather than adding a hiden method for this
403            doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
404            //noinspection deprecation
405            mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
406            mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
407        } else */ {
408            final ViewConfiguration configuration = ViewConfiguration.get(context);
409            touchSlop = configuration.getScaledTouchSlop();
410/*  Commented out in Chromium for NDK compliance and replaced with the following line.  Note that
411 *  ViewConfiguration.TOUCH_SLOP has the same value as DOUBLE_TAP_TOUCH_SLOP in current Android, so
412 *  this doesn't introduce a behavior difference in Android versions <= 4.2.
413            doubleTapTouchSlop = configuration.getScaledDoubleTapTouchSlop();
414*/
415            doubleTapTouchSlop = touchSlop;
416            doubleTapSlop = configuration.getScaledDoubleTapSlop();
417            mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
418            mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity();
419        }
420        mTouchSlopSquare = touchSlop * touchSlop;
421        mDoubleTapTouchSlopSquare = doubleTapTouchSlop * doubleTapTouchSlop;
422        mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
423    }
424 
425    /**
426     * Sets the listener which will be called for double-tap and related
427     * gestures.
428     * 
429     * @param onDoubleTapListener the listener invoked for all the callbacks, or
430     *        null to stop listening for double-tap gestures.
431     */
432    public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
433        mDoubleTapListener = onDoubleTapListener;
434    }
435 
436    /**
437     * Set whether longpress is enabled, if this is enabled when a user
438     * presses and holds down you get a longpress event and nothing further.
439     * If it's disabled the user can press and hold down and then later
440     * moved their finger and you will get scroll events. By default
441     * longpress is enabled.
442     *
443     * @param isLongpressEnabled whether longpress should be enabled.
444     */
445    public void setIsLongpressEnabled(boolean isLongpressEnabled) {
446        mIsLongpressEnabled = isLongpressEnabled;
447    }
448 
449    /**
450     * @return true if longpress is enabled, else false.
451     */
452    public boolean isLongpressEnabled() {
453        return mIsLongpressEnabled;
454    }
455 
456    /**
457     * Analyzes the given motion event and if applicable triggers the
458     * appropriate callbacks on the {@link OnGestureListener} supplied.
459     *
460     * @param ev The current motion event.
461     * @return true if the {@link OnGestureListener} consumed the event,
462     *              else false.
463     */
464    public boolean onTouchEvent(MotionEvent ev) {
465/*  Commented out in Chromium for NDK compliance
466        if (mInputEventConsistencyVerifier != null) {
467            mInputEventConsistencyVerifier.onTouchEvent(ev, 0);
468        }
469*/
470 
471        final int action = ev.getAction();
472 
473        if (mVelocityTracker == null) {
474            mVelocityTracker = VelocityTracker.obtain();
475        }
476        mVelocityTracker.addMovement(ev);
477 
478        final boolean pointerUp =
479                (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP;
480        final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
481 
482        // Determine focal point
483        float sumX = 0, sumY = 0;
484        final int count = ev.getPointerCount();
485        for (int i = 0; i < count; i++) {
486            if (skipIndex == i) continue;
487            sumX += ev.getX(i);
488            sumY += ev.getY(i);
489        }
490        final int div = pointerUp ? count - 1 : count;
491        final float focusX = sumX / div;
492        final float focusY = sumY / div;
493 
494        boolean handled = false;
495 
496        switch (action & MotionEvent.ACTION_MASK) {
497        case MotionEvent.ACTION_POINTER_DOWN:
498            mDownFocusX = mLastFocusX = focusX;
499            mDownFocusY = mLastFocusY = focusY;
500            // Cancel long press and taps
501            cancelTaps();
502            break;
503 
504        case MotionEvent.ACTION_POINTER_UP:
505            mDownFocusX = mLastFocusX = focusX;
506            mDownFocusY = mLastFocusY = focusY;
507 
508            // Check the dot product of current velocities.
509            // If the pointer that left was opposing another velocity vector, clear.
510            mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
511            final int upIndex = ev.getActionIndex();
512            final int id1 = ev.getPointerId(upIndex);
513            final float x1 = mVelocityTracker.getXVelocity(id1);
514            final float y1 = mVelocityTracker.getYVelocity(id1);
515            for (int i = 0; i < count; i++) {
516                if (i == upIndex) continue;
517 
518                final int id2 = ev.getPointerId(i);
519                final float x = x1 * mVelocityTracker.getXVelocity(id2);
520                final float y = y1 * mVelocityTracker.getYVelocity(id2);
521 
522                final float dot = x + y;
523                if (dot < 0) {
524                    mVelocityTracker.clear();
525                    break;
526                }
527            }
528            break;
529 
530        case MotionEvent.ACTION_DOWN:
531            if (mDoubleTapListener != null) {
532                boolean hadTapMessage = mHandler.hasMessages(TAP);
533                if (hadTapMessage) mHandler.removeMessages(TAP);
534                if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
535                        isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
536                    // This is a second tap
537                    mIsDoubleTapping = true;
538                    // Give a callback with the first tap of the double-tap
539                    handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
540                    // Give a callback with down event of the double-tap
541                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
542                } else {
543                    // This is a first tap
544                    mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
545                }
546            }
547 
548            mDownFocusX = mLastFocusX = focusX;
549            mDownFocusY = mLastFocusY = focusY;
550            if (mCurrentDownEvent != null) {
551                mCurrentDownEvent.recycle();
552            }
553            mCurrentDownEvent = MotionEvent.obtain(ev);
554            mAlwaysInTapRegion = true;
555            mAlwaysInBiggerTapRegion = true;
556            mStillDown = true;
557            mInLongPress = false;
558            
559            if (mIsLongpressEnabled) {
560                mHandler.removeMessages(LONG_PRESS);
561                mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
562                        + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
563            }
564            mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
565            handled |= mListener.onDown(ev);
566            break;
567 
568        case MotionEvent.ACTION_MOVE:
569            if (mInLongPress) {
570                break;
571            }
572            final float scrollX = mLastFocusX - focusX;
573            final float scrollY = mLastFocusY - focusY;
574            if (mIsDoubleTapping) {
575                // Give the move events of the double-tap
576                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
577            } else if (mAlwaysInTapRegion) {
578                final int deltaX = (int) (focusX - mDownFocusX);
579                final int deltaY = (int) (focusY - mDownFocusY);
580                int distance = (deltaX * deltaX) + (deltaY * deltaY);
581                if (distance > mTouchSlopSquare) {
582                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
583                    mLastFocusX = focusX;
584                    mLastFocusY = focusY;
585                    mAlwaysInTapRegion = false;
586                    mHandler.removeMessages(TAP);
587                    mHandler.removeMessages(SHOW_PRESS);
588                    mHandler.removeMessages(LONG_PRESS);
589                }
590                if (distance > mDoubleTapTouchSlopSquare) {
591                    mAlwaysInBiggerTapRegion = false;
592                }
593            } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
594                handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
595                mLastFocusX = focusX;
596                mLastFocusY = focusY;
597            }
598            break;
599 
600        case MotionEvent.ACTION_UP:
601            mStillDown = false;
602            MotionEvent currentUpEvent = MotionEvent.obtain(ev);
603            if (mIsDoubleTapping) {
604                // Finally, give the up event of the double-tap
605                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
606            } else if (mInLongPress) {
607                mHandler.removeMessages(TAP);
608                mInLongPress = false;
609            } else if (mAlwaysInTapRegion) {
610                handled = mListener.onSingleTapUp(ev);
611            } else {
612 
613                // A fling must travel the minimum tap distance
614                final VelocityTracker velocityTracker = mVelocityTracker;
615                final int pointerId = ev.getPointerId(0);
616                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
617                final float velocityY = velocityTracker.getYVelocity(pointerId);
618                final float velocityX = velocityTracker.getXVelocity(pointerId);
619 
620                if ((Math.abs(velocityY) > mMinimumFlingVelocity)
621                        || (Math.abs(velocityX) > mMinimumFlingVelocity)){
622                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
623                }
624            }
625            if (mPreviousUpEvent != null) {
626                mPreviousUpEvent.recycle();
627            }
628            // Hold the event we obtained above - listeners may have changed the original.
629            mPreviousUpEvent = currentUpEvent;
630            if (mVelocityTracker != null) {
631                // This may have been cleared when we called out to the
632                // application above.
633                mVelocityTracker.recycle();
634                mVelocityTracker = null;
635            }
636            mIsDoubleTapping = false;
637            mHandler.removeMessages(SHOW_PRESS);
638            mHandler.removeMessages(LONG_PRESS);
639            break;
640 
641        case MotionEvent.ACTION_CANCEL:
642            cancel();
643            break;
644        }
645 
646/*  Commented out in Chromium for NDK compliance
647        if (!handled && mInputEventConsistencyVerifier != null) {
648            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 0);
649        }
650*/
651        return handled;
652    }
653 
654    private void cancel() {
655        mHandler.removeMessages(SHOW_PRESS);
656        mHandler.removeMessages(LONG_PRESS);
657        mHandler.removeMessages(TAP);
658        mVelocityTracker.recycle();
659        mVelocityTracker = null;
660        mIsDoubleTapping = false;
661        mStillDown = false;
662        mAlwaysInTapRegion = false;
663        mAlwaysInBiggerTapRegion = false;
664        if (mInLongPress) {
665            mInLongPress = false;
666        }
667    }
668 
669    private void cancelTaps() {
670        mHandler.removeMessages(SHOW_PRESS);
671        mHandler.removeMessages(LONG_PRESS);
672        mHandler.removeMessages(TAP);
673        mIsDoubleTapping = false;
674        mAlwaysInTapRegion = false;
675        mAlwaysInBiggerTapRegion = false;
676        if (mInLongPress) {
677            mInLongPress = false;
678        }
679    }
680 
681    private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
682            MotionEvent secondDown) {
683        if (!mAlwaysInBiggerTapRegion) {
684            return false;
685        }
686 
687        if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {
688            return false;
689        }
690 
691        int deltaX = (int) firstDown.getX() - (int) secondDown.getX();
692        int deltaY = (int) firstDown.getY() - (int) secondDown.getY();
693        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);
694    }
695 
696    private void dispatchLongPress() {
697        mHandler.removeMessages(TAP);
698        mInLongPress = true;
699        mListener.onLongPress(mCurrentDownEvent);
700    }
701}

[all classes][org.chromium.content.browser.third_party]
EMMA 2.0.5312 (C) Vladimir Roubtsov