WaveView.java revision 6033c0817427386cd3e95a992d1f34dad4188f96
13060421045d4d9e411797f91bb509824b03e33fbJim Miller/*
23060421045d4d9e411797f91bb509824b03e33fbJim Miller * Copyright (C) 2010 The Android Open Source Project
33060421045d4d9e411797f91bb509824b03e33fbJim Miller *
43060421045d4d9e411797f91bb509824b03e33fbJim Miller * Licensed under the Apache License, Version 2.0 (the "License");
53060421045d4d9e411797f91bb509824b03e33fbJim Miller * you may not use this file except in compliance with the License.
63060421045d4d9e411797f91bb509824b03e33fbJim Miller * You may obtain a copy of the License at
73060421045d4d9e411797f91bb509824b03e33fbJim Miller *
83060421045d4d9e411797f91bb509824b03e33fbJim Miller *      http://www.apache.org/licenses/LICENSE-2.0
93060421045d4d9e411797f91bb509824b03e33fbJim Miller *
103060421045d4d9e411797f91bb509824b03e33fbJim Miller * Unless required by applicable law or agreed to in writing, software
113060421045d4d9e411797f91bb509824b03e33fbJim Miller * distributed under the License is distributed on an "AS IS" BASIS,
123060421045d4d9e411797f91bb509824b03e33fbJim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133060421045d4d9e411797f91bb509824b03e33fbJim Miller * See the License for the specific language governing permissions and
143060421045d4d9e411797f91bb509824b03e33fbJim Miller * limitations under the License.
153060421045d4d9e411797f91bb509824b03e33fbJim Miller */
163060421045d4d9e411797f91bb509824b03e33fbJim Miller
173060421045d4d9e411797f91bb509824b03e33fbJim Millerpackage com.android.internal.widget;
183060421045d4d9e411797f91bb509824b03e33fbJim Miller
193060421045d4d9e411797f91bb509824b03e33fbJim Millerimport java.util.ArrayList;
203060421045d4d9e411797f91bb509824b03e33fbJim Miller
213060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.animation.ValueAnimator;
223060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.content.Context;
233060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.content.res.Resources;
243060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.graphics.Bitmap;
253060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.graphics.BitmapFactory;
263060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.graphics.Canvas;
273060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.graphics.drawable.BitmapDrawable;
283060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.os.Vibrator;
296033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganovimport android.text.TextUtils;
303060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.util.AttributeSet;
313060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.util.Log;
323060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.view.MotionEvent;
333060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.view.View;
346033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
356033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganovimport android.view.accessibility.AccessibilityManager;
363060421045d4d9e411797f91bb509824b03e33fbJim Miller
373060421045d4d9e411797f91bb509824b03e33fbJim Millerimport com.android.internal.R;
383060421045d4d9e411797f91bb509824b03e33fbJim Miller
393060421045d4d9e411797f91bb509824b03e33fbJim Miller/**
403060421045d4d9e411797f91bb509824b03e33fbJim Miller * A special widget containing a center and outer ring. Moving the center ring to the outer ring
413060421045d4d9e411797f91bb509824b03e33fbJim Miller * causes an event that can be caught by implementing OnTriggerListener.
423060421045d4d9e411797f91bb509824b03e33fbJim Miller */
433060421045d4d9e411797f91bb509824b03e33fbJim Millerpublic class WaveView extends View implements ValueAnimator.AnimatorUpdateListener {
443060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final String TAG = "WaveView";
453060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final boolean DBG = false;
463fa8a454f61c772036f5f38661d1a077fd3d8388Jim Miller    private static final int WAVE_COUNT = 20; // default wave count
473060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long VIBRATE_SHORT = 20;  // msec
483060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long VIBRATE_LONG = 20;  // msec
493060421045d4d9e411797f91bb509824b03e33fbJim Miller
503060421045d4d9e411797f91bb509824b03e33fbJim Miller    // Lock state machine states
513060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_RESET_LOCK = 0;
523060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_READY = 1;
533060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_START_ATTEMPT = 2;
543060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_ATTEMPTING = 3;
553060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_UNLOCK_ATTEMPT = 4;
563060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_UNLOCK_SUCCESS = 5;
573060421045d4d9e411797f91bb509824b03e33fbJim Miller
583060421045d4d9e411797f91bb509824b03e33fbJim Miller    // Animation properties.
590c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long DURATION = 300; // duration of transitional animations
600c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long FINAL_DURATION = 200; // duration of final animations when unlocking
610c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long RING_DELAY = 1300; // when to start fading animated rings
620c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long FINAL_DELAY = 200; // delay for unlock success animation
633060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long SHORT_DELAY = 100; // for starting one animation after another.
643060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay
653060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset
663060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long DELAY_INCREMENT = 15; // increment per wave while tracking motion
673060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long DELAY_INCREMENT2 = 12; // increment per wave while not tracking
683262a51a91655659741b3b02071ccaed258fc01fJim Miller    private static final long WAVE_DELAY = WAVE_DURATION / WAVE_COUNT; // initial propagation delay
693060421045d4d9e411797f91bb509824b03e33fbJim Miller
706033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
716033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * The scale by which to multiply the unlock handle width to compute the radius
726033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * in which it can be grabbed when accessibility is disabled.
736033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
746033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED = 0.5f;
756033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
766033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
776033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * The scale by which to multiply the unlock handle width to compute the radius
786033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * in which it can be grabbed when accessibility is enabled (more generous).
796033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
806033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.0f;
816033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
823060421045d4d9e411797f91bb509824b03e33fbJim Miller    private Vibrator mVibrator;
833060421045d4d9e411797f91bb509824b03e33fbJim Miller    private OnTriggerListener mOnTriggerListener;
843060421045d4d9e411797f91bb509824b03e33fbJim Miller    private ArrayList<DrawableHolder> mDrawables = new ArrayList<DrawableHolder>(3);
853060421045d4d9e411797f91bb509824b03e33fbJim Miller    private ArrayList<DrawableHolder> mLightWaves = new ArrayList<DrawableHolder>(WAVE_COUNT);
863060421045d4d9e411797f91bb509824b03e33fbJim Miller    private boolean mFingerDown = false;
873060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mRingRadius = 182.0f; // Radius of bitmap ring. Used to snap halo to it
883060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mSnapRadius = 136; // minimum threshold for drag unlock
893060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mWaveCount = WAVE_COUNT;  // number of waves
903262a51a91655659741b3b02071ccaed258fc01fJim Miller    private long mWaveTimerDelay = WAVE_DELAY;
913060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mCurrentWave = 0;
923060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mLockCenterX; // center of widget as dictated by widget size
933060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mLockCenterY;
943060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mMouseX; // current mouse position as of last touch event
953060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mMouseY;
963060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockRing;
973060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockDefault;
983060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockHalo;
993060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mLockState = STATE_RESET_LOCK;
1003060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
1018996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller    private boolean mWavesRunning;
1028996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller    private boolean mFinishWaves;
1033060421045d4d9e411797f91bb509824b03e33fbJim Miller
1043060421045d4d9e411797f91bb509824b03e33fbJim Miller    public WaveView(Context context) {
1053060421045d4d9e411797f91bb509824b03e33fbJim Miller        this(context, null);
1063060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1073060421045d4d9e411797f91bb509824b03e33fbJim Miller
1083060421045d4d9e411797f91bb509824b03e33fbJim Miller    public WaveView(Context context, AttributeSet attrs) {
1093060421045d4d9e411797f91bb509824b03e33fbJim Miller        super(context, attrs);
1103060421045d4d9e411797f91bb509824b03e33fbJim Miller
1113060421045d4d9e411797f91bb509824b03e33fbJim Miller        // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView);
1123060421045d4d9e411797f91bb509824b03e33fbJim Miller        // mOrientation = a.getInt(R.styleable.WaveView_orientation, HORIZONTAL);
1133060421045d4d9e411797f91bb509824b03e33fbJim Miller        // a.recycle();
1143060421045d4d9e411797f91bb509824b03e33fbJim Miller
1153060421045d4d9e411797f91bb509824b03e33fbJim Miller        initDrawables();
1163060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1173060421045d4d9e411797f91bb509824b03e33fbJim Miller
1183060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1193060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1203060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockCenterX = 0.5f * w;
1213060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockCenterY = 0.5f * h;
1223060421045d4d9e411797f91bb509824b03e33fbJim Miller        super.onSizeChanged(w, h, oldw, oldh);
1233060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1243060421045d4d9e411797f91bb509824b03e33fbJim Miller
1253060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1263060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected int getSuggestedMinimumWidth() {
1273060421045d4d9e411797f91bb509824b03e33fbJim Miller        // View should be large enough to contain the unlock ring + halo
1283060421045d4d9e411797f91bb509824b03e33fbJim Miller        return mUnlockRing.getWidth() + mUnlockHalo.getWidth();
1293060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1303060421045d4d9e411797f91bb509824b03e33fbJim Miller
1313060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1323060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected int getSuggestedMinimumHeight() {
1333060421045d4d9e411797f91bb509824b03e33fbJim Miller        // View should be large enough to contain the unlock ring + halo
1343060421045d4d9e411797f91bb509824b03e33fbJim Miller        return mUnlockRing.getHeight() + mUnlockHalo.getHeight();
1353060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1363060421045d4d9e411797f91bb509824b03e33fbJim Miller
1373060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1383060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1393060421045d4d9e411797f91bb509824b03e33fbJim Miller        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
1403060421045d4d9e411797f91bb509824b03e33fbJim Miller        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
1413060421045d4d9e411797f91bb509824b03e33fbJim Miller        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
1423060421045d4d9e411797f91bb509824b03e33fbJim Miller        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
1433060421045d4d9e411797f91bb509824b03e33fbJim Miller        int width;
1443060421045d4d9e411797f91bb509824b03e33fbJim Miller        int height;
1453060421045d4d9e411797f91bb509824b03e33fbJim Miller
1463060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (widthSpecMode == MeasureSpec.AT_MOST) {
1473060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = Math.min(widthSpecSize, getSuggestedMinimumWidth());
1483060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
1493060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = widthSpecSize;
1503060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else {
1513060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = getSuggestedMinimumWidth();
1523060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1533060421045d4d9e411797f91bb509824b03e33fbJim Miller
1543060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (heightSpecMode == MeasureSpec.AT_MOST) {
1553060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = Math.min(heightSpecSize, getSuggestedMinimumWidth());
1563060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else if (heightSpecMode == MeasureSpec.EXACTLY) {
1573060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = heightSpecSize;
1583060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else {
1593060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = getSuggestedMinimumHeight();
1603060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1613060421045d4d9e411797f91bb509824b03e33fbJim Miller
1623060421045d4d9e411797f91bb509824b03e33fbJim Miller        setMeasuredDimension(width, height);
1633060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1643060421045d4d9e411797f91bb509824b03e33fbJim Miller
1653060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void initDrawables() {
166c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing = new DrawableHolder(createDrawable(R.drawable.unlock_ring));
167c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setX(mLockCenterX);
168c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setY(mLockCenterY);
169c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setScaleX(0.1f);
170c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setScaleY(0.1f);
171c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setAlpha(0.0f);
1723060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockRing);
1733060421045d4d9e411797f91bb509824b03e33fbJim Miller
174c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault = new DrawableHolder(createDrawable(R.drawable.unlock_default));
175c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setX(mLockCenterX);
176c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setY(mLockCenterY);
177c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setScaleX(0.1f);
178c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setScaleY(0.1f);
179c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setAlpha(0.0f);
1803060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockDefault);
1813060421045d4d9e411797f91bb509824b03e33fbJim Miller
182c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo = new DrawableHolder(createDrawable(R.drawable.unlock_halo));
183c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setX(mLockCenterX);
184c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setY(mLockCenterY);
185c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setScaleX(0.1f);
186c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setScaleY(0.1f);
187c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setAlpha(0.0f);
1883060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockHalo);
1893060421045d4d9e411797f91bb509824b03e33fbJim Miller
1903060421045d4d9e411797f91bb509824b03e33fbJim Miller        BitmapDrawable wave = createDrawable(R.drawable.unlock_wave);
1913060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mWaveCount; i++) {
1923060421045d4d9e411797f91bb509824b03e33fbJim Miller            DrawableHolder holder = new DrawableHolder(wave);
1933060421045d4d9e411797f91bb509824b03e33fbJim Miller            mLightWaves.add(holder);
1943060421045d4d9e411797f91bb509824b03e33fbJim Miller            holder.setAlpha(0.0f);
1953060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1963060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1973060421045d4d9e411797f91bb509824b03e33fbJim Miller
1983060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void waveUpdateFrame(float mouseX, float mouseY, boolean fingerDown) {
1993060421045d4d9e411797f91bb509824b03e33fbJim Miller        double distX = mouseX - mLockCenterX;
2003060421045d4d9e411797f91bb509824b03e33fbJim Miller        double distY = mouseY - mLockCenterY;
2013060421045d4d9e411797f91bb509824b03e33fbJim Miller        int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
2023060421045d4d9e411797f91bb509824b03e33fbJim Miller        double touchA = Math.atan2(distX, distY);
2033060421045d4d9e411797f91bb509824b03e33fbJim Miller        float ringX = (float) (mLockCenterX + mRingRadius * Math.sin(touchA));
2043060421045d4d9e411797f91bb509824b03e33fbJim Miller        float ringY = (float) (mLockCenterY + mRingRadius * Math.cos(touchA));
2053060421045d4d9e411797f91bb509824b03e33fbJim Miller
2063060421045d4d9e411797f91bb509824b03e33fbJim Miller        switch (mLockState) {
2073060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_RESET_LOCK:
2083060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State RESET_LOCK");
2093262a51a91655659741b3b02071ccaed258fc01fJim Miller                mWaveTimerDelay = WAVE_DELAY;
2103060421045d4d9e411797f91bb509824b03e33fbJim Miller                for (int i = 0; i < mLightWaves.size(); i++) {
2113060421045d4d9e411797f91bb509824b03e33fbJim Miller                    DrawableHolder holder = mLightWaves.get(i);
2123060421045d4d9e411797f91bb509824b03e33fbJim Miller                    holder.addAnimTo(300, 0, "alpha", 0.0f, false);
2133060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
2143060421045d4d9e411797f91bb509824b03e33fbJim Miller                for (int i = 0; i < mLightWaves.size(); i++) {
2153060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLightWaves.get(i).startAnimations(this);
2163060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
2173060421045d4d9e411797f91bb509824b03e33fbJim Miller
2183060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "x", mLockCenterX, true);
2193060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "y", mLockCenterY, true);
2203060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, true);
2213060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, true);
2223060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, true);
2233060421045d4d9e411797f91bb509824b03e33fbJim Miller
2243060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("x");
2253060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("y");
2263060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleX");
2273060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleY");
2283060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("alpha");
229c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setX(mLockCenterX);
230c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setY(mLockCenterY);
231c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleX(0.1f);
232c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleY(0.1f);
233c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setAlpha(0.0f);
2343060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
2353060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
2363060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
2373060421045d4d9e411797f91bb509824b03e33fbJim Miller
2383060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("x");
2393060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("y");
2403060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("scaleX");
2413060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("scaleY");
2423060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("alpha");
243c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setX(mLockCenterX);
244c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setY(mLockCenterY);
245c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setScaleX(0.1f);
246c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setScaleY(0.1f);
247c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setAlpha(0.0f);
2483060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "x", mLockCenterX, true);
2493060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "y", mLockCenterY, true);
2503060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
2513060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
2523060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
2533060421045d4d9e411797f91bb509824b03e33fbJim Miller
2543060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mLockTimerActions);
2553060421045d4d9e411797f91bb509824b03e33fbJim Miller
2563060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_READY;
2573060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2583060421045d4d9e411797f91bb509824b03e33fbJim Miller
2593060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_READY:
2603060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State READY");
2618996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                mWaveTimerDelay = WAVE_DELAY;
2623060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2633060421045d4d9e411797f91bb509824b03e33fbJim Miller
2643060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_START_ATTEMPT:
2653060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State START_ATTEMPT");
2663060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("x");
2673060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("y");
2683060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleX");
2693060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleY");
2703060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("alpha");
271c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setX(mLockCenterX + 182);
272c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setY(mLockCenterY);
273c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleX(0.1f);
274c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleY(0.1f);
275c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setAlpha(0.0f);
2763060421045d4d9e411797f91bb509824b03e33fbJim Miller
2773060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, false);
2783060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, false);
2793060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, false);
2803060421045d4d9e411797f91bb509824b03e33fbJim Miller
2813060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 1.0f, true);
2823060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 1.0f, true);
2833060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 1.0f, true);
2843060421045d4d9e411797f91bb509824b03e33fbJim Miller
2853060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_ATTEMPTING;
2863060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2873060421045d4d9e411797f91bb509824b03e33fbJim Miller
2883060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_ATTEMPTING:
289ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                if (DBG) Log.v(TAG, "State ATTEMPTING (fingerDown = " + fingerDown + ")");
2903060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (dragDistance > mSnapRadius) {
2918996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    mFinishWaves = true; // don't start any more waves.
2923060421045d4d9e411797f91bb509824b03e33fbJim Miller                    if (fingerDown) {
2933060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "x", ringX, true);
2943060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "y", ringY, true);
2953060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
2963060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
2973060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
2983060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }  else {
299ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                        if (DBG) Log.v(TAG, "up detected, moving to STATE_UNLOCK_ATTEMPT");
3003060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mLockState = STATE_UNLOCK_ATTEMPT;
3013060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3023060421045d4d9e411797f91bb509824b03e33fbJim Miller                } else {
3038996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    // If waves have stopped, we need to kick them off again...
3048996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    if (!mWavesRunning) {
3058996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        mWavesRunning = true;
3068996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        mFinishWaves = false;
3078996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        // mWaveTimerDelay = WAVE_DELAY;
3088996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        postDelayed(mAddWaveAction, mWaveTimerDelay);
3098996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    }
3103060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "x", mouseX, true);
3113060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "y", mouseY, true);
3123060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
3133060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
3143060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
3153060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
3163060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3173060421045d4d9e411797f91bb509824b03e33fbJim Miller
3183060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_UNLOCK_ATTEMPT:
3193060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State UNLOCK_ATTEMPT");
3203060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (dragDistance > mSnapRadius) {
3213060421045d4d9e411797f91bb509824b03e33fbJim Miller                    for (int n = 0; n < mLightWaves.size(); n++) {
3223060421045d4d9e411797f91bb509824b03e33fbJim Miller                        DrawableHolder wave = mLightWaves.get(n);
3233060421045d4d9e411797f91bb509824b03e33fbJim Miller                        long delay = 1000L*(6 + n - mCurrentWave)/10L;
3240c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true);
3250c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "y", ringY, true);
3260c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "scaleX", 0.1f, true);
3270c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "scaleY", 0.1f, true);
3280c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "alpha", 0.0f, true);
3293060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3303060421045d4d9e411797f91bb509824b03e33fbJim Miller                    for (int i = 0; i < mLightWaves.size(); i++) {
3313060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mLightWaves.get(i).startAnimations(this);
3323060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3333060421045d4d9e411797f91bb509824b03e33fbJim Miller
3340c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
3350c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
3360c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false);
3370c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false);
3380c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false);
3393060421045d4d9e411797f91bb509824b03e33fbJim Miller
3400c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3413060421045d4d9e411797f91bb509824b03e33fbJim Miller
3423060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("x");
3433060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("y");
3443060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("scaleX");
3453060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("scaleY");
3463060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("alpha");
347c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setX(ringX);
348c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setY(ringY);
349c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setScaleX(0.1f);
350c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setScaleY(0.1f);
351c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setAlpha(0.0f);
3523060421045d4d9e411797f91bb509824b03e33fbJim Miller
3530c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true);
3540c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true);
3550c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true);
3560c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true);
3570c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true);
3583060421045d4d9e411797f91bb509824b03e33fbJim Miller
3590c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
3600c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
3610c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3623060421045d4d9e411797f91bb509824b03e33fbJim Miller
3630c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
3640c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
3653060421045d4d9e411797f91bb509824b03e33fbJim Miller
3660c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
3670c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
3680c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3693060421045d4d9e411797f91bb509824b03e33fbJim Miller
3703060421045d4d9e411797f91bb509824b03e33fbJim Miller                    removeCallbacks(mLockTimerActions);
3713060421045d4d9e411797f91bb509824b03e33fbJim Miller
3723060421045d4d9e411797f91bb509824b03e33fbJim Miller                    postDelayed(mLockTimerActions, RESET_TIMEOUT);
3733060421045d4d9e411797f91bb509824b03e33fbJim Miller
3743060421045d4d9e411797f91bb509824b03e33fbJim Miller                    dispatchTriggerEvent(OnTriggerListener.CENTER_HANDLE);
3753060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLockState = STATE_UNLOCK_SUCCESS;
3763060421045d4d9e411797f91bb509824b03e33fbJim Miller                } else {
3773060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLockState = STATE_RESET_LOCK;
3783060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
3793060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3803060421045d4d9e411797f91bb509824b03e33fbJim Miller
3813060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_UNLOCK_SUCCESS:
3823060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State UNLOCK_SUCCESS");
3833060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mAddWaveAction);
3843060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3853060421045d4d9e411797f91bb509824b03e33fbJim Miller
3863060421045d4d9e411797f91bb509824b03e33fbJim Miller            default:
3873060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "Unknown state " + mLockState);
3883060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3893060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
3903060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockDefault.startAnimations(this);
3913060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockHalo.startAnimations(this);
3923060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockRing.startAnimations(this);
3933060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
3943060421045d4d9e411797f91bb509824b03e33fbJim Miller
3953060421045d4d9e411797f91bb509824b03e33fbJim Miller    BitmapDrawable createDrawable(int resId) {
3963060421045d4d9e411797f91bb509824b03e33fbJim Miller        Resources res = getResources();
3973060421045d4d9e411797f91bb509824b03e33fbJim Miller        Bitmap bitmap = BitmapFactory.decodeResource(res, resId);
3983060421045d4d9e411797f91bb509824b03e33fbJim Miller        return new BitmapDrawable(res, bitmap);
3993060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
4003060421045d4d9e411797f91bb509824b03e33fbJim Miller
4013060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
4023060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onDraw(Canvas canvas) {
4033060421045d4d9e411797f91bb509824b03e33fbJim Miller        waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
4043060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mDrawables.size(); ++i) {
4053060421045d4d9e411797f91bb509824b03e33fbJim Miller            mDrawables.get(i).draw(canvas);
4063060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4073060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mLightWaves.size(); ++i) {
4083060421045d4d9e411797f91bb509824b03e33fbJim Miller            mLightWaves.get(i).draw(canvas);
4093060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4103060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
4113060421045d4d9e411797f91bb509824b03e33fbJim Miller
4123060421045d4d9e411797f91bb509824b03e33fbJim Miller    private final Runnable mLockTimerActions = new Runnable() {
4133060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void run() {
4143060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (DBG) Log.v(TAG, "LockTimerActions");
4153060421045d4d9e411797f91bb509824b03e33fbJim Miller            // reset lock after inactivity
4163060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_ATTEMPTING) {
417607d320c9d18a57350bef72cc74017366ffd04ecJim Miller                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK");
4183060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_RESET_LOCK;
4193060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4203060421045d4d9e411797f91bb509824b03e33fbJim Miller            // for prototype, reset after successful unlock
4213060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_UNLOCK_SUCCESS) {
422607d320c9d18a57350bef72cc74017366ffd04ecJim Miller                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK after success");
4233060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_RESET_LOCK;
4243060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4253060421045d4d9e411797f91bb509824b03e33fbJim Miller            invalidate();
4263060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4273060421045d4d9e411797f91bb509824b03e33fbJim Miller    };
4283060421045d4d9e411797f91bb509824b03e33fbJim Miller
4293060421045d4d9e411797f91bb509824b03e33fbJim Miller    private final Runnable mAddWaveAction = new Runnable() {
4303060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void run() {
4313060421045d4d9e411797f91bb509824b03e33fbJim Miller            double distX = mMouseX - mLockCenterX;
4323060421045d4d9e411797f91bb509824b03e33fbJim Miller            double distY = mMouseY - mLockCenterY;
4333060421045d4d9e411797f91bb509824b03e33fbJim Miller            int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
4343060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_ATTEMPTING && dragDistance < mSnapRadius
4353262a51a91655659741b3b02071ccaed258fc01fJim Miller                    && mWaveTimerDelay >= WAVE_DELAY) {
4363060421045d4d9e411797f91bb509824b03e33fbJim Miller                mWaveTimerDelay = Math.min(WAVE_DURATION, mWaveTimerDelay + DELAY_INCREMENT);
4373060421045d4d9e411797f91bb509824b03e33fbJim Miller
4383060421045d4d9e411797f91bb509824b03e33fbJim Miller                DrawableHolder wave = mLightWaves.get(mCurrentWave);
4393060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setAlpha(0.0f);
4403060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setScaleX(0.2f);
4413060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setScaleY(0.2f);
4423060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setX(mMouseX);
4433060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setY(mMouseY);
4443060421045d4d9e411797f91bb509824b03e33fbJim Miller
4453060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "x", mLockCenterX, true);
4463060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "y", mLockCenterY, true);
4473060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION*2/3, 0, "alpha", 1.0f, true);
4483060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "scaleX", 1.0f, true);
4493060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "scaleY", 1.0f, true);
4503060421045d4d9e411797f91bb509824b03e33fbJim Miller
4510c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false);
4523060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.startAnimations(WaveView.this);
4533060421045d4d9e411797f91bb509824b03e33fbJim Miller
4543060421045d4d9e411797f91bb509824b03e33fbJim Miller                mCurrentWave = (mCurrentWave+1) % mWaveCount;
4553060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "WaveTimerDelay: start new wave in " + mWaveTimerDelay);
4563060421045d4d9e411797f91bb509824b03e33fbJim Miller            } else {
4573060421045d4d9e411797f91bb509824b03e33fbJim Miller                mWaveTimerDelay += DELAY_INCREMENT2;
4583060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4598996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            if (mFinishWaves) {
4608996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                // sentinel used to restart the waves after they've stopped
4618996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                mWavesRunning = false;
4628996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            } else {
4638996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                postDelayed(mAddWaveAction, mWaveTimerDelay);
4648996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            }
4653060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4663060421045d4d9e411797f91bb509824b03e33fbJim Miller    };
4673060421045d4d9e411797f91bb509824b03e33fbJim Miller
4683060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
4696033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    public boolean onHoverEvent(MotionEvent event) {
4706033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
4716033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            final int action = event.getAction();
4726033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            switch (action) {
4736033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_ENTER:
4746033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_DOWN);
4756033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4766033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_MOVE:
4776033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_MOVE);
4786033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4796033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_EXIT:
4806033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_UP);
4816033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4826033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            }
4836033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            onTouchEvent(event);
4846033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            event.setAction(action);
4856033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
4866033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        return super.onHoverEvent(event);
4876033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
4886033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
4896033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    @Override
4903060421045d4d9e411797f91bb509824b03e33fbJim Miller    public boolean onTouchEvent(MotionEvent event) {
4913060421045d4d9e411797f91bb509824b03e33fbJim Miller        final int action = event.getAction();
4923060421045d4d9e411797f91bb509824b03e33fbJim Miller        mMouseX = event.getX();
4933060421045d4d9e411797f91bb509824b03e33fbJim Miller        mMouseY = event.getY();
4943060421045d4d9e411797f91bb509824b03e33fbJim Miller        boolean handled = false;
4953060421045d4d9e411797f91bb509824b03e33fbJim Miller        switch (action) {
4963060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_DOWN:
4973060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mLockTimerActions);
4983060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = true;
4996033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                tryTransitionToStartAttemptState(event);
5003060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5013060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5023060421045d4d9e411797f91bb509824b03e33fbJim Miller
5033060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_MOVE:
5046033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                tryTransitionToStartAttemptState(event);
5053060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5063060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5073060421045d4d9e411797f91bb509824b03e33fbJim Miller
5083060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_UP:
509ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                if (DBG) Log.v(TAG, "ACTION_UP");
5103060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = false;
5113060421045d4d9e411797f91bb509824b03e33fbJim Miller                postDelayed(mLockTimerActions, RESET_TIMEOUT);
5123060421045d4d9e411797f91bb509824b03e33fbJim Miller                setGrabbedState(OnTriggerListener.NO_HANDLE);
513ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // Normally the state machine is driven by user interaction causing redraws.
514ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // However, when there's no more user interaction and no running animations,
515ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // the state machine stops advancing because onDraw() never gets called.
516ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // The following ensures we advance to the next state in this case,
517ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // either STATE_UNLOCK_ATTEMPT or STATE_RESET_LOCK.
518ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
5193060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5203060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5213060421045d4d9e411797f91bb509824b03e33fbJim Miller
5223060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_CANCEL:
5233060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = false;
5243060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5253060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5263060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
5273060421045d4d9e411797f91bb509824b03e33fbJim Miller        invalidate();
5283060421045d4d9e411797f91bb509824b03e33fbJim Miller        return handled ? true : super.onTouchEvent(event);
5293060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
5303060421045d4d9e411797f91bb509824b03e33fbJim Miller
5313060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
5326033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * Tries to transition to start attempt state.
5336033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     *
5346033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * @param event A motion event.
5356033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5366033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private void tryTransitionToStartAttemptState(MotionEvent event) {
5376033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        final float dx = event.getX() - mUnlockHalo.getX();
5386033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        final float dy = event.getY() - mUnlockHalo.getY();
5396033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        float dist = (float) Math.hypot(dx, dy);
5406033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (dist <= getScaledGrabHandleRadius()) {
5416033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            setGrabbedState(OnTriggerListener.CENTER_HANDLE);
5426033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            if (mLockState == STATE_READY) {
5436033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                mLockState = STATE_START_ATTEMPT;
5446033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5456033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    announceUnlockHandle();
5466033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                }
5476033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            }
5486033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
5496033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5506033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5516033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5526033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * @return The radius in which the handle is grabbed scaled based on
5536033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     *     whether accessibility is enabled.
5546033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5556033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private float getScaledGrabHandleRadius() {
5566033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5576033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mUnlockHalo.getWidth();
5586033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        } else {
5596033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED * mUnlockHalo.getWidth();
5606033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
5616033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5626033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5636033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5646033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * Announces the unlock handle if accessibility is enabled.
5656033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5666033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private void announceUnlockHandle() {
5676033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        setContentDescription(mContext.getString(R.string.description_target_unlock_tablet));
5686033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
5696033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        setContentDescription(null);
5706033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5716033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5726033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5733060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Triggers haptic feedback.
5743060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
5753060421045d4d9e411797f91bb509824b03e33fbJim Miller    private synchronized void vibrate(long duration) {
5763060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (mVibrator == null) {
5773060421045d4d9e411797f91bb509824b03e33fbJim Miller            mVibrator = (android.os.Vibrator)
5783060421045d4d9e411797f91bb509824b03e33fbJim Miller                    getContext().getSystemService(Context.VIBRATOR_SERVICE);
5793060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
5803060421045d4d9e411797f91bb509824b03e33fbJim Miller        mVibrator.vibrate(duration);
5813060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
5823060421045d4d9e411797f91bb509824b03e33fbJim Miller
5833060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
5843060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Registers a callback to be invoked when the user triggers an event.
5853060421045d4d9e411797f91bb509824b03e33fbJim Miller     *
5863060421045d4d9e411797f91bb509824b03e33fbJim Miller     * @param listener the OnDialTriggerListener to attach to this view
5873060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
5883060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void setOnTriggerListener(OnTriggerListener listener) {
5893060421045d4d9e411797f91bb509824b03e33fbJim Miller        mOnTriggerListener = listener;
5903060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
5913060421045d4d9e411797f91bb509824b03e33fbJim Miller
5923060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
5933060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Dispatches a trigger event to listener. Ignored if a listener is not set.
5943060421045d4d9e411797f91bb509824b03e33fbJim Miller     * @param whichHandle the handle that triggered the event.
5953060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
5963060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void dispatchTriggerEvent(int whichHandle) {
5973060421045d4d9e411797f91bb509824b03e33fbJim Miller        vibrate(VIBRATE_LONG);
5983060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (mOnTriggerListener != null) {
5993060421045d4d9e411797f91bb509824b03e33fbJim Miller            mOnTriggerListener.onTrigger(this, whichHandle);
6003060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
6013060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6023060421045d4d9e411797f91bb509824b03e33fbJim Miller
6033060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
6043060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Sets the current grabbed state, and dispatches a grabbed state change
6053060421045d4d9e411797f91bb509824b03e33fbJim Miller     * event to our listener.
6063060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
6073060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void setGrabbedState(int newState) {
6083060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (newState != mGrabbedState) {
6093060421045d4d9e411797f91bb509824b03e33fbJim Miller            mGrabbedState = newState;
6103060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mOnTriggerListener != null) {
6113060421045d4d9e411797f91bb509824b03e33fbJim Miller                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
6123060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
6133060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
6143060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6153060421045d4d9e411797f91bb509824b03e33fbJim Miller
6163060421045d4d9e411797f91bb509824b03e33fbJim Miller    public interface OnTriggerListener {
6173060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6183060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Sent when the user releases the handle.
6193060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6203060421045d4d9e411797f91bb509824b03e33fbJim Miller        public static final int NO_HANDLE = 0;
6213060421045d4d9e411797f91bb509824b03e33fbJim Miller
6223060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6233060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Sent when the user grabs the center handle
6243060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6253060421045d4d9e411797f91bb509824b03e33fbJim Miller        public static final int CENTER_HANDLE = 10;
6263060421045d4d9e411797f91bb509824b03e33fbJim Miller
6273060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6283060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Called when the user drags the center ring beyond a threshold.
6293060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6303060421045d4d9e411797f91bb509824b03e33fbJim Miller        void onTrigger(View v, int whichHandle);
6313060421045d4d9e411797f91bb509824b03e33fbJim Miller
6323060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6333060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
6343060421045d4d9e411797f91bb509824b03e33fbJim Miller         * one of the handles.)
6353060421045d4d9e411797f91bb509824b03e33fbJim Miller         *
6363060421045d4d9e411797f91bb509824b03e33fbJim Miller         * @param v the view that was triggered
6373060421045d4d9e411797f91bb509824b03e33fbJim Miller         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #CENTER_HANDLE},
6383060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6393060421045d4d9e411797f91bb509824b03e33fbJim Miller        void onGrabbedStateChange(View v, int grabbedState);
6403060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6413060421045d4d9e411797f91bb509824b03e33fbJim Miller
6423060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void onAnimationUpdate(ValueAnimator animation) {
6433060421045d4d9e411797f91bb509824b03e33fbJim Miller        invalidate();
6443060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6453060421045d4d9e411797f91bb509824b03e33fbJim Miller
6463060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void reset() {
647607d320c9d18a57350bef72cc74017366ffd04ecJim Miller        if (DBG) Log.v(TAG, "reset() : resets state to STATE_RESET_LOCK");
6483060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockState = STATE_RESET_LOCK;
649607d320c9d18a57350bef72cc74017366ffd04ecJim Miller        invalidate();
6503060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6513060421045d4d9e411797f91bb509824b03e33fbJim Miller}
652