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 1935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.content.Context; 20d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.content.res.TypedArray; 2135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Canvas; 2235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Paint; 2335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Path; 2435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.graphics.Rect; 2582f3495b146b267f3786997752cef25310176349Romain Guyimport android.graphics.RectF; 2635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.util.AttributeSet; 2735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport android.view.MotionEvent; 28d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.view.animation.AnimationUtils; 29d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport android.view.animation.AccelerateDecelerateInterpolator; 3082f3495b146b267f3786997752cef25310176349Romain Guyimport android.widget.FrameLayout; 3182f3495b146b267f3786997752cef25310176349Romain Guyimport android.os.SystemClock; 3251099c5aa63c8349bb7de6d1720480f2c84f404eRomain Guyimport android.annotation.Widget; 33d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guyimport com.android.internal.R; 3435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liimport java.util.ArrayList; 3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/** 3882f3495b146b267f3786997752cef25310176349Romain Guy * A transparent overlay for gesture input that can be placed on top of other 3982f3495b146b267f3786997752cef25310176349Romain Guy * widgets or contain other widgets. 40d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * 4182f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_eventsInterceptionEnabled 4282f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeDuration 4382f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeOffset 44ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy * @attr ref android.R.styleable#GestureOverlayView_fadeEnabled 45d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeWidth 4682f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeAngleThreshold 4782f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeLengthThreshold 4882f3495b146b267f3786997752cef25310176349Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeSquarenessThreshold 498d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeType 50d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_gestureColor 518d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy * @attr ref android.R.styleable#GestureOverlayView_orientation 52d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy * @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor 5335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */ 5451099c5aa63c8349bb7de6d1720480f2c84f404eRomain Guy@Widget 5582f3495b146b267f3786997752cef25310176349Romain Guypublic class GestureOverlayView extends FrameLayout { 5682f3495b146b267f3786997752cef25310176349Romain Guy public static final int GESTURE_STROKE_TYPE_SINGLE = 0; 5782f3495b146b267f3786997752cef25310176349Romain Guy public static final int GESTURE_STROKE_TYPE_MULTIPLE = 1; 5882f3495b146b267f3786997752cef25310176349Romain Guy 59e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public static final int ORIENTATION_HORIZONTAL = 0; 60e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public static final int ORIENTATION_VERTICAL = 1; 61e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 6282f3495b146b267f3786997752cef25310176349Romain Guy private static final int FADE_ANIMATION_RATE = 16; 6335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean GESTURE_RENDERING_ANTIALIAS = true; 6435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private static final boolean DITHER_FLAG = true; 6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 6682f3495b146b267f3786997752cef25310176349Romain Guy private final Paint mGesturePaint = new Paint(); 6735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 6882f3495b146b267f3786997752cef25310176349Romain Guy private long mFadeDuration = 150; 6982f3495b146b267f3786997752cef25310176349Romain Guy private long mFadeOffset = 420; 70d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private long mFadingStart; 7182f3495b146b267f3786997752cef25310176349Romain Guy private boolean mFadingHasStarted; 72ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy private boolean mFadeEnabled = true; 73db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 7482f3495b146b267f3786997752cef25310176349Romain Guy private int mCurrentColor; 75d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private int mCertainGestureColor = 0xFFFFFF00; 7682f3495b146b267f3786997752cef25310176349Romain Guy private int mUncertainGestureColor = 0x48FFFF00; 7782f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeWidth = 12.0f; 78d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private int mInvalidateExtraBorder = 10; 7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 8082f3495b146b267f3786997752cef25310176349Romain Guy private int mGestureStrokeType = GESTURE_STROKE_TYPE_SINGLE; 81d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy private float mGestureStrokeLengthThreshold = 50.0f; 8282f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeSquarenessTreshold = 0.275f; 8382f3495b146b267f3786997752cef25310176349Romain Guy private float mGestureStrokeAngleThreshold = 40.0f; 8482f3495b146b267f3786997752cef25310176349Romain Guy 85e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy private int mOrientation = ORIENTATION_VERTICAL; 86e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 87d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final Rect mInvalidRect = new Rect(); 88d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final Path mPath = new Path(); 89e705f2c52e683bdad2e845b50df6b6cbed660614Romain Guy private boolean mGestureVisible = true; 9035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 9135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mX; 9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mY; 938d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 9435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mCurveEndX; 9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private float mCurveEndY; 9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 9782f3495b146b267f3786997752cef25310176349Romain Guy private float mTotalLength; 9882f3495b146b267f3786997752cef25310176349Romain Guy private boolean mIsGesturing = false; 99834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy private boolean mPreviousWasGesturing = false; 10082f3495b146b267f3786997752cef25310176349Romain Guy private boolean mInterceptEvents = true; 10182f3495b146b267f3786997752cef25310176349Romain Guy private boolean mIsListeningForGestures; 10273d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy private boolean mResetGesture; 10382f3495b146b267f3786997752cef25310176349Romain Guy 10435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // current gesture 10582f3495b146b267f3786997752cef25310176349Romain Guy private Gesture mCurrentGesture; 10682f3495b146b267f3786997752cef25310176349Romain Guy private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100); 10735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 108c534727972c3835ed997e84a349f259915ef2cddRomain Guy // TODO: Make this a list of WeakReferences 109d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final ArrayList<OnGestureListener> mOnGestureListeners = 110d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy new ArrayList<OnGestureListener>(); 11182f3495b146b267f3786997752cef25310176349Romain Guy // TODO: Make this a list of WeakReferences 11282f3495b146b267f3786997752cef25310176349Romain Guy private final ArrayList<OnGesturePerformedListener> mOnGesturePerformedListeners = 11382f3495b146b267f3786997752cef25310176349Romain Guy new ArrayList<OnGesturePerformedListener>(); 1149af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy // TODO: Make this a list of WeakReferences 1159af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy private final ArrayList<OnGesturingListener> mOnGesturingListeners = 1169af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy new ArrayList<OnGesturingListener>(); 11782f3495b146b267f3786997752cef25310176349Romain Guy 11882f3495b146b267f3786997752cef25310176349Romain Guy private boolean mHandleGestureActions; 11935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 12035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // fading out effect 12135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private boolean mIsFadingOut = false; 12282f3495b146b267f3786997752cef25310176349Romain Guy private float mFadingAlpha = 1.0f; 123d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private final AccelerateDecelerateInterpolator mInterpolator = 124d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy new AccelerateDecelerateInterpolator(); 12535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 12682f3495b146b267f3786997752cef25310176349Romain Guy private final FadeOutRunnable mFadingOut = new FadeOutRunnable(); 12735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 128db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public GestureOverlayView(Context context) { 12935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li super(context); 13035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li init(); 13135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 13235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 133db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public GestureOverlayView(Context context, AttributeSet attrs) { 134d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy this(context, attrs, com.android.internal.R.attr.gestureOverlayViewStyle); 135d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 136d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 137d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy public GestureOverlayView(Context context, AttributeSet attrs, int defStyle) { 138d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy super(context, attrs, defStyle); 139d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 140d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy TypedArray a = context.obtainStyledAttributes(attrs, 141d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy R.styleable.GestureOverlayView, defStyle, 0); 142d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 14382f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth = a.getFloat(R.styleable.GestureOverlayView_gestureStrokeWidth, 14482f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth); 14582f3495b146b267f3786997752cef25310176349Romain Guy mInvalidateExtraBorder = Math.max(1, ((int) mGestureStrokeWidth) - 1); 146d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mCertainGestureColor = a.getColor(R.styleable.GestureOverlayView_gestureColor, 147d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mCertainGestureColor); 148d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mUncertainGestureColor = a.getColor(R.styleable.GestureOverlayView_uncertainGestureColor, 149d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mUncertainGestureColor); 150d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mFadeDuration = a.getInt(R.styleable.GestureOverlayView_fadeDuration, (int) mFadeDuration); 151d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mFadeOffset = a.getInt(R.styleable.GestureOverlayView_fadeOffset, (int) mFadeOffset); 15282f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType = a.getInt(R.styleable.GestureOverlayView_gestureStrokeType, 15382f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType); 15482f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold = a.getFloat( 15582f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeLengthThreshold, 15682f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold); 15782f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold = a.getFloat( 15882f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeAngleThreshold, 15982f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold); 16082f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold = a.getFloat( 16182f3495b146b267f3786997752cef25310176349Romain Guy R.styleable.GestureOverlayView_gestureStrokeSquarenessThreshold, 16282f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold); 16382f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents = a.getBoolean(R.styleable.GestureOverlayView_eventsInterceptionEnabled, 16482f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents); 165ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled = a.getBoolean(R.styleable.GestureOverlayView_fadeEnabled, 166ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled); 167e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy mOrientation = a.getInt(R.styleable.GestureOverlayView_orientation, mOrientation); 168d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 169d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy a.recycle(); 170d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 17135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li init(); 17235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 17335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 17482f3495b146b267f3786997752cef25310176349Romain Guy private void init() { 17582f3495b146b267f3786997752cef25310176349Romain Guy setWillNotDraw(false); 17635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 17782f3495b146b267f3786997752cef25310176349Romain Guy final Paint gesturePaint = mGesturePaint; 17882f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS); 17982f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setColor(mCertainGestureColor); 18082f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStyle(Paint.Style.STROKE); 18182f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeJoin(Paint.Join.ROUND); 18282f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeCap(Paint.Cap.ROUND); 18382f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setStrokeWidth(mGestureStrokeWidth); 18482f3495b146b267f3786997752cef25310176349Romain Guy gesturePaint.setDither(DITHER_FLAG); 18582f3495b146b267f3786997752cef25310176349Romain Guy 18682f3495b146b267f3786997752cef25310176349Romain Guy mCurrentColor = mCertainGestureColor; 18782f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 18835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 18935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 19082f3495b146b267f3786997752cef25310176349Romain Guy public ArrayList<GesturePoint> getCurrentStroke() { 19182f3495b146b267f3786997752cef25310176349Romain Guy return mStrokeBuffer; 19235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 19335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 194e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public int getOrientation() { 195e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy return mOrientation; 196e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 197e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 198e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy public void setOrientation(int orientation) { 199e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy mOrientation = orientation; 200e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 201e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy 202db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void setGestureColor(int color) { 203db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mCertainGestureColor = color; 204db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 205db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 206db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void setUncertainGestureColor(int color) { 207db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mUncertainGestureColor = color; 208db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 209db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 210db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public int getUncertainGestureColor() { 211db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy return mUncertainGestureColor; 212db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 213db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 214db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public int getGestureColor() { 215db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy return mCertainGestureColor; 216db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 217db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 21882f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeWidth() { 21982f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeWidth; 220d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 221d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 22282f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeWidth(float gestureStrokeWidth) { 22382f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeWidth = gestureStrokeWidth; 22482f3495b146b267f3786997752cef25310176349Romain Guy mInvalidateExtraBorder = Math.max(1, ((int) gestureStrokeWidth) - 1); 22582f3495b146b267f3786997752cef25310176349Romain Guy mGesturePaint.setStrokeWidth(gestureStrokeWidth); 226d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 227d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 22882f3495b146b267f3786997752cef25310176349Romain Guy public int getGestureStrokeType() { 22982f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeType; 23082f3495b146b267f3786997752cef25310176349Romain Guy } 23135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 23282f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeType(int gestureStrokeType) { 23382f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeType = gestureStrokeType; 23482f3495b146b267f3786997752cef25310176349Romain Guy } 23535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 23682f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeLengthThreshold() { 23782f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeLengthThreshold; 23835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 23935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 24082f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeLengthThreshold(float gestureStrokeLengthThreshold) { 24182f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeLengthThreshold = gestureStrokeLengthThreshold; 24282f3495b146b267f3786997752cef25310176349Romain Guy } 243c534727972c3835ed997e84a349f259915ef2cddRomain Guy 24482f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeSquarenessTreshold() { 24582f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeSquarenessTreshold; 24635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 24735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 24882f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeSquarenessTreshold(float gestureStrokeSquarenessTreshold) { 24982f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeSquarenessTreshold = gestureStrokeSquarenessTreshold; 25082f3495b146b267f3786997752cef25310176349Romain Guy } 251c534727972c3835ed997e84a349f259915ef2cddRomain Guy 25282f3495b146b267f3786997752cef25310176349Romain Guy public float getGestureStrokeAngleThreshold() { 25382f3495b146b267f3786997752cef25310176349Romain Guy return mGestureStrokeAngleThreshold; 25482f3495b146b267f3786997752cef25310176349Romain Guy } 255c534727972c3835ed997e84a349f259915ef2cddRomain Guy 25682f3495b146b267f3786997752cef25310176349Romain Guy public void setGestureStrokeAngleThreshold(float gestureStrokeAngleThreshold) { 25782f3495b146b267f3786997752cef25310176349Romain Guy mGestureStrokeAngleThreshold = gestureStrokeAngleThreshold; 25882f3495b146b267f3786997752cef25310176349Romain Guy } 259c534727972c3835ed997e84a349f259915ef2cddRomain Guy 26082f3495b146b267f3786997752cef25310176349Romain Guy public boolean isEventsInterceptionEnabled() { 26182f3495b146b267f3786997752cef25310176349Romain Guy return mInterceptEvents; 26282f3495b146b267f3786997752cef25310176349Romain Guy } 263c534727972c3835ed997e84a349f259915ef2cddRomain Guy 26482f3495b146b267f3786997752cef25310176349Romain Guy public void setEventsInterceptionEnabled(boolean enabled) { 26582f3495b146b267f3786997752cef25310176349Romain Guy mInterceptEvents = enabled; 26682f3495b146b267f3786997752cef25310176349Romain Guy } 26782f3495b146b267f3786997752cef25310176349Romain Guy 268ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy public boolean isFadeEnabled() { 269ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy return mFadeEnabled; 270ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 271ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 272ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy public void setFadeEnabled(boolean fadeEnabled) { 273ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadeEnabled = fadeEnabled; 274ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 275ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 27682f3495b146b267f3786997752cef25310176349Romain Guy public Gesture getGesture() { 27782f3495b146b267f3786997752cef25310176349Romain Guy return mCurrentGesture; 27882f3495b146b267f3786997752cef25310176349Romain Guy } 279c534727972c3835ed997e84a349f259915ef2cddRomain Guy 28082f3495b146b267f3786997752cef25310176349Romain Guy public void setGesture(Gesture gesture) { 28135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li if (mCurrentGesture != null) { 28282f3495b146b267f3786997752cef25310176349Romain Guy clear(false); 28335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 28482f3495b146b267f3786997752cef25310176349Romain Guy 28582f3495b146b267f3786997752cef25310176349Romain Guy setCurrentColor(mCertainGestureColor); 28682f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = gesture; 28782f3495b146b267f3786997752cef25310176349Romain Guy 28882f3495b146b267f3786997752cef25310176349Romain Guy final Path path = mCurrentGesture.toPath(); 28982f3495b146b267f3786997752cef25310176349Romain Guy final RectF bounds = new RectF(); 29082f3495b146b267f3786997752cef25310176349Romain Guy path.computeBounds(bounds, true); 29182f3495b146b267f3786997752cef25310176349Romain Guy 292cfbe8cf878f60ab2e3e25c09a91227dd85731718Romain Guy // TODO: The path should also be scaled to fit inside this view 29382f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 29403f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mPath.addPath(path, -bounds.left + (getWidth() - bounds.width()) / 2.0f, 29503f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy -bounds.top + (getHeight() - bounds.height()) / 2.0f); 29603f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy 29703f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mResetGesture = true; 29882f3495b146b267f3786997752cef25310176349Romain Guy 29982f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 30035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 30135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 302b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public Path getGesturePath() { 303b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mPath; 304b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 305b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 306b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public Path getGesturePath(Path path) { 307b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy path.set(mPath); 308b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return path; 309b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 310b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 311b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public boolean isGestureVisible() { 312b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mGestureVisible; 313b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 314b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 315b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public void setGestureVisible(boolean visible) { 316b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy mGestureVisible = visible; 317b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 318b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 319b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public long getFadeOffset() { 320b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy return mFadeOffset; 321b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 322b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 323b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy public void setFadeOffset(long fadeOffset) { 324b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy mFadeOffset = fadeOffset; 325b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy } 326b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy 327db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void addOnGestureListener(OnGestureListener listener) { 328db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mOnGestureListeners.add(listener); 32935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 33035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 331db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public void removeOnGestureListener(OnGestureListener listener) { 332db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy mOnGestureListeners.remove(listener); 33335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 33435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 335d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy public void removeAllOnGestureListeners() { 336d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy mOnGestureListeners.clear(); 337d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 338d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 33982f3495b146b267f3786997752cef25310176349Romain Guy public void addOnGesturePerformedListener(OnGesturePerformedListener listener) { 34082f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.add(listener); 34182f3495b146b267f3786997752cef25310176349Romain Guy if (mOnGesturePerformedListeners.size() > 0) { 34282f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = true; 34382f3495b146b267f3786997752cef25310176349Romain Guy } 34482f3495b146b267f3786997752cef25310176349Romain Guy } 34582f3495b146b267f3786997752cef25310176349Romain Guy 34682f3495b146b267f3786997752cef25310176349Romain Guy public void removeOnGesturePerformedListener(OnGesturePerformedListener listener) { 34782f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.remove(listener); 34882f3495b146b267f3786997752cef25310176349Romain Guy if (mOnGesturePerformedListeners.size() <= 0) { 34982f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = false; 35082f3495b146b267f3786997752cef25310176349Romain Guy } 35182f3495b146b267f3786997752cef25310176349Romain Guy } 35282f3495b146b267f3786997752cef25310176349Romain Guy 35382f3495b146b267f3786997752cef25310176349Romain Guy public void removeAllOnGesturePerformedListeners() { 35482f3495b146b267f3786997752cef25310176349Romain Guy mOnGesturePerformedListeners.clear(); 35582f3495b146b267f3786997752cef25310176349Romain Guy mHandleGestureActions = false; 35682f3495b146b267f3786997752cef25310176349Romain Guy } 35735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 3589af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void addOnGesturingListener(OnGesturingListener listener) { 3599af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.add(listener); 3609af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3619af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 3629af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void removeOnGesturingListener(OnGesturingListener listener) { 3639af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.remove(listener); 3649af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3659af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 3669af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public void removeAllOnGesturingListeners() { 3679af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy mOnGesturingListeners.clear(); 3689af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 3699af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 37082f3495b146b267f3786997752cef25310176349Romain Guy public boolean isGesturing() { 37182f3495b146b267f3786997752cef25310176349Romain Guy return mIsGesturing; 37282f3495b146b267f3786997752cef25310176349Romain Guy } 37382f3495b146b267f3786997752cef25310176349Romain Guy 37482f3495b146b267f3786997752cef25310176349Romain Guy private void setCurrentColor(int color) { 37582f3495b146b267f3786997752cef25310176349Romain Guy mCurrentColor = color; 37682f3495b146b267f3786997752cef25310176349Romain Guy if (mFadingHasStarted) { 37782f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha((int) (255 * mFadingAlpha)); 37835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } else { 37982f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 38082f3495b146b267f3786997752cef25310176349Romain Guy } 38182f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 38282f3495b146b267f3786997752cef25310176349Romain Guy } 38382f3495b146b267f3786997752cef25310176349Romain Guy 38427a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy /** 38527a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy * @hide 38627a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy */ 38727a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy public Paint getGesturePaint() { 38827a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy return mGesturePaint; 38927a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy } 39027a2b50dedd4315b921d502a30ac0fda51fb6a7cRomain Guy 39182f3495b146b267f3786997752cef25310176349Romain Guy @Override 39282f3495b146b267f3786997752cef25310176349Romain Guy public void draw(Canvas canvas) { 39382f3495b146b267f3786997752cef25310176349Romain Guy super.draw(canvas); 39482f3495b146b267f3786997752cef25310176349Romain Guy 395b973eef289ee0315dbae147eccb1915d3ed08f43Romain Guy if (mCurrentGesture != null && mGestureVisible) { 39682f3495b146b267f3786997752cef25310176349Romain Guy canvas.drawPath(mPath, mGesturePaint); 39735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 39882f3495b146b267f3786997752cef25310176349Romain Guy } 39982f3495b146b267f3786997752cef25310176349Romain Guy 40082f3495b146b267f3786997752cef25310176349Romain Guy private void setPaintAlpha(int alpha) { 40182f3495b146b267f3786997752cef25310176349Romain Guy alpha += alpha >> 7; 40282f3495b146b267f3786997752cef25310176349Romain Guy final int baseAlpha = mCurrentColor >>> 24; 40382f3495b146b267f3786997752cef25310176349Romain Guy final int useAlpha = baseAlpha * alpha >> 8; 40482f3495b146b267f3786997752cef25310176349Romain Guy mGesturePaint.setColor((mCurrentColor << 8 >>> 8) | (useAlpha << 24)); 40582f3495b146b267f3786997752cef25310176349Romain Guy } 40635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 40782f3495b146b267f3786997752cef25310176349Romain Guy public void clear(boolean animated) { 40803f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy clear(animated, false, true); 40935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 41035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 41103f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy private void clear(boolean animated, boolean fireActionPerformed, boolean immediate) { 41282f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 4139edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy removeCallbacks(mFadingOut); 41473d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = false; 4159edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingOut.fireActionPerformed = fireActionPerformed; 41673d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mFadingOut.resetMultipleStrokes = false; 4179edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 41882f3495b146b267f3786997752cef25310176349Romain Guy if (animated && mCurrentGesture != null) { 4199edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingAlpha = 1.0f; 4209edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mIsFadingOut = true; 4219edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingHasStarted = false; 4229edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingStart = AnimationUtils.currentAnimationTimeMillis() + mFadeOffset; 4239edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 424d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy postDelayed(mFadingOut, mFadeOffset); 42535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } else { 4269edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingAlpha = 1.0f; 4279edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mIsFadingOut = false; 4289edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mFadingHasStarted = false; 4299edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 43003f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy if (immediate) { 4319edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mCurrentGesture = null; 4329edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy mPath.rewind(); 4339edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy invalidate(); 43403f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy } else if (fireActionPerformed) { 43503f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy postDelayed(mFadingOut, mFadeOffset); 43673d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy } else if (mGestureStrokeType == GESTURE_STROKE_TYPE_MULTIPLE) { 43773d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mFadingOut.resetMultipleStrokes = true; 43873d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy postDelayed(mFadingOut, mFadeOffset); 43903f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy } else { 44003f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mCurrentGesture = null; 44103f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy mPath.rewind(); 44203f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy invalidate(); 4439edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy } 44435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 44535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 44635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 44782f3495b146b267f3786997752cef25310176349Romain Guy public void cancelClearAnimation() { 44882f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 44935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mIsFadingOut = false; 45082f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 451d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy removeCallbacks(mFadingOut); 45282f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 45382f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 45482f3495b146b267f3786997752cef25310176349Romain Guy } 45582f3495b146b267f3786997752cef25310176349Romain Guy 45682f3495b146b267f3786997752cef25310176349Romain Guy public void cancelGesture() { 45782f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = false; 45882f3495b146b267f3786997752cef25310176349Romain Guy 45982f3495b146b267f3786997752cef25310176349Romain Guy // add the stroke to the current gesture 46082f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer)); 46182f3495b146b267f3786997752cef25310176349Romain Guy 46282f3495b146b267f3786997752cef25310176349Romain Guy // pass the event to handlers 46382f3495b146b267f3786997752cef25310176349Romain Guy final long now = SystemClock.uptimeMillis(); 46482f3495b146b267f3786997752cef25310176349Romain Guy final MotionEvent event = MotionEvent.obtain(now, now, 46582f3495b146b267f3786997752cef25310176349Romain Guy MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); 46682f3495b146b267f3786997752cef25310176349Romain Guy 46782f3495b146b267f3786997752cef25310176349Romain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 4689af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 46982f3495b146b267f3786997752cef25310176349Romain Guy for (int i = 0; i < count; i++) { 47082f3495b146b267f3786997752cef25310176349Romain Guy listeners.get(i).onGestureCancelled(this, event); 47182f3495b146b267f3786997752cef25310176349Romain Guy } 47282f3495b146b267f3786997752cef25310176349Romain Guy 47382f3495b146b267f3786997752cef25310176349Romain Guy event.recycle(); 47482f3495b146b267f3786997752cef25310176349Romain Guy 47582f3495b146b267f3786997752cef25310176349Romain Guy clear(false); 47682f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 477834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 47882f3495b146b267f3786997752cef25310176349Romain Guy mStrokeBuffer.clear(); 4799af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 4809af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> otherListeners = mOnGesturingListeners; 4819af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy count = otherListeners.size(); 4829af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 4839af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy otherListeners.get(i).onGesturingEnded(this); 4849af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 48535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 48635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 48735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li @Override 48882f3495b146b267f3786997752cef25310176349Romain Guy protected void onDetachedFromWindow() { 48982f3495b146b267f3786997752cef25310176349Romain Guy cancelClearAnimation(); 49082f3495b146b267f3786997752cef25310176349Romain Guy } 49182f3495b146b267f3786997752cef25310176349Romain Guy 49282f3495b146b267f3786997752cef25310176349Romain Guy @Override 49382f3495b146b267f3786997752cef25310176349Romain Guy public boolean dispatchTouchEvent(MotionEvent event) { 49482f3495b146b267f3786997752cef25310176349Romain Guy if (isEnabled()) { 495834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy final boolean cancelDispatch = (mIsGesturing || (mCurrentGesture != null && 496834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mCurrentGesture.getStrokesCount() > 0 && mPreviousWasGesturing)) && 497834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mInterceptEvents; 498834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy 49982f3495b146b267f3786997752cef25310176349Romain Guy processEvent(event); 50082f3495b146b267f3786997752cef25310176349Romain Guy 50182f3495b146b267f3786997752cef25310176349Romain Guy if (cancelDispatch) { 50282f3495b146b267f3786997752cef25310176349Romain Guy event.setAction(MotionEvent.ACTION_CANCEL); 50382f3495b146b267f3786997752cef25310176349Romain Guy } 50482f3495b146b267f3786997752cef25310176349Romain Guy 50582f3495b146b267f3786997752cef25310176349Romain Guy super.dispatchTouchEvent(event); 506834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy 50735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return true; 50835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 50935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 51082f3495b146b267f3786997752cef25310176349Romain Guy return super.dispatchTouchEvent(event); 511d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } 512d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 51382f3495b146b267f3786997752cef25310176349Romain Guy private boolean processEvent(MotionEvent event) { 51435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li switch (event.getAction()) { 51535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_DOWN: 516e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy touchDown(event); 51782f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 51882f3495b146b267f3786997752cef25310176349Romain Guy return true; 51935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_MOVE: 52082f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 52182f3495b146b267f3786997752cef25310176349Romain Guy Rect rect = touchMove(event); 52282f3495b146b267f3786997752cef25310176349Romain Guy if (rect != null) { 52382f3495b146b267f3786997752cef25310176349Romain Guy invalidate(rect); 52482f3495b146b267f3786997752cef25310176349Romain Guy } 52582f3495b146b267f3786997752cef25310176349Romain Guy return true; 52635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 52735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li break; 52835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li case MotionEvent.ACTION_UP: 52982f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 53082f3495b146b267f3786997752cef25310176349Romain Guy touchUp(event, false); 53182f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 53282f3495b146b267f3786997752cef25310176349Romain Guy return true; 53382f3495b146b267f3786997752cef25310176349Romain Guy } 534d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy break; 535d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy case MotionEvent.ACTION_CANCEL: 53682f3495b146b267f3786997752cef25310176349Romain Guy if (mIsListeningForGestures) { 53782f3495b146b267f3786997752cef25310176349Romain Guy touchUp(event, true); 53882f3495b146b267f3786997752cef25310176349Romain Guy invalidate(); 53982f3495b146b267f3786997752cef25310176349Romain Guy return true; 54082f3495b146b267f3786997752cef25310176349Romain Guy } 54135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 54282f3495b146b267f3786997752cef25310176349Romain Guy 54382f3495b146b267f3786997752cef25310176349Romain Guy return false; 54435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 54535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 546e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy private void touchDown(MotionEvent event) { 54782f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = true; 54882f3495b146b267f3786997752cef25310176349Romain Guy 54935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float x = event.getX(); 55035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li float y = event.getY(); 55135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 55235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mX = x; 55335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mY = y; 55435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 55582f3495b146b267f3786997752cef25310176349Romain Guy mTotalLength = 0; 55682f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 55782f3495b146b267f3786997752cef25310176349Romain Guy 55873d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy if (mGestureStrokeType == GESTURE_STROKE_TYPE_SINGLE || mResetGesture) { 55982f3495b146b267f3786997752cef25310176349Romain Guy if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor); 56073d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = false; 56182f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 56282f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 56382f3495b146b267f3786997752cef25310176349Romain Guy } else if (mCurrentGesture == null || mCurrentGesture.getStrokesCount() == 0) { 56482f3495b146b267f3786997752cef25310176349Romain Guy if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor); 56582f3495b146b267f3786997752cef25310176349Romain Guy } 56682f3495b146b267f3786997752cef25310176349Romain Guy 56782f3495b146b267f3786997752cef25310176349Romain Guy // if there is fading out going on, stop it. 56882f3495b146b267f3786997752cef25310176349Romain Guy if (mFadingHasStarted) { 56982f3495b146b267f3786997752cef25310176349Romain Guy cancelClearAnimation(); 57082f3495b146b267f3786997752cef25310176349Romain Guy } else if (mIsFadingOut) { 57182f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 57282f3495b146b267f3786997752cef25310176349Romain Guy mIsFadingOut = false; 57382f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 57482f3495b146b267f3786997752cef25310176349Romain Guy removeCallbacks(mFadingOut); 57582f3495b146b267f3786997752cef25310176349Romain Guy } 57682f3495b146b267f3786997752cef25310176349Romain Guy 57735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li if (mCurrentGesture == null) { 57835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurrentGesture = new Gesture(); 57935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 58035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 58182f3495b146b267f3786997752cef25310176349Romain Guy mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); 58235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mPath.moveTo(x, y); 58335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 58482f3495b146b267f3786997752cef25310176349Romain Guy final int border = mInvalidateExtraBorder; 58582f3495b146b267f3786997752cef25310176349Romain Guy mInvalidRect.set((int) x - border, (int) y - border, (int) x + border, (int) y + border); 58682f3495b146b267f3786997752cef25310176349Romain Guy 58735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurveEndX = x; 58835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mCurveEndY = y; 589ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy 590ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy // pass the event to handlers 591ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 592ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy final int count = listeners.size(); 593ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy for (int i = 0; i < count; i++) { 594ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy listeners.get(i).onGestureStarted(this, event); 5958d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy } 59635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 59735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 59835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li private Rect touchMove(MotionEvent event) { 59935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li Rect areaToRefresh = null; 6008d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 601d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float x = event.getX(); 602d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float y = event.getY(); 603d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 604d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float previousX = mX; 605d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float previousY = mY; 60635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 607d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float dx = Math.abs(x - previousX); 608d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy final float dy = Math.abs(y - previousY); 6098d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 610d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy if (dx >= GestureStroke.TOUCH_TOLERANCE || dy >= GestureStroke.TOUCH_TOLERANCE) { 611d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy areaToRefresh = mInvalidRect; 612d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 61335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // start with the curve end 61482f3495b146b267f3786997752cef25310176349Romain Guy final int border = mInvalidateExtraBorder; 61582f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border, 61682f3495b146b267f3786997752cef25310176349Romain Guy (int) mCurveEndX + border, (int) mCurveEndY + border); 6178d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 61882f3495b146b267f3786997752cef25310176349Romain Guy float cX = mCurveEndX = (x + previousX) / 2; 61982f3495b146b267f3786997752cef25310176349Romain Guy float cY = mCurveEndY = (y + previousY) / 2; 620d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 62182f3495b146b267f3786997752cef25310176349Romain Guy mPath.quadTo(previousX, previousY, cX, cY); 6228d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 62335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // union with the control point of the new curve 62482f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.union((int) previousX - border, (int) previousY - border, 62582f3495b146b267f3786997752cef25310176349Romain Guy (int) previousX + border, (int) previousY + border); 6268d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy 62735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li // union with the end point of the new curve 62882f3495b146b267f3786997752cef25310176349Romain Guy areaToRefresh.union((int) cX - border, (int) cY - border, 62982f3495b146b267f3786997752cef25310176349Romain Guy (int) cX + border, (int) cY + border); 63035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 63135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mX = x; 63235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li mY = y; 63335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 634d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); 63535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 636d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mHandleGestureActions && !mIsGesturing) { 637d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mTotalLength += (float) Math.sqrt(dx * dx + dy * dy); 63882f3495b146b267f3786997752cef25310176349Romain Guy 639d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mTotalLength > mGestureStrokeLengthThreshold) { 640d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final OrientedBoundingBox box = 64146c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy GestureUtils.computeOrientedBoundingBox(mStrokeBuffer); 64282f3495b146b267f3786997752cef25310176349Romain Guy 643d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy float angle = Math.abs(box.orientation); 644d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (angle > 90) { 645d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle = 180 - angle; 646d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 64782f3495b146b267f3786997752cef25310176349Romain Guy 648d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (box.squareness > mGestureStrokeSquarenessTreshold || 649d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy (mOrientation == ORIENTATION_VERTICAL ? 650d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle < mGestureStrokeAngleThreshold : 651d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy angle > mGestureStrokeAngleThreshold)) { 65282f3495b146b267f3786997752cef25310176349Romain Guy 653d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mIsGesturing = true; 654d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy setCurrentColor(mCertainGestureColor); 6559af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 6569af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> listeners = mOnGesturingListeners; 6579af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 6589af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 6599af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy listeners.get(i).onGesturingStarted(this); 6609af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 661d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 66282f3495b146b267f3786997752cef25310176349Romain Guy } 66382f3495b146b267f3786997752cef25310176349Romain Guy } 66482f3495b146b267f3786997752cef25310176349Romain Guy 665d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 666d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 667d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final int count = listeners.size(); 668d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 669d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGesture(this, event); 670d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 671d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 672ff686ce11e952a9001b1384d8e7d82127b0529a2Romain Guy 67335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li return areaToRefresh; 67435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 67535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 676d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy private void touchUp(MotionEvent event, boolean cancel) { 67782f3495b146b267f3786997752cef25310176349Romain Guy mIsListeningForGestures = false; 67835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 679d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // A gesture wasn't started or was cancelled 680d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (mCurrentGesture != null) { 681d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // add the stroke to the current gesture 682d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer)); 683d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 684d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy if (!cancel) { 685d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 686d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 687d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy int count = listeners.size(); 688d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 689d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGestureEnded(this, event); 690d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 691d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 69203f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy clear(mHandleGestureActions && mFadeEnabled, mHandleGestureActions && mIsGesturing, 69303f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy false); 694d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } else { 695d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy cancelGesture(event); 69682f3495b146b267f3786997752cef25310176349Romain Guy 69782f3495b146b267f3786997752cef25310176349Romain Guy } 698d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy } else { 699d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy cancelGesture(event); 70035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 701d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 7028d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy mStrokeBuffer.clear(); 703834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = mIsGesturing; 70482f3495b146b267f3786997752cef25310176349Romain Guy mIsGesturing = false; 7059af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 7069af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturingListener> listeners = mOnGesturingListeners; 7079af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy int count = listeners.size(); 7089af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy for (int i = 0; i < count; i++) { 7099af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy listeners.get(i).onGesturingEnded(this); 7109af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 71182f3495b146b267f3786997752cef25310176349Romain Guy } 71282f3495b146b267f3786997752cef25310176349Romain Guy 713d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy private void cancelGesture(MotionEvent event) { 714d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy // pass the event to handlers 715d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final ArrayList<OnGestureListener> listeners = mOnGestureListeners; 716d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy final int count = listeners.size(); 717d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy for (int i = 0; i < count; i++) { 718d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy listeners.get(i).onGestureCancelled(this, event); 719d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 720d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 721d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy clear(false); 722d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy } 723d1c67d42abdf41d10c9a7589da1e0088af1e123aRomain Guy 724ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy private void fireOnGesturePerformed() { 7259af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy final ArrayList<OnGesturePerformedListener> actionListeners = mOnGesturePerformedListeners; 726ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy final int count = actionListeners.size(); 727ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy for (int i = 0; i < count; i++) { 7289af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy actionListeners.get(i).onGesturePerformed(GestureOverlayView.this, mCurrentGesture); 729ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy } 730e7c36dda7ada30e02f3aa9d75f282a53402aeae7Romain Guy } 731ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 73282f3495b146b267f3786997752cef25310176349Romain Guy private class FadeOutRunnable implements Runnable { 73382f3495b146b267f3786997752cef25310176349Romain Guy boolean fireActionPerformed; 73473d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy boolean resetMultipleStrokes; 73582f3495b146b267f3786997752cef25310176349Romain Guy 73682f3495b146b267f3786997752cef25310176349Romain Guy public void run() { 73782f3495b146b267f3786997752cef25310176349Romain Guy if (mIsFadingOut) { 73882f3495b146b267f3786997752cef25310176349Romain Guy final long now = AnimationUtils.currentAnimationTimeMillis(); 73982f3495b146b267f3786997752cef25310176349Romain Guy final long duration = now - mFadingStart; 74082f3495b146b267f3786997752cef25310176349Romain Guy 74182f3495b146b267f3786997752cef25310176349Romain Guy if (duration > mFadeDuration) { 74282f3495b146b267f3786997752cef25310176349Romain Guy if (fireActionPerformed) { 743ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy fireOnGesturePerformed(); 74482f3495b146b267f3786997752cef25310176349Romain Guy } 74582f3495b146b267f3786997752cef25310176349Romain Guy 746834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 74782f3495b146b267f3786997752cef25310176349Romain Guy mIsFadingOut = false; 74882f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = false; 74982f3495b146b267f3786997752cef25310176349Romain Guy mPath.rewind(); 75082f3495b146b267f3786997752cef25310176349Romain Guy mCurrentGesture = null; 75182f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha(255); 75282f3495b146b267f3786997752cef25310176349Romain Guy } else { 75382f3495b146b267f3786997752cef25310176349Romain Guy mFadingHasStarted = true; 75482f3495b146b267f3786997752cef25310176349Romain Guy float interpolatedTime = Math.max(0.0f, 75582f3495b146b267f3786997752cef25310176349Romain Guy Math.min(1.0f, duration / (float) mFadeDuration)); 75682f3495b146b267f3786997752cef25310176349Romain Guy mFadingAlpha = 1.0f - mInterpolator.getInterpolation(interpolatedTime); 75782f3495b146b267f3786997752cef25310176349Romain Guy setPaintAlpha((int) (255 * mFadingAlpha)); 75882f3495b146b267f3786997752cef25310176349Romain Guy postDelayed(this, FADE_ANIMATION_RATE); 75982f3495b146b267f3786997752cef25310176349Romain Guy } 76073d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy } else if (resetMultipleStrokes) { 76173d2589d6df34307c22f1adcdfa1debf4c780eccRomain Guy mResetGesture = true; 7629edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy } else { 763ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy fireOnGesturePerformed(); 764ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy 765ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mFadingHasStarted = false; 766ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mPath.rewind(); 767ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy mCurrentGesture = null; 768834f0391b50d33a832bd583fd7763a9a12208e8dRomain Guy mPreviousWasGesturing = false; 769ec25df9fbc685be384f8dd764fa224a4d923e9d8Romain Guy setPaintAlpha(255); 77082f3495b146b267f3786997752cef25310176349Romain Guy } 7719edc4e8930273d9bb3b5e9cb73c219e012de8ffbRomain Guy 7728d78756c160bda736cccef9ca1a6e2d6a159ac42Romain Guy invalidate(); 77382f3495b146b267f3786997752cef25310176349Romain Guy } 77435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li } 77535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li 7769af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy public static interface OnGesturingListener { 7779af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy void onGesturingStarted(GestureOverlayView overlay); 7789af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 7799af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy void onGesturingEnded(GestureOverlayView overlay); 7809af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy } 7819af0b4f7be14f2b3ed0ecc843c57ea47ec288e55Romain Guy 782db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy public static interface OnGestureListener { 783d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureStarted(GestureOverlayView overlay, MotionEvent event); 784d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy 785d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGesture(GestureOverlayView overlay, MotionEvent event); 786db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 787d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureEnded(GestureOverlayView overlay, MotionEvent event); 788db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy 789d6a463a9f23b3901bf729f2f27a6bb8f78b95248Romain Guy void onGestureCancelled(GestureOverlayView overlay, MotionEvent event); 790db567c390bd56c05614eaa83c02dbb99f97ad9ccRomain Guy } 79182f3495b146b267f3786997752cef25310176349Romain Guy 79282f3495b146b267f3786997752cef25310176349Romain Guy public static interface OnGesturePerformedListener { 79382f3495b146b267f3786997752cef25310176349Romain Guy void onGesturePerformed(GestureOverlayView overlay, Gesture gesture); 79482f3495b146b267f3786997752cef25310176349Romain Guy } 79535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li} 796