135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/* 2d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * Copyright (C) 2009 The Android Open Source Project 335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Licensed under the Apache License, Version 2.0 (the "License"); 535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * you may not use this file except in compliance with the License. 635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * You may obtain a copy of the License at 735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * http://www.apache.org/licenses/LICENSE-2.0 935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * 1035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Unless required by applicable law or agreed to in writing, software 1135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * distributed under the License is distributed on an "AS IS" BASIS, 1235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * See the License for the specific language governing permissions and 1435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * limitations under the License. 1535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 1635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 17db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guypackage android.gesture; 1835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 1980756e38882720860db52f1fcc21fa1505a02abfTor Norbyeimport android.annotation.ColorInt; 2035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.content.Context; 21d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.content.res.TypedArray; 2235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Canvas; 2335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Paint; 2435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Path; 2535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Rect; 2682f3495b146b267f3786997752cef25310176349Romain Guyimport android.graphics.RectF; 2735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.util.AttributeSet; 2835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.view.MotionEvent; 29d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.view.animation.AnimationUtils; 30d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.view.animation.AccelerateDecelerateInterpolator; 3182f3495b146b267f3786997752cef25310176349Romain Guyimport android.widget.FrameLayout; 3282f3495b146b267f3786997752cef25310176349Romain Guyimport android.os.SystemClock; 3351099c5aa63c8349bb7de6d1720480f2c84f404eRomain Guyimport android.annotation.Widget; 34d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport com.android.internal.R; 3535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport java.util.ArrayList; 3735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/** 3982f3495b146b267f3786997752cef25310176349Romain Guy * A transparent overlay for gesture input that can be placed on top of other 4082f3495b146b267f3786997752cef25310176349Romain Guy * widgets or contain other widgets. 41d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * 4282f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_eventsInterceptionEnabled 4382f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeDuration 4482f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeOffset 45ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeEnabled 46d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeWidth 4782f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeAngleThreshold 4882f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeLengthThreshold 4982f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeSquarenessThreshold 508d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeType 51d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureColor 528d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy * @attr ref android.R.styleable#GestureOverlayView_orientation 53d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor 5435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 5551099c5aa63c8349bb7de6d1720480f2c84f404eRomain Guy@Widget 5682f3495b146b267f3786997752cef25310176349Romain Guypublic class GestureOverlayView extends FrameLayout { 5782f3495b146b267f3786997752cef25310176349Romain Guy public static final int GESTURE_STROKE_TYPE_SINGLE = 0; 5882f3495b146b267f3786997752cef25310176349Romain Guy public static final int GESTURE_STROKE_TYPE_MULTIPLE = 1; 5982f3495b146b267f3786997752cef25310176349Romain Guy 60e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public static final int ORIENTATION_HORIZONTAL = 0; 61e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public static final int ORIENTATION_VERTICAL = 1; 62e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 6382f3495b146b267f3786997752cef25310176349Romain Guy private static final int FADE_ANIMATION_RATE = 16; 6435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean GESTURE_RENDERING_ANTIALIAS = true; 6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean DITHER_FLAG = true; 6635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 6782f3495b146b267f3786997752cef25310176349Romain Guy private final Paint mGesturePaint = new Paint(); 6835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 6982f3495b146b267f3786997752cef25310176349Romain Guy private long mFadeDuration = 150; 7082f3495b146b267f3786997752cef25310176349Romain Guy private long mFadeOffset = 420; 71d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private long mFadingStart; 7282f3495b146b267f3786997752cef25310176349Romain Guy private boolean mFadingHasStarted; 73ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy private boolean mFadeEnabled = true; 74db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 7582f3495b146b267f3786997752cef25310176349Romain Guy private int mCurrentColor; 76d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private int mCertainGestureColor = 0xFFFFFF00; 7782f3495b146b267f3786997752cef25310176349Romain Guy private int mUncertainGestureColor = 0x48FFFF00; 7882f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeWidth = 12.0f; 79d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private int mInvalidateExtraBorder = 10; 8035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 8182f3495b146b267f3786997752cef25310176349Romain Guy private int mGestureStrokeType = GESTURE_STROKE_TYPE_SINGLE; 82d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy private float mGestureStrokeLengthThreshold = 50.0f; 8382f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeSquarenessTreshold = 0.275f; 8482f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeAngleThreshold = 40.0f; 8582f3495b146b267f3786997752cef25310176349Romain Guy 86e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy private int mOrientation = ORIENTATION_VERTICAL; 87e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 88d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final Rect mInvalidRect = new Rect(); 89d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final Path mPath = new Path(); 90e705f2c52e683bdad2e845b50df6b6cbed660614Romain Guy private boolean mGestureVisible = true; 9135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mX; 9335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mY; 948d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mCurveEndX; 9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mCurveEndY; 9735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 9882f3495b146b267f3786997752cef25310176349Romain Guy private float mTotalLength; 9982f3495b146b267f3786997752cef25310176349Romain Guy private boolean mIsGesturing = false; 100834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy private boolean mPreviousWasGesturing = false; 10182f3495b146b267f3786997752cef25310176349Romain Guy private boolean mInterceptEvents = true; 10282f3495b146b267f3786997752cef25310176349Romain Guy private boolean mIsListeningForGestures; 10373d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy private boolean mResetGesture; 10482f3495b146b267f3786997752cef25310176349Romain Guy 10535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // current gesture 10682f3495b146b267f3786997752cef25310176349Romain Guy private Gesture mCurrentGesture; 10782f3495b146b267f3786997752cef25310176349Romain Guy private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100); 10835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 109c534727972c3835ed997e84a349f259915ef2cddRomain Guy // TODO: Make this a list of WeakReferences 110d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final ArrayList<OnGestureListener> mOnGestureListeners = 111d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy new ArrayList<OnGestureListener>(); 11282f3495b146b267f3786997752cef25310176349Romain Guy // TODO: Make this a list of WeakReferences 11382f3495b146b267f3786997752cef25310176349Romain Guy private final ArrayList<OnGesturePerformedListener> mOnGesturePerformedListeners = 11482f3495b146b267f3786997752cef25310176349Romain Guy new ArrayList<OnGesturePerformedListener>(); 1159af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy // TODO: Make this a list of WeakReferences 1169af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy private final ArrayList<OnGesturingListener> mOnGesturingListeners = 1179af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy new ArrayList<OnGesturingListener>(); 11882f3495b146b267f3786997752cef25310176349Romain Guy 11982f3495b146b267f3786997752cef25310176349Romain Guy private boolean mHandleGestureActions; 12035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 12135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // fading out effect 12235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private boolean mIsFadingOut = false; 12382f3495b146b267f3786997752cef25310176349Romain Guy private float mFadingAlpha = 1.0f; 124d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final AccelerateDecelerateInterpolator mInterpolator = 125d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy new AccelerateDecelerateInterpolator(); 12635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 12782f3495b146b267f3786997752cef25310176349Romain Guy private final FadeOutRunnable mFadingOut = new FadeOutRunnable(); 12835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 129db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public GestureOverlayView(Context context) { 13035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li super(context); 13135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li init(); 13235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 13335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 134db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public GestureOverlayView(Context context, AttributeSet attrs) { 135d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy this(context, attrs, com.android.internal.R.attr.gestureOverlayViewStyle); 136d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 137d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 138617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GestureOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { 139617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 140617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 141617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 142617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public GestureOverlayView( 143617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 144617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 145d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 146617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette final TypedArray a = context.obtainStyledAttributes( 147617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette attrs, R.styleable.GestureOverlayView, defStyleAttr, defStyleRes); 148d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 14982f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth = a.getFloat(R.styleable.GestureOverlayView_gestureStrokeWidth, 15082f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth); 15182f3495b146b267f3786997752cef25310176349Romain Guy mInvalidateExtraBorder = Math.max(1, ((int) mGestureStrokeWidth) - 1); 152d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mCertainGestureColor = a.getColor(R.styleable.GestureOverlayView_gestureColor, 153d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mCertainGestureColor); 154d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mUncertainGestureColor = a.getColor(R.styleable.GestureOverlayView_uncertainGestureColor, 155d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mUncertainGestureColor); 156d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mFadeDuration = a.getInt(R.styleable.GestureOverlayView_fadeDuration, (int) mFadeDuration); 157d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mFadeOffset = a.getInt(R.styleable.GestureOverlayView_fadeOffset, (int) mFadeOffset); 15882f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType = a.getInt(R.styleable.GestureOverlayView_gestureStrokeType, 15982f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType); 16082f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold = a.getFloat( 16182f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeLengthThreshold, 16282f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold); 16382f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold = a.getFloat( 16482f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeAngleThreshold, 16582f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold); 16682f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold = a.getFloat( 16782f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeSquarenessThreshold, 16882f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold); 16982f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents = a.getBoolean(R.styleable.GestureOverlayView_eventsInterceptionEnabled, 17082f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents); 171ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled = a.getBoolean(R.styleable.GestureOverlayView_fadeEnabled, 172ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled); 173e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy mOrientation = a.getInt(R.styleable.GestureOverlayView_orientation, mOrientation); 174d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 175d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy a.recycle(); 176d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 17735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li init(); 17835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 17935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 18082f3495b146b267f3786997752cef25310176349Romain Guy private void init() { 18182f3495b146b267f3786997752cef25310176349Romain Guy setWillNotDraw(false); 18235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 18382f3495b146b267f3786997752cef25310176349Romain Guy final Paint gesturePaint = mGesturePaint; 18482f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS); 18582f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setColor(mCertainGestureColor); 18682f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStyle(Paint.Style.STROKE); 18782f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeJoin(Paint.Join.ROUND); 18882f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeCap(Paint.Cap.ROUND); 18982f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeWidth(mGestureStrokeWidth); 19082f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setDither(DITHER_FLAG); 19182f3495b146b267f3786997752cef25310176349Romain Guy 19282f3495b146b267f3786997752cef25310176349Romain Guy mCurrentColor = mCertainGestureColor; 19382f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 19435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 19535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 19682f3495b146b267f3786997752cef25310176349Romain Guy public ArrayList<GesturePoint> getCurrentStroke() { 19782f3495b146b267f3786997752cef25310176349Romain Guy return mStrokeBuffer; 19835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 19935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 200e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public int getOrientation() { 201e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy return mOrientation; 202e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 203e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 204e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public void setOrientation(int orientation) { 205e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy mOrientation = orientation; 206e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 207e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 20880756e38882720860db52f1fcc21fa1505a02abfTor Norbye public void setGestureColor(@ColorInt int color) { 209db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mCertainGestureColor = color; 210db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 211db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 21280756e38882720860db52f1fcc21fa1505a02abfTor Norbye public void setUncertainGestureColor(@ColorInt int color) { 213db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mUncertainGestureColor = color; 214db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 215db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 21680756e38882720860db52f1fcc21fa1505a02abfTor Norbye @ColorInt 217db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public int getUncertainGestureColor() { 218db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy return mUncertainGestureColor; 219db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 220db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 22180756e38882720860db52f1fcc21fa1505a02abfTor Norbye @ColorInt 222db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public int getGestureColor() { 223db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy return mCertainGestureColor; 224db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 225db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 22682f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeWidth() { 22782f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeWidth; 228d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 229d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 23082f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeWidth(float gestureStrokeWidth) { 23182f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth = gestureStrokeWidth; 23282f3495b146b267f3786997752cef25310176349Romain Guy mInvalidateExtraBorder = Math.max(1, ((int) gestureStrokeWidth) - 1); 23382f3495b146b267f3786997752cef25310176349Romain Guy mGesturePaint.setStrokeWidth(gestureStrokeWidth); 234d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 235d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 23682f3495b146b267f3786997752cef25310176349Romain Guy public int getGestureStrokeType() { 23782f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeType; 23882f3495b146b267f3786997752cef25310176349Romain Guy } 23935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 24082f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeType(int gestureStrokeType) { 24182f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType = gestureStrokeType; 24282f3495b146b267f3786997752cef25310176349Romain Guy } 24335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 24482f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeLengthThreshold() { 24582f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeLengthThreshold; 24635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 24735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 24882f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeLengthThreshold(float gestureStrokeLengthThreshold) { 24982f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold = gestureStrokeLengthThreshold; 25082f3495b146b267f3786997752cef25310176349Romain Guy } 251c534727972c3835ed997e84a349f259915ef2cddRomain Guy 25282f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeSquarenessTreshold() { 25382f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeSquarenessTreshold; 25435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 25535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 25682f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeSquarenessTreshold(float gestureStrokeSquarenessTreshold) { 25782f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold = gestureStrokeSquarenessTreshold; 25882f3495b146b267f3786997752cef25310176349Romain Guy } 259c534727972c3835ed997e84a349f259915ef2cddRomain Guy 26082f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeAngleThreshold() { 26182f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeAngleThreshold; 26282f3495b146b267f3786997752cef25310176349Romain Guy } 263c534727972c3835ed997e84a349f259915ef2cddRomain Guy 26482f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeAngleThreshold(float gestureStrokeAngleThreshold) { 26582f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold = gestureStrokeAngleThreshold; 26682f3495b146b267f3786997752cef25310176349Romain Guy } 267c534727972c3835ed997e84a349f259915ef2cddRomain Guy 26882f3495b146b267f3786997752cef25310176349Romain Guy public boolean isEventsInterceptionEnabled() { 26982f3495b146b267f3786997752cef25310176349Romain Guy return mInterceptEvents; 27082f3495b146b267f3786997752cef25310176349Romain Guy } 271c534727972c3835ed997e84a349f259915ef2cddRomain Guy 27282f3495b146b267f3786997752cef25310176349Romain Guy public void setEventsInterceptionEnabled(boolean enabled) { 27382f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents = enabled; 27482f3495b146b267f3786997752cef25310176349Romain Guy } 27582f3495b146b267f3786997752cef25310176349Romain Guy 276ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy public boolean isFadeEnabled() { 277ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy return mFadeEnabled; 278ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 279ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 280ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy public void setFadeEnabled(boolean fadeEnabled) { 281ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled = fadeEnabled; 282ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 283ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 28482f3495b146b267f3786997752cef25310176349Romain Guy public Gesture getGesture() { 28582f3495b146b267f3786997752cef25310176349Romain Guy return mCurrentGesture; 28682f3495b146b267f3786997752cef25310176349Romain Guy } 287c534727972c3835ed997e84a349f259915ef2cddRomain Guy 28882f3495b146b267f3786997752cef25310176349Romain Guy public void setGesture(Gesture gesture) { 28935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li if (mCurrentGesture != null) { 29082f3495b146b267f3786997752cef25310176349Romain Guy clear(false); 29135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 29282f3495b146b267f3786997752cef25310176349Romain Guy 29382f3495b146b267f3786997752cef25310176349Romain Guy setCurrentColor(mCertainGestureColor); 29482f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = gesture; 29582f3495b146b267f3786997752cef25310176349Romain Guy 29682f3495b146b267f3786997752cef25310176349Romain Guy final Path path = mCurrentGesture.toPath(); 29782f3495b146b267f3786997752cef25310176349Romain Guy final RectF bounds = new RectF(); 29882f3495b146b267f3786997752cef25310176349Romain Guy path.computeBounds(bounds, true); 29982f3495b146b267f3786997752cef25310176349Romain Guy 300cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy // TODO: The path should also be scaled to fit inside this view 30182f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 30203f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mPath.addPath(path, -bounds.left + (getWidth() - bounds.width()) / 2.0f, 30303f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy -bounds.top + (getHeight() - bounds.height()) / 2.0f); 30403f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy 30503f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mResetGesture = true; 30682f3495b146b267f3786997752cef25310176349Romain Guy 30782f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 30835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 30935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 310b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public Path getGesturePath() { 311b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mPath; 312b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 313b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 314b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public Path getGesturePath(Path path) { 315b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy path.set(mPath); 316b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return path; 317b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 318b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 319b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public boolean isGestureVisible() { 320b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mGestureVisible; 321b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 322b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 323b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public void setGestureVisible(boolean visible) { 324b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy mGestureVisible = visible; 325b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 326b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 327b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public long getFadeOffset() { 328b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mFadeOffset; 329b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 330b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 331b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public void setFadeOffset(long fadeOffset) { 332b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy mFadeOffset = fadeOffset; 333b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 334b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 335db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void addOnGestureListener(OnGestureListener listener) { 336db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mOnGestureListeners.add(listener); 33735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 33835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 339db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void removeOnGestureListener(OnGestureListener listener) { 340db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mOnGestureListeners.remove(listener); 34135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 34235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 343d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy public void removeAllOnGestureListeners() { 344d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mOnGestureListeners.clear(); 345d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 346d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 34782f3495b146b267f3786997752cef25310176349Romain Guy public void addOnGesturePerformedListener(OnGesturePerformedListener listener) { 34882f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.add(listener); 34982f3495b146b267f3786997752cef25310176349Romain Guy if (mOnGesturePerformedListeners.size() > 0) { 35082f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = true; 35182f3495b146b267f3786997752cef25310176349Romain Guy } 35282f3495b146b267f3786997752cef25310176349Romain Guy } 35382f3495b146b267f3786997752cef25310176349Romain Guy 35482f3495b146b267f3786997752cef25310176349Romain Guy public void removeOnGesturePerformedListener(OnGesturePerformedListener listener) { 35582f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.remove(listener); 35682f3495b146b267f3786997752cef25310176349Romain Guy if (mOnGesturePerformedListeners.size() <= 0) { 35782f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = false; 35882f3495b146b267f3786997752cef25310176349Romain Guy } 35982f3495b146b267f3786997752cef25310176349Romain Guy } 36082f3495b146b267f3786997752cef25310176349Romain Guy 36182f3495b146b267f3786997752cef25310176349Romain Guy public void removeAllOnGesturePerformedListeners() { 36282f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.clear(); 36382f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = false; 36482f3495b146b267f3786997752cef25310176349Romain Guy } 36535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3669af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void addOnGesturingListener(OnGesturingListener listener) { 3679af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.add(listener); 3689af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3699af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 3709af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void removeOnGesturingListener(OnGesturingListener listener) { 3719af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.remove(listener); 3729af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3739af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 3749af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void removeAllOnGesturingListeners() { 3759af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.clear(); 3769af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3779af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 37882f3495b146b267f3786997752cef25310176349Romain Guy public boolean isGesturing() { 37982f3495b146b267f3786997752cef25310176349Romain Guy return mIsGesturing; 38082f3495b146b267f3786997752cef25310176349Romain Guy } 38182f3495b146b267f3786997752cef25310176349Romain Guy 38282f3495b146b267f3786997752cef25310176349Romain Guy private void setCurrentColor(int color) { 38382f3495b146b267f3786997752cef25310176349Romain Guy mCurrentColor = color; 38482f3495b146b267f3786997752cef25310176349Romain Guy if (mFadingHasStarted) { 38582f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha((int) (255 * mFadingAlpha)); 38635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } else { 38782f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 38882f3495b146b267f3786997752cef25310176349Romain Guy } 38982f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 39082f3495b146b267f3786997752cef25310176349Romain Guy } 39182f3495b146b267f3786997752cef25310176349Romain Guy 39227a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy /** 39327a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy * @hide 39427a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy */ 39527a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy public Paint getGesturePaint() { 39627a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy return mGesturePaint; 39727a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy } 39827a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy 39982f3495b146b267f3786997752cef25310176349Romain Guy @Override 40082f3495b146b267f3786997752cef25310176349Romain Guy public void draw(Canvas canvas) { 40182f3495b146b267f3786997752cef25310176349Romain Guy super.draw(canvas); 40282f3495b146b267f3786997752cef25310176349Romain Guy 403b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy if (mCurrentGesture != null && mGestureVisible) { 40482f3495b146b267f3786997752cef25310176349Romain Guy canvas.drawPath(mPath, mGesturePaint); 40535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 40682f3495b146b267f3786997752cef25310176349Romain Guy } 40782f3495b146b267f3786997752cef25310176349Romain Guy 40882f3495b146b267f3786997752cef25310176349Romain Guy private void setPaintAlpha(int alpha) { 40982f3495b146b267f3786997752cef25310176349Romain Guy alpha += alpha >> 7; 41082f3495b146b267f3786997752cef25310176349Romain Guy final int baseAlpha = mCurrentColor >>> 24; 41182f3495b146b267f3786997752cef25310176349Romain Guy final int useAlpha = baseAlpha * alpha >> 8; 41282f3495b146b267f3786997752cef25310176349Romain Guy mGesturePaint.setColor((mCurrentColor << 8 >>> 8) | (useAlpha << 24)); 41382f3495b146b267f3786997752cef25310176349Romain Guy } 41435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 41582f3495b146b267f3786997752cef25310176349Romain Guy public void clear(boolean animated) { 41603f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy clear(animated, false, true); 41735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 41835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 41903f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy private void clear(boolean animated, boolean fireActionPerformed, boolean immediate) { 42082f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 4219edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy removeCallbacks(mFadingOut); 42273d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = false; 4239edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingOut.fireActionPerformed = fireActionPerformed; 42473d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mFadingOut.resetMultipleStrokes = false; 4259edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 42682f3495b146b267f3786997752cef25310176349Romain Guy if (animated && mCurrentGesture != null) { 4279edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingAlpha = 1.0f; 4289edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mIsFadingOut = true; 4299edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingHasStarted = false; 4309edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingStart = AnimationUtils.currentAnimationTimeMillis() + mFadeOffset; 4319edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 432d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy postDelayed(mFadingOut, mFadeOffset); 43335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } else { 4349edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingAlpha = 1.0f; 4359edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mIsFadingOut = false; 4369edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingHasStarted = false; 4379edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 43803f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy if (immediate) { 4399edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mCurrentGesture = null; 4409edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mPath.rewind(); 4419edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy invalidate(); 44203f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy } else if (fireActionPerformed) { 44303f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy postDelayed(mFadingOut, mFadeOffset); 44473d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy } else if (mGestureStrokeType == GESTURE_STROKE_TYPE_MULTIPLE) { 44573d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mFadingOut.resetMultipleStrokes = true; 44673d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy postDelayed(mFadingOut, mFadeOffset); 44703f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy } else { 44803f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mCurrentGesture = null; 44903f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mPath.rewind(); 45003f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy invalidate(); 4519edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy } 45235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 45335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 45435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 45582f3495b146b267f3786997752cef25310176349Romain Guy public void cancelClearAnimation() { 45682f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 45735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mIsFadingOut = false; 45882f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 459d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy removeCallbacks(mFadingOut); 46082f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 46182f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 46282f3495b146b267f3786997752cef25310176349Romain Guy } 46382f3495b146b267f3786997752cef25310176349Romain Guy 46482f3495b146b267f3786997752cef25310176349Romain Guy public void cancelGesture() { 46582f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = false; 46682f3495b146b267f3786997752cef25310176349Romain Guy 46782f3495b146b267f3786997752cef25310176349Romain Guy // add the stroke to the current gesture 46882f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer)); 46982f3495b146b267f3786997752cef25310176349Romain Guy 47082f3495b146b267f3786997752cef25310176349Romain Guy // pass the event to handlers 47182f3495b146b267f3786997752cef25310176349Romain Guy final long now = SystemClock.uptimeMillis(); 47282f3495b146b267f3786997752cef25310176349Romain Guy final MotionEvent event = MotionEvent.obtain(now, now, 47382f3495b146b267f3786997752cef25310176349Romain Guy MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); 47482f3495b146b267f3786997752cef25310176349Romain Guy 47582f3495b146b267f3786997752cef25310176349Romain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 4769af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 47782f3495b146b267f3786997752cef25310176349Romain Guy for (int i = 0; i < count; i++) { 47882f3495b146b267f3786997752cef25310176349Romain Guy listeners.get(i).onGestureCancelled(this, event); 47982f3495b146b267f3786997752cef25310176349Romain Guy } 48082f3495b146b267f3786997752cef25310176349Romain Guy 48182f3495b146b267f3786997752cef25310176349Romain Guy event.recycle(); 48282f3495b146b267f3786997752cef25310176349Romain Guy 48382f3495b146b267f3786997752cef25310176349Romain Guy clear(false); 48482f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 485834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 48682f3495b146b267f3786997752cef25310176349Romain Guy mStrokeBuffer.clear(); 4879af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 4889af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> otherListeners = mOnGesturingListeners; 4899af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy count = otherListeners.size(); 4909af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 4919af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy otherListeners.get(i).onGesturingEnded(this); 4929af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 49335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 49435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 49535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li @Override 49682f3495b146b267f3786997752cef25310176349Romain Guy protected void onDetachedFromWindow() { 49746bfc4811094e5b1e3196246e457d4c6b58332ecRomain Guy super.onDetachedFromWindow(); 49882f3495b146b267f3786997752cef25310176349Romain Guy cancelClearAnimation(); 49982f3495b146b267f3786997752cef25310176349Romain Guy } 50082f3495b146b267f3786997752cef25310176349Romain Guy 50182f3495b146b267f3786997752cef25310176349Romain Guy @Override 50282f3495b146b267f3786997752cef25310176349Romain Guy public boolean dispatchTouchEvent(MotionEvent event) { 50382f3495b146b267f3786997752cef25310176349Romain Guy if (isEnabled()) { 504834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy final boolean cancelDispatch = (mIsGesturing || (mCurrentGesture != null && 505834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mCurrentGesture.getStrokesCount() > 0 && mPreviousWasGesturing)) && 506834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mInterceptEvents; 507834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy 50882f3495b146b267f3786997752cef25310176349Romain Guy processEvent(event); 50982f3495b146b267f3786997752cef25310176349Romain Guy 51082f3495b146b267f3786997752cef25310176349Romain Guy if (cancelDispatch) { 51182f3495b146b267f3786997752cef25310176349Romain Guy event.setAction(MotionEvent.ACTION_CANCEL); 51282f3495b146b267f3786997752cef25310176349Romain Guy } 51382f3495b146b267f3786997752cef25310176349Romain Guy 51482f3495b146b267f3786997752cef25310176349Romain Guy super.dispatchTouchEvent(event); 515834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy 51635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return true; 51735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 51835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 51982f3495b146b267f3786997752cef25310176349Romain Guy return super.dispatchTouchEvent(event); 520d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 521d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 52282f3495b146b267f3786997752cef25310176349Romain Guy private boolean processEvent(MotionEvent event) { 52335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li switch (event.getAction()) { 52435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_DOWN: 525e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy touchDown(event); 52682f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 52782f3495b146b267f3786997752cef25310176349Romain Guy return true; 52835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_MOVE: 52982f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 53082f3495b146b267f3786997752cef25310176349Romain Guy Rect rect = touchMove(event); 53182f3495b146b267f3786997752cef25310176349Romain Guy if (rect != null) { 53282f3495b146b267f3786997752cef25310176349Romain Guy invalidate(rect); 53382f3495b146b267f3786997752cef25310176349Romain Guy } 53482f3495b146b267f3786997752cef25310176349Romain Guy return true; 53535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 53635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li break; 53735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_UP: 53882f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 53982f3495b146b267f3786997752cef25310176349Romain Guy touchUp(event, false); 54082f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 54182f3495b146b267f3786997752cef25310176349Romain Guy return true; 54282f3495b146b267f3786997752cef25310176349Romain Guy } 543d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy break; 544d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy case MotionEvent.ACTION_CANCEL: 54582f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 54682f3495b146b267f3786997752cef25310176349Romain Guy touchUp(event, true); 54782f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 54882f3495b146b267f3786997752cef25310176349Romain Guy return true; 54982f3495b146b267f3786997752cef25310176349Romain Guy } 55035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 55182f3495b146b267f3786997752cef25310176349Romain Guy 55282f3495b146b267f3786997752cef25310176349Romain Guy return false; 55335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 55435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 555e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy private void touchDown(MotionEvent event) { 55682f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = true; 55782f3495b146b267f3786997752cef25310176349Romain Guy 55835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float x = event.getX(); 55935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float y = event.getY(); 56035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 56135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mX = x; 56235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mY = y; 56335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 56482f3495b146b267f3786997752cef25310176349Romain Guy mTotalLength = 0; 56582f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 56682f3495b146b267f3786997752cef25310176349Romain Guy 56773d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy if (mGestureStrokeType == GESTURE_STROKE_TYPE_SINGLE || mResetGesture) { 56882f3495b146b267f3786997752cef25310176349Romain Guy if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor); 56973d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = false; 57082f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 57182f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 57282f3495b146b267f3786997752cef25310176349Romain Guy } else if (mCurrentGesture == null || mCurrentGesture.getStrokesCount() == 0) { 57382f3495b146b267f3786997752cef25310176349Romain Guy if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor); 57482f3495b146b267f3786997752cef25310176349Romain Guy } 57582f3495b146b267f3786997752cef25310176349Romain Guy 57682f3495b146b267f3786997752cef25310176349Romain Guy // if there is fading out going on, stop it. 57782f3495b146b267f3786997752cef25310176349Romain Guy if (mFadingHasStarted) { 57882f3495b146b267f3786997752cef25310176349Romain Guy cancelClearAnimation(); 57982f3495b146b267f3786997752cef25310176349Romain Guy } else if (mIsFadingOut) { 58082f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 58182f3495b146b267f3786997752cef25310176349Romain Guy mIsFadingOut = false; 58282f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 58382f3495b146b267f3786997752cef25310176349Romain Guy removeCallbacks(mFadingOut); 58482f3495b146b267f3786997752cef25310176349Romain Guy } 58582f3495b146b267f3786997752cef25310176349Romain Guy 58635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li if (mCurrentGesture == null) { 58735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurrentGesture = new Gesture(); 58835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 58935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 59082f3495b146b267f3786997752cef25310176349Romain Guy mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); 59135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mPath.moveTo(x, y); 59235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 59382f3495b146b267f3786997752cef25310176349Romain Guy final int border = mInvalidateExtraBorder; 59482f3495b146b267f3786997752cef25310176349Romain Guy mInvalidRect.set((int) x - border, (int) y - border, (int) x + border, (int) y + border); 59582f3495b146b267f3786997752cef25310176349Romain Guy 59635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurveEndX = x; 59735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurveEndY = y; 598ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy 599ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy // pass the event to handlers 600ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 601ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy final int count = listeners.size(); 602ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy for (int i = 0; i < count; i++) { 603ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy listeners.get(i).onGestureStarted(this, event); 6048d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy } 60535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 60635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 60735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private Rect touchMove(MotionEvent event) { 60835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li Rect areaToRefresh = null; 6098d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 610d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float x = event.getX(); 611d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float y = event.getY(); 612d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 613d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float previousX = mX; 614d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float previousY = mY; 61535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 616d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float dx = Math.abs(x - previousX); 617d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float dy = Math.abs(y - previousY); 6188d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 619d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy if (dx >= GestureStroke.TOUCH_TOLERANCE || dy >= GestureStroke.TOUCH_TOLERANCE) { 620d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy areaToRefresh = mInvalidRect; 621d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 62235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // start with the curve end 62382f3495b146b267f3786997752cef25310176349Romain Guy final int border = mInvalidateExtraBorder; 62482f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border, 62582f3495b146b267f3786997752cef25310176349Romain Guy (int) mCurveEndX + border, (int) mCurveEndY + border); 6268d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 62782f3495b146b267f3786997752cef25310176349Romain Guy float cX = mCurveEndX = (x + previousX) / 2; 62882f3495b146b267f3786997752cef25310176349Romain Guy float cY = mCurveEndY = (y + previousY) / 2; 629d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 63082f3495b146b267f3786997752cef25310176349Romain Guy mPath.quadTo(previousX, previousY, cX, cY); 6318d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 63235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // union with the control point of the new curve 63382f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.union((int) previousX - border, (int) previousY - border, 63482f3495b146b267f3786997752cef25310176349Romain Guy (int) previousX + border, (int) previousY + border); 6358d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 63635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // union with the end point of the new curve 63782f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.union((int) cX - border, (int) cY - border, 63882f3495b146b267f3786997752cef25310176349Romain Guy (int) cX + border, (int) cY + border); 63935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 64035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mX = x; 64135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mY = y; 64235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 643d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); 64435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 645d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mHandleGestureActions && !mIsGesturing) { 64633253a4baa6279f81a73425b49dfb6abe5f5416eNeil Fuller mTotalLength += (float) Math.hypot(dx, dy); 64782f3495b146b267f3786997752cef25310176349Romain Guy 648d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mTotalLength > mGestureStrokeLengthThreshold) { 649d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final OrientedBoundingBox box = 65046c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.computeOrientedBoundingBox(mStrokeBuffer); 65182f3495b146b267f3786997752cef25310176349Romain Guy 652d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy float angle = Math.abs(box.orientation); 653d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (angle > 90) { 654d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle = 180 - angle; 655d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 65682f3495b146b267f3786997752cef25310176349Romain Guy 657d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (box.squareness > mGestureStrokeSquarenessTreshold || 658d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy (mOrientation == ORIENTATION_VERTICAL ? 659d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle < mGestureStrokeAngleThreshold : 660d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle > mGestureStrokeAngleThreshold)) { 66182f3495b146b267f3786997752cef25310176349Romain Guy 662d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mIsGesturing = true; 663d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy setCurrentColor(mCertainGestureColor); 6649af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 6659af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> listeners = mOnGesturingListeners; 6669af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 6679af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 6689af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy listeners.get(i).onGesturingStarted(this); 6699af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 670d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 67182f3495b146b267f3786997752cef25310176349Romain Guy } 67282f3495b146b267f3786997752cef25310176349Romain Guy } 67382f3495b146b267f3786997752cef25310176349Romain Guy 674d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 675d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 676d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final int count = listeners.size(); 677d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 678d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGesture(this, event); 679d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 680d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 681ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy 68235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return areaToRefresh; 68335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 68435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 685d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private void touchUp(MotionEvent event, boolean cancel) { 68682f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = false; 68735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 688d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // A gesture wasn't started or was cancelled 689d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mCurrentGesture != null) { 690d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // add the stroke to the current gesture 691d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer)); 692d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 693d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (!cancel) { 694d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 695d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 696d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy int count = listeners.size(); 697d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 698d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGestureEnded(this, event); 699d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 700d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 70103f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy clear(mHandleGestureActions && mFadeEnabled, mHandleGestureActions && mIsGesturing, 70203f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy false); 703d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } else { 704d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy cancelGesture(event); 70582f3495b146b267f3786997752cef25310176349Romain Guy 70682f3495b146b267f3786997752cef25310176349Romain Guy } 707d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } else { 708d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy cancelGesture(event); 70935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 710d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 7118d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy mStrokeBuffer.clear(); 712834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = mIsGesturing; 71382f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 7149af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 7159af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> listeners = mOnGesturingListeners; 7169af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 7179af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 7189af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy listeners.get(i).onGesturingEnded(this); 7199af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 72082f3495b146b267f3786997752cef25310176349Romain Guy } 72182f3495b146b267f3786997752cef25310176349Romain Guy 722d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy private void cancelGesture(MotionEvent event) { 723d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 724d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 725d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final int count = listeners.size(); 726d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 727d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGestureCancelled(this, event); 728d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 729d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 730d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy clear(false); 731d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 732d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 733ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy private void fireOnGesturePerformed() { 7349af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturePerformedListener> actionListeners = mOnGesturePerformedListeners; 735ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy final int count = actionListeners.size(); 736ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy for (int i = 0; i < count; i++) { 7379af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy actionListeners.get(i).onGesturePerformed(GestureOverlayView.this, mCurrentGesture); 738ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 739e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 740ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 74182f3495b146b267f3786997752cef25310176349Romain Guy private class FadeOutRunnable implements Runnable { 74282f3495b146b267f3786997752cef25310176349Romain Guy boolean fireActionPerformed; 74373d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy boolean resetMultipleStrokes; 74482f3495b146b267f3786997752cef25310176349Romain Guy 74582f3495b146b267f3786997752cef25310176349Romain Guy public void run() { 74682f3495b146b267f3786997752cef25310176349Romain Guy if (mIsFadingOut) { 74782f3495b146b267f3786997752cef25310176349Romain Guy final long now = AnimationUtils.currentAnimationTimeMillis(); 74882f3495b146b267f3786997752cef25310176349Romain Guy final long duration = now - mFadingStart; 74982f3495b146b267f3786997752cef25310176349Romain Guy 75082f3495b146b267f3786997752cef25310176349Romain Guy if (duration > mFadeDuration) { 75182f3495b146b267f3786997752cef25310176349Romain Guy if (fireActionPerformed) { 752ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy fireOnGesturePerformed(); 75382f3495b146b267f3786997752cef25310176349Romain Guy } 75482f3495b146b267f3786997752cef25310176349Romain Guy 755834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 75682f3495b146b267f3786997752cef25310176349Romain Guy mIsFadingOut = false; 75782f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 75882f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 75982f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 76082f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 76182f3495b146b267f3786997752cef25310176349Romain Guy } else { 76282f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = true; 76382f3495b146b267f3786997752cef25310176349Romain Guy float interpolatedTime = Math.max(0.0f, 76482f3495b146b267f3786997752cef25310176349Romain Guy Math.min(1.0f, duration / (float) mFadeDuration)); 76582f3495b146b267f3786997752cef25310176349Romain Guy mFadingAlpha = 1.0f - mInterpolator.getInterpolation(interpolatedTime); 76682f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha((int) (255 * mFadingAlpha)); 76782f3495b146b267f3786997752cef25310176349Romain Guy postDelayed(this, FADE_ANIMATION_RATE); 76882f3495b146b267f3786997752cef25310176349Romain Guy } 76973d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy } else if (resetMultipleStrokes) { 77073d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = true; 7719edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy } else { 772ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy fireOnGesturePerformed(); 773ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 774ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadingHasStarted = false; 775ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mPath.rewind(); 776ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mCurrentGesture = null; 777834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 778ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy setPaintAlpha(255); 77982f3495b146b267f3786997752cef25310176349Romain Guy } 7809edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 7818d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy invalidate(); 78282f3495b146b267f3786997752cef25310176349Romain Guy } 78335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 78435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 7859af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public static interface OnGesturingListener { 7869af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy void onGesturingStarted(GestureOverlayView overlay); 7879af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 7889af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy void onGesturingEnded(GestureOverlayView overlay); 7899af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 7909af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 791db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public static interface OnGestureListener { 792d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureStarted(GestureOverlayView overlay, MotionEvent event); 793d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 794d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGesture(GestureOverlayView overlay, MotionEvent event); 795db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 796d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureEnded(GestureOverlayView overlay, MotionEvent event); 797db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 798d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureCancelled(GestureOverlayView overlay, MotionEvent event); 799db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 80082f3495b146b267f3786997752cef25310176349Romain Guy 80182f3495b146b267f3786997752cef25310176349Romain Guy public static interface OnGesturePerformedListener { 80282f3495b146b267f3786997752cef25310176349Romain Guy void onGesturePerformed(GestureOverlayView overlay, Gesture gesture); 80382f3495b146b267f3786997752cef25310176349Romain Guy } 80435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li} 805