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;
287b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlockimport android.media.AudioAttributes;
29723a725e790d269f32980116e775d3d7f0037865Jeff Sharkeyimport android.os.UserHandle;
303060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.os.Vibrator;
31723a725e790d269f32980116e775d3d7f0037865Jeff Sharkeyimport android.provider.Settings;
323060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.util.AttributeSet;
333060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.util.Log;
343060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.view.MotionEvent;
353060421045d4d9e411797f91bb509824b03e33fbJim Millerimport android.view.View;
366033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
376033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganovimport android.view.accessibility.AccessibilityManager;
383060421045d4d9e411797f91bb509824b03e33fbJim Miller
393060421045d4d9e411797f91bb509824b03e33fbJim Millerimport com.android.internal.R;
403060421045d4d9e411797f91bb509824b03e33fbJim Miller
413060421045d4d9e411797f91bb509824b03e33fbJim Miller/**
423060421045d4d9e411797f91bb509824b03e33fbJim Miller * A special widget containing a center and outer ring. Moving the center ring to the outer ring
433060421045d4d9e411797f91bb509824b03e33fbJim Miller * causes an event that can be caught by implementing OnTriggerListener.
443060421045d4d9e411797f91bb509824b03e33fbJim Miller */
453060421045d4d9e411797f91bb509824b03e33fbJim Millerpublic class WaveView extends View implements ValueAnimator.AnimatorUpdateListener {
463060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final String TAG = "WaveView";
473060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final boolean DBG = false;
483fa8a454f61c772036f5f38661d1a077fd3d8388Jim Miller    private static final int WAVE_COUNT = 20; // default wave count
493060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long VIBRATE_SHORT = 20;  // msec
503060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long VIBRATE_LONG = 20;  // msec
513060421045d4d9e411797f91bb509824b03e33fbJim Miller
523060421045d4d9e411797f91bb509824b03e33fbJim Miller    // Lock state machine states
533060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_RESET_LOCK = 0;
543060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_READY = 1;
553060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_START_ATTEMPT = 2;
563060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_ATTEMPTING = 3;
573060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_UNLOCK_ATTEMPT = 4;
583060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final int STATE_UNLOCK_SUCCESS = 5;
593060421045d4d9e411797f91bb509824b03e33fbJim Miller
603060421045d4d9e411797f91bb509824b03e33fbJim Miller    // Animation properties.
610c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long DURATION = 300; // duration of transitional animations
620c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long FINAL_DURATION = 200; // duration of final animations when unlocking
630c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long RING_DELAY = 1300; // when to start fading animated rings
640c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller    private static final long FINAL_DELAY = 200; // delay for unlock success animation
653060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long SHORT_DELAY = 100; // for starting one animation after another.
663060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay
673060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset
683060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long DELAY_INCREMENT = 15; // increment per wave while tracking motion
693060421045d4d9e411797f91bb509824b03e33fbJim Miller    private static final long DELAY_INCREMENT2 = 12; // increment per wave while not tracking
703262a51a91655659741b3b02071ccaed258fc01fJim Miller    private static final long WAVE_DELAY = WAVE_DURATION / WAVE_COUNT; // initial propagation delay
713060421045d4d9e411797f91bb509824b03e33fbJim Miller
726033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
736033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * The scale by which to multiply the unlock handle width to compute the radius
746033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * in which it can be grabbed when accessibility is disabled.
756033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
766033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED = 0.5f;
776033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
786033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
796033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * The scale by which to multiply the unlock handle width to compute the radius
806033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * in which it can be grabbed when accessibility is enabled (more generous).
816033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
826033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.0f;
836033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
847b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
857b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
867b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
877b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            .build();
887b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock
893060421045d4d9e411797f91bb509824b03e33fbJim Miller    private Vibrator mVibrator;
903060421045d4d9e411797f91bb509824b03e33fbJim Miller    private OnTriggerListener mOnTriggerListener;
913060421045d4d9e411797f91bb509824b03e33fbJim Miller    private ArrayList<DrawableHolder> mDrawables = new ArrayList<DrawableHolder>(3);
923060421045d4d9e411797f91bb509824b03e33fbJim Miller    private ArrayList<DrawableHolder> mLightWaves = new ArrayList<DrawableHolder>(WAVE_COUNT);
933060421045d4d9e411797f91bb509824b03e33fbJim Miller    private boolean mFingerDown = false;
943060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mRingRadius = 182.0f; // Radius of bitmap ring. Used to snap halo to it
953060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mSnapRadius = 136; // minimum threshold for drag unlock
963060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mWaveCount = WAVE_COUNT;  // number of waves
973262a51a91655659741b3b02071ccaed258fc01fJim Miller    private long mWaveTimerDelay = WAVE_DELAY;
983060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mCurrentWave = 0;
993060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mLockCenterX; // center of widget as dictated by widget size
1003060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mLockCenterY;
1013060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mMouseX; // current mouse position as of last touch event
1023060421045d4d9e411797f91bb509824b03e33fbJim Miller    private float mMouseY;
1033060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockRing;
1043060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockDefault;
1053060421045d4d9e411797f91bb509824b03e33fbJim Miller    private DrawableHolder mUnlockHalo;
1063060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mLockState = STATE_RESET_LOCK;
1073060421045d4d9e411797f91bb509824b03e33fbJim Miller    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
1088996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller    private boolean mWavesRunning;
1098996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller    private boolean mFinishWaves;
1103060421045d4d9e411797f91bb509824b03e33fbJim Miller
1113060421045d4d9e411797f91bb509824b03e33fbJim Miller    public WaveView(Context context) {
1123060421045d4d9e411797f91bb509824b03e33fbJim Miller        this(context, null);
1133060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1143060421045d4d9e411797f91bb509824b03e33fbJim Miller
1153060421045d4d9e411797f91bb509824b03e33fbJim Miller    public WaveView(Context context, AttributeSet attrs) {
1163060421045d4d9e411797f91bb509824b03e33fbJim Miller        super(context, attrs);
1173060421045d4d9e411797f91bb509824b03e33fbJim Miller
1183060421045d4d9e411797f91bb509824b03e33fbJim Miller        // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView);
1193060421045d4d9e411797f91bb509824b03e33fbJim Miller        // mOrientation = a.getInt(R.styleable.WaveView_orientation, HORIZONTAL);
1203060421045d4d9e411797f91bb509824b03e33fbJim Miller        // a.recycle();
1213060421045d4d9e411797f91bb509824b03e33fbJim Miller
1223060421045d4d9e411797f91bb509824b03e33fbJim Miller        initDrawables();
1233060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1243060421045d4d9e411797f91bb509824b03e33fbJim Miller
1253060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1263060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1273060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockCenterX = 0.5f * w;
1283060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockCenterY = 0.5f * h;
1293060421045d4d9e411797f91bb509824b03e33fbJim Miller        super.onSizeChanged(w, h, oldw, oldh);
1303060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1313060421045d4d9e411797f91bb509824b03e33fbJim Miller
1323060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1333060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected int getSuggestedMinimumWidth() {
1343060421045d4d9e411797f91bb509824b03e33fbJim Miller        // View should be large enough to contain the unlock ring + halo
1353060421045d4d9e411797f91bb509824b03e33fbJim Miller        return mUnlockRing.getWidth() + mUnlockHalo.getWidth();
1363060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1373060421045d4d9e411797f91bb509824b03e33fbJim Miller
1383060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1393060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected int getSuggestedMinimumHeight() {
1403060421045d4d9e411797f91bb509824b03e33fbJim Miller        // View should be large enough to contain the unlock ring + halo
1413060421045d4d9e411797f91bb509824b03e33fbJim Miller        return mUnlockRing.getHeight() + mUnlockHalo.getHeight();
1423060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1433060421045d4d9e411797f91bb509824b03e33fbJim Miller
1443060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
1453060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1463060421045d4d9e411797f91bb509824b03e33fbJim Miller        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
1473060421045d4d9e411797f91bb509824b03e33fbJim Miller        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
1483060421045d4d9e411797f91bb509824b03e33fbJim Miller        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
1493060421045d4d9e411797f91bb509824b03e33fbJim Miller        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
1503060421045d4d9e411797f91bb509824b03e33fbJim Miller        int width;
1513060421045d4d9e411797f91bb509824b03e33fbJim Miller        int height;
1523060421045d4d9e411797f91bb509824b03e33fbJim Miller
1533060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (widthSpecMode == MeasureSpec.AT_MOST) {
1543060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = Math.min(widthSpecSize, getSuggestedMinimumWidth());
1553060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
1563060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = widthSpecSize;
1573060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else {
1583060421045d4d9e411797f91bb509824b03e33fbJim Miller            width = getSuggestedMinimumWidth();
1593060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1603060421045d4d9e411797f91bb509824b03e33fbJim Miller
1613060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (heightSpecMode == MeasureSpec.AT_MOST) {
1623060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = Math.min(heightSpecSize, getSuggestedMinimumWidth());
1633060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else if (heightSpecMode == MeasureSpec.EXACTLY) {
1643060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = heightSpecSize;
1653060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else {
1663060421045d4d9e411797f91bb509824b03e33fbJim Miller            height = getSuggestedMinimumHeight();
1673060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1683060421045d4d9e411797f91bb509824b03e33fbJim Miller
1693060421045d4d9e411797f91bb509824b03e33fbJim Miller        setMeasuredDimension(width, height);
1703060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1713060421045d4d9e411797f91bb509824b03e33fbJim Miller
1723060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void initDrawables() {
173c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing = new DrawableHolder(createDrawable(R.drawable.unlock_ring));
174c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setX(mLockCenterX);
175c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setY(mLockCenterY);
176c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setScaleX(0.1f);
177c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setScaleY(0.1f);
178c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockRing.setAlpha(0.0f);
1793060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockRing);
1803060421045d4d9e411797f91bb509824b03e33fbJim Miller
181c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault = new DrawableHolder(createDrawable(R.drawable.unlock_default));
182c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setX(mLockCenterX);
183c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setY(mLockCenterY);
184c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setScaleX(0.1f);
185c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setScaleY(0.1f);
186c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockDefault.setAlpha(0.0f);
1873060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockDefault);
1883060421045d4d9e411797f91bb509824b03e33fbJim Miller
189c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo = new DrawableHolder(createDrawable(R.drawable.unlock_halo));
190c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setX(mLockCenterX);
191c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setY(mLockCenterY);
192c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setScaleX(0.1f);
193c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setScaleY(0.1f);
194c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller        mUnlockHalo.setAlpha(0.0f);
1953060421045d4d9e411797f91bb509824b03e33fbJim Miller        mDrawables.add(mUnlockHalo);
1963060421045d4d9e411797f91bb509824b03e33fbJim Miller
1973060421045d4d9e411797f91bb509824b03e33fbJim Miller        BitmapDrawable wave = createDrawable(R.drawable.unlock_wave);
1983060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mWaveCount; i++) {
1993060421045d4d9e411797f91bb509824b03e33fbJim Miller            DrawableHolder holder = new DrawableHolder(wave);
2003060421045d4d9e411797f91bb509824b03e33fbJim Miller            mLightWaves.add(holder);
2013060421045d4d9e411797f91bb509824b03e33fbJim Miller            holder.setAlpha(0.0f);
2023060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
2033060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
2043060421045d4d9e411797f91bb509824b03e33fbJim Miller
2053060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void waveUpdateFrame(float mouseX, float mouseY, boolean fingerDown) {
2063060421045d4d9e411797f91bb509824b03e33fbJim Miller        double distX = mouseX - mLockCenterX;
2073060421045d4d9e411797f91bb509824b03e33fbJim Miller        double distY = mouseY - mLockCenterY;
2083060421045d4d9e411797f91bb509824b03e33fbJim Miller        int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
2093060421045d4d9e411797f91bb509824b03e33fbJim Miller        double touchA = Math.atan2(distX, distY);
2103060421045d4d9e411797f91bb509824b03e33fbJim Miller        float ringX = (float) (mLockCenterX + mRingRadius * Math.sin(touchA));
2113060421045d4d9e411797f91bb509824b03e33fbJim Miller        float ringY = (float) (mLockCenterY + mRingRadius * Math.cos(touchA));
2123060421045d4d9e411797f91bb509824b03e33fbJim Miller
2133060421045d4d9e411797f91bb509824b03e33fbJim Miller        switch (mLockState) {
2143060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_RESET_LOCK:
2153060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State RESET_LOCK");
2163262a51a91655659741b3b02071ccaed258fc01fJim Miller                mWaveTimerDelay = WAVE_DELAY;
2173060421045d4d9e411797f91bb509824b03e33fbJim Miller                for (int i = 0; i < mLightWaves.size(); i++) {
2183060421045d4d9e411797f91bb509824b03e33fbJim Miller                    DrawableHolder holder = mLightWaves.get(i);
2193060421045d4d9e411797f91bb509824b03e33fbJim Miller                    holder.addAnimTo(300, 0, "alpha", 0.0f, false);
2203060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
2213060421045d4d9e411797f91bb509824b03e33fbJim Miller                for (int i = 0; i < mLightWaves.size(); i++) {
2223060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLightWaves.get(i).startAnimations(this);
2233060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
2243060421045d4d9e411797f91bb509824b03e33fbJim Miller
2253060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "x", mLockCenterX, true);
2263060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "y", mLockCenterY, true);
2273060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, true);
2283060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, true);
2293060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, true);
2303060421045d4d9e411797f91bb509824b03e33fbJim Miller
2313060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("x");
2323060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("y");
2333060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleX");
2343060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleY");
2353060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("alpha");
236c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setX(mLockCenterX);
237c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setY(mLockCenterY);
238c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleX(0.1f);
239c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleY(0.1f);
240c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setAlpha(0.0f);
2413060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
2423060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
2433060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
2443060421045d4d9e411797f91bb509824b03e33fbJim Miller
2453060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("x");
2463060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("y");
2473060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("scaleX");
2483060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("scaleY");
2493060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.removeAnimationFor("alpha");
250c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setX(mLockCenterX);
251c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setY(mLockCenterY);
252c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setScaleX(0.1f);
253c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setScaleY(0.1f);
254c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockHalo.setAlpha(0.0f);
2553060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "x", mLockCenterX, true);
2563060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "y", mLockCenterY, true);
2573060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
2583060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
2593060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
2603060421045d4d9e411797f91bb509824b03e33fbJim Miller
2613060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mLockTimerActions);
2623060421045d4d9e411797f91bb509824b03e33fbJim Miller
2633060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_READY;
2643060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2653060421045d4d9e411797f91bb509824b03e33fbJim Miller
2663060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_READY:
2673060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State READY");
2688996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                mWaveTimerDelay = WAVE_DELAY;
2693060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2703060421045d4d9e411797f91bb509824b03e33fbJim Miller
2713060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_START_ATTEMPT:
2723060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State START_ATTEMPT");
2733060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("x");
2743060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("y");
2753060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleX");
2763060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("scaleY");
2773060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.removeAnimationFor("alpha");
278c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setX(mLockCenterX + 182);
279c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setY(mLockCenterY);
280c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleX(0.1f);
281c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setScaleY(0.1f);
282c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                mUnlockDefault.setAlpha(0.0f);
2833060421045d4d9e411797f91bb509824b03e33fbJim Miller
2843060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, false);
2853060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, false);
2863060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, false);
2873060421045d4d9e411797f91bb509824b03e33fbJim Miller
2883060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 1.0f, true);
2893060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 1.0f, true);
2903060421045d4d9e411797f91bb509824b03e33fbJim Miller                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 1.0f, true);
2913060421045d4d9e411797f91bb509824b03e33fbJim Miller
2923060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_ATTEMPTING;
2933060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
2943060421045d4d9e411797f91bb509824b03e33fbJim Miller
2953060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_ATTEMPTING:
296ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                if (DBG) Log.v(TAG, "State ATTEMPTING (fingerDown = " + fingerDown + ")");
2973060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (dragDistance > mSnapRadius) {
2988996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    mFinishWaves = true; // don't start any more waves.
2993060421045d4d9e411797f91bb509824b03e33fbJim Miller                    if (fingerDown) {
3003060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "x", ringX, true);
3013060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "y", ringY, true);
3023060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
3033060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
3043060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
3053060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }  else {
306ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                        if (DBG) Log.v(TAG, "up detected, moving to STATE_UNLOCK_ATTEMPT");
3073060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mLockState = STATE_UNLOCK_ATTEMPT;
3083060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3093060421045d4d9e411797f91bb509824b03e33fbJim Miller                } else {
3108996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    // If waves have stopped, we need to kick them off again...
3118996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    if (!mWavesRunning) {
3128996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        mWavesRunning = true;
3138996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        mFinishWaves = false;
3148996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        // mWaveTimerDelay = WAVE_DELAY;
3158996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                        postDelayed(mAddWaveAction, mWaveTimerDelay);
3168996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                    }
3173060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "x", mouseX, true);
3183060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "y", mouseY, true);
3193060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
3203060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
3213060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
3223060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
3233060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3243060421045d4d9e411797f91bb509824b03e33fbJim Miller
3253060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_UNLOCK_ATTEMPT:
3263060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State UNLOCK_ATTEMPT");
3273060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (dragDistance > mSnapRadius) {
3283060421045d4d9e411797f91bb509824b03e33fbJim Miller                    for (int n = 0; n < mLightWaves.size(); n++) {
3293060421045d4d9e411797f91bb509824b03e33fbJim Miller                        DrawableHolder wave = mLightWaves.get(n);
3303060421045d4d9e411797f91bb509824b03e33fbJim Miller                        long delay = 1000L*(6 + n - mCurrentWave)/10L;
3310c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true);
3320c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "y", ringY, true);
3330c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "scaleX", 0.1f, true);
3340c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "scaleY", 0.1f, true);
3350c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                        wave.addAnimTo(FINAL_DURATION, delay, "alpha", 0.0f, true);
3363060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3373060421045d4d9e411797f91bb509824b03e33fbJim Miller                    for (int i = 0; i < mLightWaves.size(); i++) {
3383060421045d4d9e411797f91bb509824b03e33fbJim Miller                        mLightWaves.get(i).startAnimations(this);
3393060421045d4d9e411797f91bb509824b03e33fbJim Miller                    }
3403060421045d4d9e411797f91bb509824b03e33fbJim Miller
3410c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
3420c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
3430c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false);
3440c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false);
3450c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false);
3463060421045d4d9e411797f91bb509824b03e33fbJim Miller
3470c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3483060421045d4d9e411797f91bb509824b03e33fbJim Miller
3493060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("x");
3503060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("y");
3513060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("scaleX");
3523060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("scaleY");
3533060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mUnlockDefault.removeAnimationFor("alpha");
354c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setX(ringX);
355c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setY(ringY);
356c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setScaleX(0.1f);
357c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setScaleY(0.1f);
358c002fab06d5f6d3c83bb2b89c8ee9a14f6580af3Jim Miller                    mUnlockDefault.setAlpha(0.0f);
3593060421045d4d9e411797f91bb509824b03e33fbJim Miller
3600c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true);
3610c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true);
3620c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true);
3630c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true);
3640c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true);
3653060421045d4d9e411797f91bb509824b03e33fbJim Miller
3660c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
3670c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
3680c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3693060421045d4d9e411797f91bb509824b03e33fbJim Miller
3700c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
3710c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
3723060421045d4d9e411797f91bb509824b03e33fbJim Miller
3730c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
3740c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
3750c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
3763060421045d4d9e411797f91bb509824b03e33fbJim Miller
3773060421045d4d9e411797f91bb509824b03e33fbJim Miller                    removeCallbacks(mLockTimerActions);
3783060421045d4d9e411797f91bb509824b03e33fbJim Miller
3793060421045d4d9e411797f91bb509824b03e33fbJim Miller                    postDelayed(mLockTimerActions, RESET_TIMEOUT);
3803060421045d4d9e411797f91bb509824b03e33fbJim Miller
3813060421045d4d9e411797f91bb509824b03e33fbJim Miller                    dispatchTriggerEvent(OnTriggerListener.CENTER_HANDLE);
3823060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLockState = STATE_UNLOCK_SUCCESS;
3833060421045d4d9e411797f91bb509824b03e33fbJim Miller                } else {
3843060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mLockState = STATE_RESET_LOCK;
3853060421045d4d9e411797f91bb509824b03e33fbJim Miller                }
3863060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3873060421045d4d9e411797f91bb509824b03e33fbJim Miller
3883060421045d4d9e411797f91bb509824b03e33fbJim Miller            case STATE_UNLOCK_SUCCESS:
3893060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "State UNLOCK_SUCCESS");
3903060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mAddWaveAction);
3913060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3923060421045d4d9e411797f91bb509824b03e33fbJim Miller
3933060421045d4d9e411797f91bb509824b03e33fbJim Miller            default:
3943060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "Unknown state " + mLockState);
3953060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
3963060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
3973060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockDefault.startAnimations(this);
3983060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockHalo.startAnimations(this);
3993060421045d4d9e411797f91bb509824b03e33fbJim Miller        mUnlockRing.startAnimations(this);
4003060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
4013060421045d4d9e411797f91bb509824b03e33fbJim Miller
4023060421045d4d9e411797f91bb509824b03e33fbJim Miller    BitmapDrawable createDrawable(int resId) {
4033060421045d4d9e411797f91bb509824b03e33fbJim Miller        Resources res = getResources();
4043060421045d4d9e411797f91bb509824b03e33fbJim Miller        Bitmap bitmap = BitmapFactory.decodeResource(res, resId);
4053060421045d4d9e411797f91bb509824b03e33fbJim Miller        return new BitmapDrawable(res, bitmap);
4063060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
4073060421045d4d9e411797f91bb509824b03e33fbJim Miller
4083060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
4093060421045d4d9e411797f91bb509824b03e33fbJim Miller    protected void onDraw(Canvas canvas) {
4103060421045d4d9e411797f91bb509824b03e33fbJim Miller        waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
4113060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mDrawables.size(); ++i) {
4123060421045d4d9e411797f91bb509824b03e33fbJim Miller            mDrawables.get(i).draw(canvas);
4133060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4143060421045d4d9e411797f91bb509824b03e33fbJim Miller        for (int i = 0; i < mLightWaves.size(); ++i) {
4153060421045d4d9e411797f91bb509824b03e33fbJim Miller            mLightWaves.get(i).draw(canvas);
4163060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4173060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
4183060421045d4d9e411797f91bb509824b03e33fbJim Miller
4193060421045d4d9e411797f91bb509824b03e33fbJim Miller    private final Runnable mLockTimerActions = new Runnable() {
4203060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void run() {
4213060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (DBG) Log.v(TAG, "LockTimerActions");
4223060421045d4d9e411797f91bb509824b03e33fbJim Miller            // reset lock after inactivity
4233060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_ATTEMPTING) {
424607d320c9d18a57350bef72cc74017366ffd04ecJim Miller                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK");
4253060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_RESET_LOCK;
4263060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4273060421045d4d9e411797f91bb509824b03e33fbJim Miller            // for prototype, reset after successful unlock
4283060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_UNLOCK_SUCCESS) {
429607d320c9d18a57350bef72cc74017366ffd04ecJim Miller                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK after success");
4303060421045d4d9e411797f91bb509824b03e33fbJim Miller                mLockState = STATE_RESET_LOCK;
4313060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4323060421045d4d9e411797f91bb509824b03e33fbJim Miller            invalidate();
4333060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4343060421045d4d9e411797f91bb509824b03e33fbJim Miller    };
4353060421045d4d9e411797f91bb509824b03e33fbJim Miller
4363060421045d4d9e411797f91bb509824b03e33fbJim Miller    private final Runnable mAddWaveAction = new Runnable() {
4373060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void run() {
4383060421045d4d9e411797f91bb509824b03e33fbJim Miller            double distX = mMouseX - mLockCenterX;
4393060421045d4d9e411797f91bb509824b03e33fbJim Miller            double distY = mMouseY - mLockCenterY;
4403060421045d4d9e411797f91bb509824b03e33fbJim Miller            int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
4413060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mLockState == STATE_ATTEMPTING && dragDistance < mSnapRadius
4423262a51a91655659741b3b02071ccaed258fc01fJim Miller                    && mWaveTimerDelay >= WAVE_DELAY) {
4433060421045d4d9e411797f91bb509824b03e33fbJim Miller                mWaveTimerDelay = Math.min(WAVE_DURATION, mWaveTimerDelay + DELAY_INCREMENT);
4443060421045d4d9e411797f91bb509824b03e33fbJim Miller
4453060421045d4d9e411797f91bb509824b03e33fbJim Miller                DrawableHolder wave = mLightWaves.get(mCurrentWave);
4463060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setAlpha(0.0f);
4473060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setScaleX(0.2f);
4483060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setScaleY(0.2f);
4493060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setX(mMouseX);
4503060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.setY(mMouseY);
4513060421045d4d9e411797f91bb509824b03e33fbJim Miller
4523060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "x", mLockCenterX, true);
4533060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "y", mLockCenterY, true);
4543060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION*2/3, 0, "alpha", 1.0f, true);
4553060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "scaleX", 1.0f, true);
4563060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.addAnimTo(WAVE_DURATION, 0, "scaleY", 1.0f, true);
4573060421045d4d9e411797f91bb509824b03e33fbJim Miller
4580c91a8ee9321da4dee17f0aeffbc20b0c5bb0644Jim Miller                wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false);
4593060421045d4d9e411797f91bb509824b03e33fbJim Miller                wave.startAnimations(WaveView.this);
4603060421045d4d9e411797f91bb509824b03e33fbJim Miller
4613060421045d4d9e411797f91bb509824b03e33fbJim Miller                mCurrentWave = (mCurrentWave+1) % mWaveCount;
4623060421045d4d9e411797f91bb509824b03e33fbJim Miller                if (DBG) Log.v(TAG, "WaveTimerDelay: start new wave in " + mWaveTimerDelay);
4633060421045d4d9e411797f91bb509824b03e33fbJim Miller            } else {
4643060421045d4d9e411797f91bb509824b03e33fbJim Miller                mWaveTimerDelay += DELAY_INCREMENT2;
4653060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
4668996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            if (mFinishWaves) {
4678996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                // sentinel used to restart the waves after they've stopped
4688996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                mWavesRunning = false;
4698996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            } else {
4708996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller                postDelayed(mAddWaveAction, mWaveTimerDelay);
4718996cf071abf5e6a6458da258a1d59bcaafc3c2cJim Miller            }
4723060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
4733060421045d4d9e411797f91bb509824b03e33fbJim Miller    };
4743060421045d4d9e411797f91bb509824b03e33fbJim Miller
4753060421045d4d9e411797f91bb509824b03e33fbJim Miller    @Override
4766033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    public boolean onHoverEvent(MotionEvent event) {
4776033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
4786033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            final int action = event.getAction();
4796033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            switch (action) {
4806033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_ENTER:
4816033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_DOWN);
4826033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4836033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_MOVE:
4846033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_MOVE);
4856033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4866033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                case MotionEvent.ACTION_HOVER_EXIT:
4876033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    event.setAction(MotionEvent.ACTION_UP);
4886033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    break;
4896033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            }
4906033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            onTouchEvent(event);
4916033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            event.setAction(action);
4926033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
4936033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        return super.onHoverEvent(event);
4946033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
4956033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
4966033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    @Override
4973060421045d4d9e411797f91bb509824b03e33fbJim Miller    public boolean onTouchEvent(MotionEvent event) {
4983060421045d4d9e411797f91bb509824b03e33fbJim Miller        final int action = event.getAction();
4993060421045d4d9e411797f91bb509824b03e33fbJim Miller        mMouseX = event.getX();
5003060421045d4d9e411797f91bb509824b03e33fbJim Miller        mMouseY = event.getY();
5013060421045d4d9e411797f91bb509824b03e33fbJim Miller        boolean handled = false;
5023060421045d4d9e411797f91bb509824b03e33fbJim Miller        switch (action) {
5033060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_DOWN:
5043060421045d4d9e411797f91bb509824b03e33fbJim Miller                removeCallbacks(mLockTimerActions);
5053060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = true;
5066033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                tryTransitionToStartAttemptState(event);
5073060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5083060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5093060421045d4d9e411797f91bb509824b03e33fbJim Miller
5103060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_MOVE:
5116033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                tryTransitionToStartAttemptState(event);
5123060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5133060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5143060421045d4d9e411797f91bb509824b03e33fbJim Miller
5153060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_UP:
516ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                if (DBG) Log.v(TAG, "ACTION_UP");
5173060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = false;
5183060421045d4d9e411797f91bb509824b03e33fbJim Miller                postDelayed(mLockTimerActions, RESET_TIMEOUT);
5193060421045d4d9e411797f91bb509824b03e33fbJim Miller                setGrabbedState(OnTriggerListener.NO_HANDLE);
520ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // Normally the state machine is driven by user interaction causing redraws.
521ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // However, when there's no more user interaction and no running animations,
522ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // the state machine stops advancing because onDraw() never gets called.
523ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // The following ensures we advance to the next state in this case,
524ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                // either STATE_UNLOCK_ATTEMPT or STATE_RESET_LOCK.
525ec6ac82a295b80a39f12ff7951ec254ba45809fdJim Miller                waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
5263060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5273060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5283060421045d4d9e411797f91bb509824b03e33fbJim Miller
5293060421045d4d9e411797f91bb509824b03e33fbJim Miller            case MotionEvent.ACTION_CANCEL:
5303060421045d4d9e411797f91bb509824b03e33fbJim Miller                mFingerDown = false;
5313060421045d4d9e411797f91bb509824b03e33fbJim Miller                handled = true;
5323060421045d4d9e411797f91bb509824b03e33fbJim Miller                break;
5333060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
5343060421045d4d9e411797f91bb509824b03e33fbJim Miller        invalidate();
5353060421045d4d9e411797f91bb509824b03e33fbJim Miller        return handled ? true : super.onTouchEvent(event);
5363060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
5373060421045d4d9e411797f91bb509824b03e33fbJim Miller
5383060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
5396033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * Tries to transition to start attempt state.
5406033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     *
5416033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * @param event A motion event.
5426033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5436033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private void tryTransitionToStartAttemptState(MotionEvent event) {
5446033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        final float dx = event.getX() - mUnlockHalo.getX();
5456033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        final float dy = event.getY() - mUnlockHalo.getY();
5466033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        float dist = (float) Math.hypot(dx, dy);
5476033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (dist <= getScaledGrabHandleRadius()) {
5486033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            setGrabbedState(OnTriggerListener.CENTER_HANDLE);
5496033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            if (mLockState == STATE_READY) {
5506033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                mLockState = STATE_START_ATTEMPT;
5516033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5526033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                    announceUnlockHandle();
5536033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov                }
5546033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            }
5556033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
5566033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5576033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5586033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5596033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * @return The radius in which the handle is grabbed scaled based on
5606033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     *     whether accessibility is enabled.
5616033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5626033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private float getScaledGrabHandleRadius() {
5636033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
5646033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mUnlockHalo.getWidth();
5656033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        } else {
5666033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED * mUnlockHalo.getWidth();
5676033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        }
5686033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5696033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5706033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5716033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     * Announces the unlock handle if accessibility is enabled.
5726033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov     */
5736033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    private void announceUnlockHandle() {
5746033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        setContentDescription(mContext.getString(R.string.description_target_unlock_tablet));
5756033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
5766033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov        setContentDescription(null);
5776033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    }
5786033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov
5796033c0817427386cd3e95a992d1f34dad4188f96Svetoslav Ganov    /**
5803060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Triggers haptic feedback.
5813060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
5823060421045d4d9e411797f91bb509824b03e33fbJim Miller    private synchronized void vibrate(long duration) {
583723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey        final boolean hapticEnabled = Settings.System.getIntForUser(
584723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1,
585723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                UserHandle.USER_CURRENT) != 0;
586723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey        if (hapticEnabled) {
587723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey            if (mVibrator == null) {
588723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                mVibrator = (android.os.Vibrator) getContext()
589723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                        .getSystemService(Context.VIBRATOR_SERVICE);
590723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey            }
5917b41467704f941b11af6aace3e40993afc7f6c6fJohn Spurlock            mVibrator.vibrate(duration, VIBRATION_ATTRIBUTES);
5923060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
5933060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
5943060421045d4d9e411797f91bb509824b03e33fbJim Miller
5953060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
5963060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Registers a callback to be invoked when the user triggers an event.
5973060421045d4d9e411797f91bb509824b03e33fbJim Miller     *
5983060421045d4d9e411797f91bb509824b03e33fbJim Miller     * @param listener the OnDialTriggerListener to attach to this view
5993060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
6003060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void setOnTriggerListener(OnTriggerListener listener) {
6013060421045d4d9e411797f91bb509824b03e33fbJim Miller        mOnTriggerListener = listener;
6023060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6033060421045d4d9e411797f91bb509824b03e33fbJim Miller
6043060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
6053060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Dispatches a trigger event to listener. Ignored if a listener is not set.
6063060421045d4d9e411797f91bb509824b03e33fbJim Miller     * @param whichHandle the handle that triggered the event.
6073060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
6083060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void dispatchTriggerEvent(int whichHandle) {
6093060421045d4d9e411797f91bb509824b03e33fbJim Miller        vibrate(VIBRATE_LONG);
6103060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (mOnTriggerListener != null) {
6113060421045d4d9e411797f91bb509824b03e33fbJim Miller            mOnTriggerListener.onTrigger(this, whichHandle);
6123060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
6133060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6143060421045d4d9e411797f91bb509824b03e33fbJim Miller
6153060421045d4d9e411797f91bb509824b03e33fbJim Miller    /**
6163060421045d4d9e411797f91bb509824b03e33fbJim Miller     * Sets the current grabbed state, and dispatches a grabbed state change
6173060421045d4d9e411797f91bb509824b03e33fbJim Miller     * event to our listener.
6183060421045d4d9e411797f91bb509824b03e33fbJim Miller     */
6193060421045d4d9e411797f91bb509824b03e33fbJim Miller    private void setGrabbedState(int newState) {
6203060421045d4d9e411797f91bb509824b03e33fbJim Miller        if (newState != mGrabbedState) {
6213060421045d4d9e411797f91bb509824b03e33fbJim Miller            mGrabbedState = newState;
6223060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (mOnTriggerListener != null) {
6233060421045d4d9e411797f91bb509824b03e33fbJim Miller                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
6243060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
6253060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
6263060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6273060421045d4d9e411797f91bb509824b03e33fbJim Miller
6283060421045d4d9e411797f91bb509824b03e33fbJim Miller    public interface OnTriggerListener {
6293060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6303060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Sent when the user releases the handle.
6313060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6323060421045d4d9e411797f91bb509824b03e33fbJim Miller        public static final int NO_HANDLE = 0;
6333060421045d4d9e411797f91bb509824b03e33fbJim Miller
6343060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6353060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Sent when the user grabs the center handle
6363060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6373060421045d4d9e411797f91bb509824b03e33fbJim Miller        public static final int CENTER_HANDLE = 10;
6383060421045d4d9e411797f91bb509824b03e33fbJim Miller
6393060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6403060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Called when the user drags the center ring beyond a threshold.
6413060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6423060421045d4d9e411797f91bb509824b03e33fbJim Miller        void onTrigger(View v, int whichHandle);
6433060421045d4d9e411797f91bb509824b03e33fbJim Miller
6443060421045d4d9e411797f91bb509824b03e33fbJim Miller        /**
6453060421045d4d9e411797f91bb509824b03e33fbJim Miller         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
6463060421045d4d9e411797f91bb509824b03e33fbJim Miller         * one of the handles.)
6473060421045d4d9e411797f91bb509824b03e33fbJim Miller         *
6483060421045d4d9e411797f91bb509824b03e33fbJim Miller         * @param v the view that was triggered
6493060421045d4d9e411797f91bb509824b03e33fbJim Miller         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #CENTER_HANDLE},
6503060421045d4d9e411797f91bb509824b03e33fbJim Miller         */
6513060421045d4d9e411797f91bb509824b03e33fbJim Miller        void onGrabbedStateChange(View v, int grabbedState);
6523060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6533060421045d4d9e411797f91bb509824b03e33fbJim Miller
6543060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void onAnimationUpdate(ValueAnimator animation) {
6553060421045d4d9e411797f91bb509824b03e33fbJim Miller        invalidate();
6563060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6573060421045d4d9e411797f91bb509824b03e33fbJim Miller
6583060421045d4d9e411797f91bb509824b03e33fbJim Miller    public void reset() {
659607d320c9d18a57350bef72cc74017366ffd04ecJim Miller        if (DBG) Log.v(TAG, "reset() : resets state to STATE_RESET_LOCK");
6603060421045d4d9e411797f91bb509824b03e33fbJim Miller        mLockState = STATE_RESET_LOCK;
661607d320c9d18a57350bef72cc74017366ffd04ecJim Miller        invalidate();
6623060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
6633060421045d4d9e411797f91bb509824b03e33fbJim Miller}
664