am 955a0169: Fix 6613962: Update keyguard to use new GlowPadView UX design.

* commit '955a016922ea49f154d190b054a202559b41a4d3':
  Fix 6613962: Update keyguard to use new GlowPadView UX design.
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
new file mode 100644
index 0000000..5096be6
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -0,0 +1,1226 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+
+/**
+ * A re-usable widget containing a center, outer ring and wave animation.
+ */
+public class GlowPadView extends View {
+    private static final String TAG = "GlowPadView";
+    private static final boolean DEBUG = false;
+
+    // Wave state machine
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_START = 1;
+    private static final int STATE_FIRST_TOUCH = 2;
+    private static final int STATE_TRACKING = 3;
+    private static final int STATE_SNAP = 4;
+    private static final int STATE_FINISH = 5;
+
+    // Animation properties.
+    private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it
+
+    public interface OnTriggerListener {
+        int NO_HANDLE = 0;
+        int CENTER_HANDLE = 1;
+        public void onGrabbed(View v, int handle);
+        public void onReleased(View v, int handle);
+        public void onTrigger(View v, int target);
+        public void onGrabbedStateChange(View v, int handle);
+        public void onFinishFinalAnimation();
+    }
+
+    // Tuneable parameters for animation
+    private static final int WAVE_ANIMATION_DURATION = 1200;
+    private static final int RETURN_TO_HOME_DELAY = 1200;
+    private static final int RETURN_TO_HOME_DURATION = 200;
+    private static final int HIDE_ANIMATION_DELAY = 200;
+    private static final int HIDE_ANIMATION_DURATION = 200;
+    private static final int SHOW_ANIMATION_DURATION = 200;
+    private static final int SHOW_ANIMATION_DELAY = 50;
+    private static final int INITIAL_SHOW_HANDLE_DURATION = 200;
+    private static final int REVEAL_GLOW_DELAY = 0;
+    private static final int REVEAL_GLOW_DURATION = 0;
+
+    private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
+    private static final float TARGET_SCALE_EXPANDED = 1.0f;
+    private static final float TARGET_SCALE_COLLAPSED = 0.8f;
+    private static final float RING_SCALE_EXPANDED = 1.0f;
+    private static final float RING_SCALE_COLLAPSED = 0.5f;
+
+    private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
+    private AnimationBundle mWaveAnimations = new AnimationBundle();
+    private AnimationBundle mTargetAnimations = new AnimationBundle();
+    private AnimationBundle mGlowAnimations = new AnimationBundle();
+    private ArrayList<String> mTargetDescriptions;
+    private ArrayList<String> mDirectionDescriptions;
+    private OnTriggerListener mOnTriggerListener;
+    private TargetDrawable mHandleDrawable;
+    private TargetDrawable mOuterRing;
+    private Vibrator mVibrator;
+
+    private int mFeedbackCount = 3;
+    private int mVibrationDuration = 0;
+    private int mGrabbedState;
+    private int mActiveTarget = -1;
+    private float mGlowRadius;
+    private float mWaveCenterX;
+    private float mWaveCenterY;
+    private int mMaxTargetHeight;
+    private int mMaxTargetWidth;
+
+    private float mOuterRadius = 0.0f;
+    private float mHitRadius = 0.0f;
+    private float mSnapMargin = 0.0f;
+    private boolean mDragging;
+    private int mNewTargetResources;
+
+    private class AnimationBundle extends ArrayList<Tweener> {
+        private static final long serialVersionUID = 0xA84D78726F127468L;
+        private boolean mSuspended;
+
+        public void start() {
+            if (mSuspended) return; // ignore attempts to start animations
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.start();
+            }
+        }
+
+        public void cancel() {
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.cancel();
+            }
+            clear();
+        }
+
+        public void stop() {
+            final int count = size();
+            for (int i = 0; i < count; i++) {
+                Tweener anim = get(i);
+                anim.animator.end();
+            }
+            clear();
+        }
+
+        public void setSuspended(boolean suspend) {
+            mSuspended = suspend;
+        }
+    };
+
+    private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
+        public void onAnimationEnd(Animator animator) {
+            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+            dispatchOnFinishFinalAnimation();
+        }
+    };
+
+    private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() {
+        public void onAnimationEnd(Animator animator) {
+            ping();
+            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+            dispatchOnFinishFinalAnimation();
+        }
+    };
+
+    private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
+        public void onAnimationUpdate(ValueAnimator animation) {
+            invalidate();
+        }
+    };
+
+    private boolean mAnimatingTargets;
+    private AnimatorListener mTargetUpdateListener = new AnimatorListenerAdapter() {
+        public void onAnimationEnd(Animator animator) {
+            if (mNewTargetResources != 0) {
+                internalSetTargetResources(mNewTargetResources);
+                mNewTargetResources = 0;
+                hideTargets(false, false);
+            }
+            mAnimatingTargets = false;
+        }
+    };
+    private int mTargetResourceId;
+    private int mTargetDescriptionsResourceId;
+    private int mDirectionDescriptionsResourceId;
+    private boolean mAlwaysTrackFinger;
+    private int mHorizontalInset;
+    private int mVerticalInset;
+    private int mGravity = Gravity.TOP;
+    private boolean mInitialLayout = true;
+    private Tweener mBackgroundAnimator;
+    private PointCloud mPointCloud;
+    private float mInnerRadius;
+
+    public GlowPadView(Context context) {
+        this(context, null);
+    }
+
+    public GlowPadView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        Resources res = context.getResources();
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GlowPadView);
+        mInnerRadius = a.getDimension(R.styleable.GlowPadView_innerRadius, mInnerRadius);
+        mOuterRadius = a.getDimension(R.styleable.GlowPadView_outerRadius, mOuterRadius);
+        mHitRadius = a.getDimension(R.styleable.GlowPadView_hitRadius, mHitRadius);
+        mSnapMargin = a.getDimension(R.styleable.GlowPadView_snapMargin, mSnapMargin);
+        mVibrationDuration = a.getInt(R.styleable.GlowPadView_vibrationDuration,
+                mVibrationDuration);
+        mFeedbackCount = a.getInt(R.styleable.GlowPadView_feedbackCount,
+                mFeedbackCount);
+        mHandleDrawable = new TargetDrawable(res,
+                a.peekValue(R.styleable.GlowPadView_handleDrawable).resourceId);
+        mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+        mOuterRing = new TargetDrawable(res,
+                getResourceId(a, R.styleable.GlowPadView_outerRingDrawable));
+
+        mAlwaysTrackFinger = a.getBoolean(R.styleable.GlowPadView_alwaysTrackFinger, false);
+
+        int pointId = getResourceId(a, R.styleable.GlowPadView_pointDrawable);
+        Drawable pointDrawable = pointId != 0 ? res.getDrawable(pointId) : null;
+        mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
+
+        TypedValue outValue = new TypedValue();
+
+        // Read array of target drawables
+        if (a.getValue(R.styleable.GlowPadView_targetDrawables, outValue)) {
+            internalSetTargetResources(outValue.resourceId);
+        }
+        if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
+            throw new IllegalStateException("Must specify at least one target drawable");
+        }
+
+        // Read array of target descriptions
+        if (a.getValue(R.styleable.GlowPadView_targetDescriptions, outValue)) {
+            final int resourceId = outValue.resourceId;
+            if (resourceId == 0) {
+                throw new IllegalStateException("Must specify target descriptions");
+            }
+            setTargetDescriptionsResourceId(resourceId);
+        }
+
+        // Read array of direction descriptions
+        if (a.getValue(R.styleable.GlowPadView_directionDescriptions, outValue)) {
+            final int resourceId = outValue.resourceId;
+            if (resourceId == 0) {
+                throw new IllegalStateException("Must specify direction descriptions");
+            }
+            setDirectionDescriptionsResourceId(resourceId);
+        }
+
+        a.recycle();
+
+        // Use gravity attribute from LinearLayout
+        a = context.obtainStyledAttributes(attrs, android.R.styleable.LinearLayout);
+        mGravity = a.getInt(android.R.styleable.LinearLayout_gravity, Gravity.TOP);
+        a.recycle();
+
+        setVibrateEnabled(mVibrationDuration > 0);
+
+        assignDefaultsIfNeeded();
+
+        mPointCloud = new PointCloud(pointDrawable);
+        mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
+        mPointCloud.glowManager.setRadius(mGlowRadius);
+    }
+
+    private int getResourceId(TypedArray a, int id) {
+        TypedValue tv = a.peekValue(id);
+        return tv == null ? 0 : tv.resourceId;
+    }
+
+    private void dump() {
+        Log.v(TAG, "Outer Radius = " + mOuterRadius);
+        Log.v(TAG, "HitRadius = " + mHitRadius);
+        Log.v(TAG, "SnapMargin = " + mSnapMargin);
+        Log.v(TAG, "FeedbackCount = " + mFeedbackCount);
+        Log.v(TAG, "VibrationDuration = " + mVibrationDuration);
+        Log.v(TAG, "GlowRadius = " + mGlowRadius);
+        Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
+        Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
+    }
+
+    public void suspendAnimations() {
+        mWaveAnimations.setSuspended(true);
+        mTargetAnimations.setSuspended(true);
+        mGlowAnimations.setSuspended(true);
+    }
+
+    public void resumeAnimations() {
+        mWaveAnimations.setSuspended(false);
+        mTargetAnimations.setSuspended(false);
+        mGlowAnimations.setSuspended(false);
+        mWaveAnimations.start();
+        mTargetAnimations.start();
+        mGlowAnimations.start();
+    }
+
+    @Override
+    protected int getSuggestedMinimumWidth() {
+        // View should be large enough to contain the background + handle and
+        // target drawable on either edge.
+        return (int) (Math.max(mOuterRing.getWidth(), 2 * mOuterRadius) + mMaxTargetWidth);
+    }
+
+    @Override
+    protected int getSuggestedMinimumHeight() {
+        // View should be large enough to contain the unlock ring + target and
+        // target drawable on either edge
+        return (int) (Math.max(mOuterRing.getHeight(), 2 * mOuterRadius) + mMaxTargetHeight);
+    }
+
+    private int resolveMeasured(int measureSpec, int desired)
+    {
+        int result = 0;
+        int specSize = MeasureSpec.getSize(measureSpec);
+        switch (MeasureSpec.getMode(measureSpec)) {
+            case MeasureSpec.UNSPECIFIED:
+                result = desired;
+                break;
+            case MeasureSpec.AT_MOST:
+                result = Math.min(specSize, desired);
+                break;
+            case MeasureSpec.EXACTLY:
+            default:
+                result = specSize;
+        }
+        return result;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int minimumWidth = getSuggestedMinimumWidth();
+        final int minimumHeight = getSuggestedMinimumHeight();
+        int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
+        int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
+        computeInsets((computedWidth - minimumWidth), (computedHeight - minimumHeight));
+        setMeasuredDimension(computedWidth, computedHeight);
+    }
+
+    private void switchToState(int state, float x, float y) {
+        switch (state) {
+            case STATE_IDLE:
+                deactivateTargets();
+                hideGlow(0, 0, 0.0f, null);
+                startBackgroundAnimation(0, 0.0f);
+                mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+                mHandleDrawable.setAlpha(1.0f);
+                break;
+
+            case STATE_START:
+                startBackgroundAnimation(0, 0.0f);
+                break;
+
+            case STATE_FIRST_TOUCH:
+                mHandleDrawable.setAlpha(0.0f);
+                deactivateTargets();
+                showTargets(true);
+                startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f);
+                setGrabbedState(OnTriggerListener.CENTER_HANDLE);
+                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                    announceTargets();
+                }
+                break;
+
+            case STATE_TRACKING:
+                mHandleDrawable.setAlpha(0.0f);
+                showGlow(REVEAL_GLOW_DURATION , REVEAL_GLOW_DELAY, 1.0f, null);
+                break;
+
+            case STATE_SNAP:
+                // TODO: Add transition states (see list_selector_background_transition.xml)
+                mHandleDrawable.setAlpha(0.0f);
+                showGlow(REVEAL_GLOW_DURATION , REVEAL_GLOW_DELAY, 0.0f, null);
+                break;
+
+            case STATE_FINISH:
+                doFinish();
+                break;
+        }
+    }
+
+    private void showGlow(int duration, int delay, float finalAlpha,
+            AnimatorListener finishListener) {
+        mGlowAnimations.cancel();
+        mGlowAnimations.add(Tweener.to(mPointCloud.glowManager, duration,
+                "ease", Ease.Cubic.easeIn,
+                "delay", delay,
+                "alpha", finalAlpha,
+                "onUpdate", mUpdateListener,
+                "onComplete", finishListener));
+        mGlowAnimations.start();
+    }
+
+    private void hideGlow(int duration, int delay, float finalAlpha,
+            AnimatorListener finishListener) {
+        mGlowAnimations.cancel();
+        mGlowAnimations.add(Tweener.to(mPointCloud.glowManager, duration,
+                "ease", Ease.Quart.easeOut,
+                "delay", delay,
+                "alpha", finalAlpha,
+                "x", 0.0f,
+                "y", 0.0f,
+                "onUpdate", mUpdateListener,
+                "onComplete", finishListener));
+        mGlowAnimations.start();
+    }
+
+    private void deactivateTargets() {
+        final int count = mTargetDrawables.size();
+        for (int i = 0; i < count; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
+            target.setState(TargetDrawable.STATE_INACTIVE);
+        }
+        mActiveTarget = -1;
+    }
+
+    /**
+     * Dispatches a trigger event to listener. Ignored if a listener is not set.
+     * @param whichTarget the target that was triggered.
+     */
+    private void dispatchTriggerEvent(int whichTarget) {
+        vibrate();
+        if (mOnTriggerListener != null) {
+            mOnTriggerListener.onTrigger(this, whichTarget);
+        }
+    }
+
+    private void dispatchOnFinishFinalAnimation() {
+        if (mOnTriggerListener != null) {
+            mOnTriggerListener.onFinishFinalAnimation();
+        }
+    }
+
+    private void doFinish() {
+        final int activeTarget = mActiveTarget;
+        final boolean targetHit =  activeTarget != -1;
+
+        if (targetHit) {
+            if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
+
+            highlightSelected(activeTarget);
+
+            // Inform listener of any active targets.  Typically only one will be active.
+            hideGlow(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener);
+            dispatchTriggerEvent(activeTarget);
+            if (!mAlwaysTrackFinger) {
+                // Force ring and targets to finish animation to final expanded state
+                mTargetAnimations.stop();
+            }
+        } else {
+            // Animate handle back to the center based on current state.
+            hideGlow(HIDE_ANIMATION_DURATION, 0, 0.0f, mResetListenerWithPing);
+            hideTargets(true, false);
+        }
+
+        setGrabbedState(OnTriggerListener.NO_HANDLE);
+    }
+
+    private void highlightSelected(int activeTarget) {
+        // Highlight the given target and fade others
+        mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
+        hideUnselected(activeTarget);
+    }
+
+    private void hideUnselected(int active) {
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            if (i != active) {
+                mTargetDrawables.get(i).setAlpha(0.0f);
+            }
+        }
+    }
+
+    private void hideTargets(boolean animate, boolean expanded) {
+        mTargetAnimations.cancel();
+        // Note: these animations should complete at the same time so that we can swap out
+        // the target assets asynchronously from the setTargetResources() call.
+        mAnimatingTargets = animate;
+        final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
+        final int delay = animate ? HIDE_ANIMATION_DELAY : 0;
+
+        final float targetScale = expanded ? TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED;
+        final int length = mTargetDrawables.size();
+        final TimeInterpolator interpolator = Ease.Cubic.easeOut;
+        for (int i = 0; i < length; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
+            target.setState(TargetDrawable.STATE_INACTIVE);
+            mTargetAnimations.add(Tweener.to(target, duration,
+                    "ease", interpolator,
+                    "alpha", 0.0f,
+                    "scaleX", targetScale,
+                    "scaleY", targetScale,
+                    "delay", delay,
+                    "onUpdate", mUpdateListener));
+        }
+
+        final float ringScaleTarget = expanded ? RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED;
+        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
+                "ease", interpolator,
+                "alpha", 0.0f,
+                "scaleX", ringScaleTarget,
+                "scaleY", ringScaleTarget,
+                "delay", delay,
+                "onUpdate", mUpdateListener,
+                "onComplete", mTargetUpdateListener));
+
+        mTargetAnimations.start();
+    }
+
+    private void showTargets(boolean animate) {
+        mTargetAnimations.stop();
+        mAnimatingTargets = animate;
+        final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
+        final int duration = animate ? SHOW_ANIMATION_DURATION : 0;
+        final int length = mTargetDrawables.size();
+        for (int i = 0; i < length; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
+            target.setState(TargetDrawable.STATE_INACTIVE);
+            mTargetAnimations.add(Tweener.to(target, duration,
+                    "ease", Ease.Cubic.easeOut,
+                    "alpha", 1.0f,
+                    "scaleX", 1.0f,
+                    "scaleY", 1.0f,
+                    "delay", delay,
+                    "onUpdate", mUpdateListener));
+        }
+        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
+                "ease", Ease.Cubic.easeOut,
+                "alpha", 1.0f,
+                "scaleX", 1.0f,
+                "scaleY", 1.0f,
+                "delay", delay,
+                "onUpdate", mUpdateListener,
+                "onComplete", mTargetUpdateListener));
+
+        mTargetAnimations.start();
+    }
+
+    private void vibrate() {
+        if (mVibrator != null) {
+            mVibrator.vibrate(mVibrationDuration);
+        }
+    }
+
+    private ArrayList<TargetDrawable> loadDrawableArray(int resourceId) {
+        Resources res = getContext().getResources();
+        TypedArray array = res.obtainTypedArray(resourceId);
+        final int count = array.length();
+        ArrayList<TargetDrawable> drawables = new ArrayList<TargetDrawable>(count);
+        for (int i = 0; i < count; i++) {
+            TypedValue value = array.peekValue(i);
+            TargetDrawable target = new TargetDrawable(res, value != null ? value.resourceId : 0);
+            drawables.add(target);
+        }
+        array.recycle();
+        return drawables;
+    }
+
+    private void internalSetTargetResources(int resourceId) {
+        final ArrayList<TargetDrawable> targets = loadDrawableArray(resourceId);
+        mTargetDrawables = targets;
+        mTargetResourceId = resourceId;
+
+        int maxWidth = mHandleDrawable.getWidth();
+        int maxHeight = mHandleDrawable.getHeight();
+        final int count = targets.size();
+        for (int i = 0; i < count; i++) {
+            TargetDrawable target = targets.get(i);
+            maxWidth = Math.max(maxWidth, target.getWidth());
+            maxHeight = Math.max(maxHeight, target.getHeight());
+        }
+        if (mMaxTargetWidth != maxWidth || mMaxTargetHeight != maxHeight) {
+            mMaxTargetWidth = maxWidth;
+            mMaxTargetHeight = maxHeight;
+            requestLayout(); // required to resize layout and call updateTargetPositions()
+        } else {
+            updateTargetPositions(mWaveCenterX, mWaveCenterY);
+            updatePointCloudPosition(mWaveCenterX, mWaveCenterY);
+        }
+    }
+
+    /**
+     * Loads an array of drawables from the given resourceId.
+     *
+     * @param resourceId
+     */
+    public void setTargetResources(int resourceId) {
+        if (mAnimatingTargets) {
+            // postpone this change until we return to the initial state
+            mNewTargetResources = resourceId;
+        } else {
+            internalSetTargetResources(resourceId);
+        }
+    }
+
+    public int getTargetResourceId() {
+        return mTargetResourceId;
+    }
+
+    /**
+     * Sets the resource id specifying the target descriptions for accessibility.
+     *
+     * @param resourceId The resource id.
+     */
+    public void setTargetDescriptionsResourceId(int resourceId) {
+        mTargetDescriptionsResourceId = resourceId;
+        if (mTargetDescriptions != null) {
+            mTargetDescriptions.clear();
+        }
+    }
+
+    /**
+     * Gets the resource id specifying the target descriptions for accessibility.
+     *
+     * @return The resource id.
+     */
+    public int getTargetDescriptionsResourceId() {
+        return mTargetDescriptionsResourceId;
+    }
+
+    /**
+     * Sets the resource id specifying the target direction descriptions for accessibility.
+     *
+     * @param resourceId The resource id.
+     */
+    public void setDirectionDescriptionsResourceId(int resourceId) {
+        mDirectionDescriptionsResourceId = resourceId;
+        if (mDirectionDescriptions != null) {
+            mDirectionDescriptions.clear();
+        }
+    }
+
+    /**
+     * Gets the resource id specifying the target direction descriptions.
+     *
+     * @return The resource id.
+     */
+    public int getDirectionDescriptionsResourceId() {
+        return mDirectionDescriptionsResourceId;
+    }
+
+    /**
+     * Enable or disable vibrate on touch.
+     *
+     * @param enabled
+     */
+    public void setVibrateEnabled(boolean enabled) {
+        if (enabled && mVibrator == null) {
+            mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        } else {
+            mVibrator = null;
+        }
+    }
+
+    /**
+     * Starts wave animation.
+     *
+     */
+    public void ping() {
+        if (mFeedbackCount > 0) {
+            startWaveAnimation();
+        }
+    }
+
+    private void stopAndHideWaveAnimation() {
+        mWaveAnimations.cancel();
+        mPointCloud.waveManager.setAlpha(0.0f);
+    }
+
+    private void startWaveAnimation() {
+        mWaveAnimations.cancel();
+        mPointCloud.waveManager.setAlpha(1.0f);
+        mPointCloud.waveManager.setRadius(mHandleDrawable.getWidth()/2.0f);
+        mWaveAnimations.add(Tweener.to(mPointCloud.waveManager, WAVE_ANIMATION_DURATION,
+                "ease", Ease.Linear.easeNone,
+                "delay", 0,
+                "radius", 2.0f * mOuterRadius,
+                "onUpdate", mUpdateListener,
+                "onComplete",
+                new AnimatorListenerAdapter() {
+                    public void onAnimationEnd(Animator animator) {
+                        mPointCloud.waveManager.setRadius(0.0f);
+                        mPointCloud.waveManager.setAlpha(0.0f);
+                    }
+                }));
+        mWaveAnimations.start();
+    }
+
+    /**
+     * Resets the widget to default state and cancels all animation. If animate is 'true', will
+     * animate objects into place. Otherwise, objects will snap back to place.
+     *
+     * @param animate
+     */
+    public void reset(boolean animate) {
+        mGlowAnimations.stop();
+        mTargetAnimations.stop();
+        startBackgroundAnimation(0, 0.0f);
+        stopAndHideWaveAnimation();
+        hideTargets(animate, false);
+        hideGlow(0, 0, 1.0f, null);
+        Tweener.reset();
+    }
+
+    private void startBackgroundAnimation(int duration, float alpha) {
+        final Drawable background = getBackground();
+        if (mAlwaysTrackFinger && background != null) {
+            if (mBackgroundAnimator != null) {
+                mBackgroundAnimator.animator.cancel();
+            }
+            mBackgroundAnimator = Tweener.to(background, duration,
+                    "ease", Ease.Cubic.easeIn,
+                    "alpha", (int)(255.0f * alpha),
+                    "delay", SHOW_ANIMATION_DELAY);
+            mBackgroundAnimator.animator.start();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int action = event.getAction();
+        boolean handled = false;
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                if (DEBUG) Log.v(TAG, "*** DOWN ***");
+                handleDown(event);
+                handleMove(event);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (DEBUG) Log.v(TAG, "*** MOVE ***");
+                handleMove(event);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_UP:
+                if (DEBUG) Log.v(TAG, "*** UP ***");
+                handleMove(event);
+                handleUp(event);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                if (DEBUG) Log.v(TAG, "*** CANCEL ***");
+                handleMove(event);
+                handleCancel(event);
+                handled = true;
+                break;
+        }
+        invalidate();
+        return handled ? true : super.onTouchEvent(event);
+    }
+
+    private void updateGlowPosition(float x, float y) {
+        mPointCloud.glowManager.setX(x);
+        mPointCloud.glowManager.setY(y);
+    }
+
+    private void handleDown(MotionEvent event) {
+        float eventX = event.getX();
+        float eventY = event.getY();
+        switchToState(STATE_START, eventX, eventY);
+        if (!trySwitchToFirstTouchState(eventX, eventY)) {
+            mDragging = false;
+        } else {
+            updateGlowPosition(eventX, eventY);
+        }
+    }
+
+    private void handleUp(MotionEvent event) {
+        if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
+        switchToState(STATE_FINISH, event.getX(), event.getY());
+    }
+
+    private void handleCancel(MotionEvent event) {
+        if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
+
+        // We should drop the active target here but it interferes with
+        // moving off the screen in the direction of the navigation bar. At some point we may
+        // want to revisit how we handle this. For now we'll allow a canceled event to
+        // activate the current target.
+
+        // mActiveTarget = -1; // Drop the active target if canceled.
+
+        switchToState(STATE_FINISH, event.getX(), event.getY());
+    }
+
+    private void handleMove(MotionEvent event) {
+        int activeTarget = -1;
+        final int historySize = event.getHistorySize();
+        ArrayList<TargetDrawable> targets = mTargetDrawables;
+        int ntargets = targets.size();
+        final boolean singleTarget = ntargets == 1;
+        float x = 0.0f;
+        float y = 0.0f;
+        for (int k = 0; k < historySize + 1; k++) {
+            float eventX = k < historySize ? event.getHistoricalX(k) : event.getX();
+            float eventY = k < historySize ? event.getHistoricalY(k) : event.getY();
+            // tx and ty are relative to wave center
+            float tx = eventX - mWaveCenterX;
+            float ty = eventY - mWaveCenterY;
+            float touchRadius = (float) Math.sqrt(dist2(tx, ty));
+            final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
+            float limitX = tx * scale;
+            float limitY = ty * scale;
+
+            if (!mDragging) {
+                trySwitchToFirstTouchState(eventX, eventY);
+            }
+
+            if (mDragging) {
+                if (singleTarget) {
+                    // Snap to outer ring if there's only one target
+                    float snapRadius = mOuterRadius - mSnapMargin;
+                    if (touchRadius > snapRadius) {
+                        activeTarget = 0;
+                    }
+                } else {
+                    // For more than one target, snap to the closest one less than hitRadius away.
+                    float best = Float.MAX_VALUE;
+                    final float hitRadius2 = mHitRadius * mHitRadius;
+                    // Find first target in range
+                    for (int i = 0; i < ntargets; i++) {
+                        TargetDrawable target = targets.get(i);
+                        float dx = limitX - target.getX();
+                        float dy = limitY - target.getY();
+                        float dist2 = dx*dx + dy*dy;
+                        if (target.isEnabled() && dist2 < hitRadius2 && dist2 < best) {
+                            activeTarget = i;
+                            best = dist2;
+                        }
+                    }
+                }
+            }
+            x = limitX;
+            y = limitY;
+        }
+
+        if (!mDragging) {
+            return;
+        }
+
+        if (activeTarget != -1) {
+            switchToState(STATE_SNAP, x,y);
+            TargetDrawable target = targets.get(activeTarget);
+            final float newX = singleTarget ? x : target.getX();
+            final float newY = singleTarget ? y : target.getY();
+            updateGlowPosition(newX, newY);
+        } else {
+            switchToState(STATE_TRACKING, x, y);
+            updateGlowPosition(x, y);
+        }
+
+        if (mActiveTarget != activeTarget) {
+            // Defocus the old target
+            if (mActiveTarget != -1) {
+                TargetDrawable target = targets.get(mActiveTarget);
+                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
+                    target.setState(TargetDrawable.STATE_INACTIVE);
+                }
+            }
+            // Focus the new target
+            if (activeTarget != -1) {
+                TargetDrawable target = targets.get(activeTarget);
+                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
+                    target.setState(TargetDrawable.STATE_FOCUSED);
+                }
+                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                    String targetContentDescription = getTargetDescription(activeTarget);
+                    announceText(targetContentDescription);
+                }
+            }
+        }
+        mActiveTarget = activeTarget;
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent event) {
+        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+            final int action = event.getAction();
+            switch (action) {
+                case MotionEvent.ACTION_HOVER_ENTER:
+                    event.setAction(MotionEvent.ACTION_DOWN);
+                    break;
+                case MotionEvent.ACTION_HOVER_MOVE:
+                    event.setAction(MotionEvent.ACTION_MOVE);
+                    break;
+                case MotionEvent.ACTION_HOVER_EXIT:
+                    event.setAction(MotionEvent.ACTION_UP);
+                    break;
+            }
+            onTouchEvent(event);
+            event.setAction(action);
+        }
+        return super.onHoverEvent(event);
+    }
+
+    /**
+     * Sets the current grabbed state, and dispatches a grabbed state change
+     * event to our listener.
+     */
+    private void setGrabbedState(int newState) {
+        if (newState != mGrabbedState) {
+            if (newState != OnTriggerListener.NO_HANDLE) {
+                vibrate();
+            }
+            mGrabbedState = newState;
+            if (mOnTriggerListener != null) {
+                if (newState == OnTriggerListener.NO_HANDLE) {
+                    mOnTriggerListener.onReleased(this, OnTriggerListener.CENTER_HANDLE);
+                } else {
+                    mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE);
+                }
+                mOnTriggerListener.onGrabbedStateChange(this, newState);
+            }
+        }
+    }
+
+    private boolean trySwitchToFirstTouchState(float x, float y) {
+        final float tx = x - mWaveCenterX;
+        final float ty = y - mWaveCenterY;
+        if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledGlowRadiusSquared()) {
+            if (DEBUG) Log.v(TAG, "** Handle HIT");
+            switchToState(STATE_FIRST_TOUCH, x, y);
+            updateGlowPosition(tx, ty);
+            mDragging = true;
+            return true;
+        }
+        return false;
+    }
+
+    private void assignDefaultsIfNeeded() {
+        if (mOuterRadius == 0.0f) {
+            mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f;
+        }
+        if (mHitRadius == 0.0f) {
+            // Use the radius of inscribed circle of the first target.
+            mHitRadius = mTargetDrawables.get(0).getWidth() / 2.0f;
+        }
+        if (mSnapMargin == 0.0f) {
+            mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
+        }
+        if (mInnerRadius == 0.0f) {
+            mInnerRadius = mHandleDrawable.getWidth() / 10.0f;
+        }
+    }
+
+    private void computeInsets(int dx, int dy) {
+        final int layoutDirection = getResolvedLayoutDirection();
+        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+
+        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+            case Gravity.LEFT:
+                mHorizontalInset = 0;
+                break;
+            case Gravity.RIGHT:
+                mHorizontalInset = dx;
+                break;
+            case Gravity.CENTER_HORIZONTAL:
+            default:
+                mHorizontalInset = dx / 2;
+                break;
+        }
+        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
+            case Gravity.TOP:
+                mVerticalInset = 0;
+                break;
+            case Gravity.BOTTOM:
+                mVerticalInset = dy;
+                break;
+            case Gravity.CENTER_VERTICAL:
+            default:
+                mVerticalInset = dy / 2;
+                break;
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        final int width = right - left;
+        final int height = bottom - top;
+
+        // Target placement width/height. This puts the targets on the greater of the ring
+        // width or the specified outer radius.
+        final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
+        final float placementHeight = Math.max(mOuterRing.getHeight(), 2 * mOuterRadius);
+        float newWaveCenterX = mHorizontalInset
+                + Math.max(width, mMaxTargetWidth + placementWidth) / 2;
+        float newWaveCenterY = mVerticalInset
+                + Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
+
+        if (mInitialLayout) {
+            stopAndHideWaveAnimation();
+            hideTargets(false, false);
+            mInitialLayout = false;
+        }
+
+        mOuterRing.setPositionX(newWaveCenterX);
+        mOuterRing.setPositionY(newWaveCenterY);
+
+        mHandleDrawable.setPositionX(newWaveCenterX);
+        mHandleDrawable.setPositionY(newWaveCenterY);
+
+        updateTargetPositions(newWaveCenterX, newWaveCenterY);
+        updatePointCloudPosition(newWaveCenterX, newWaveCenterY);
+        updateGlowPosition(newWaveCenterX, newWaveCenterY);
+
+        mWaveCenterX = newWaveCenterX;
+        mWaveCenterY = newWaveCenterY;
+
+        if (DEBUG) dump();
+    }
+
+    private void updateTargetPositions(float centerX, float centerY) {
+        // Reposition the target drawables if the view changed.
+        ArrayList<TargetDrawable> targets = mTargetDrawables;
+        final int size = targets.size();
+        final float alpha = (float) (-2.0f * Math.PI / size);
+        for (int i = 0; i < size; i++) {
+            final TargetDrawable targetIcon = targets.get(i);
+            final float angle = alpha * i;
+            targetIcon.setPositionX(centerX);
+            targetIcon.setPositionY(centerY);
+            targetIcon.setX(mOuterRadius * (float) Math.cos(angle));
+            targetIcon.setY(mOuterRadius * (float) Math.sin(angle));
+        }
+    }
+
+    private void updatePointCloudPosition(float centerX, float centerY) {
+        mPointCloud.setCenter(centerX, centerY);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        mPointCloud.draw(canvas);
+        mOuterRing.draw(canvas);
+        final int ntargets = mTargetDrawables.size();
+        for (int i = 0; i < ntargets; i++) {
+            TargetDrawable target = mTargetDrawables.get(i);
+            if (target != null) {
+                target.draw(canvas);
+            }
+        }
+        mHandleDrawable.draw(canvas);
+    }
+
+    public void setOnTriggerListener(OnTriggerListener listener) {
+        mOnTriggerListener = listener;
+    }
+
+    private float square(float d) {
+        return d * d;
+    }
+
+    private float dist2(float dx, float dy) {
+        return dx*dx + dy*dy;
+    }
+
+    private float getScaledGlowRadiusSquared() {
+        final float scaledTapRadius;
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            scaledTapRadius = TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mGlowRadius;
+        } else {
+            scaledTapRadius = mGlowRadius;
+        }
+        return square(scaledTapRadius);
+    }
+
+    private void announceTargets() {
+        StringBuilder utterance = new StringBuilder();
+        final int targetCount = mTargetDrawables.size();
+        for (int i = 0; i < targetCount; i++) {
+            String targetDescription = getTargetDescription(i);
+            String directionDescription = getDirectionDescription(i);
+            if (!TextUtils.isEmpty(targetDescription)
+                    && !TextUtils.isEmpty(directionDescription)) {
+                String text = String.format(directionDescription, targetDescription);
+                utterance.append(text);
+            }
+            if (utterance.length() > 0) {
+                announceText(utterance.toString());
+            }
+        }
+    }
+
+    private void announceText(String text) {
+        setContentDescription(text);
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        setContentDescription(null);
+    }
+
+    private String getTargetDescription(int index) {
+        if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) {
+            mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId);
+            if (mTargetDrawables.size() != mTargetDescriptions.size()) {
+                Log.w(TAG, "The number of target drawables must be"
+                        + " equal to the number of target descriptions.");
+                return null;
+            }
+        }
+        return mTargetDescriptions.get(index);
+    }
+
+    private String getDirectionDescription(int index) {
+        if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) {
+            mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId);
+            if (mTargetDrawables.size() != mDirectionDescriptions.size()) {
+                Log.w(TAG, "The number of target drawables must be"
+                        + " equal to the number of direction descriptions.");
+                return null;
+            }
+        }
+        return mDirectionDescriptions.get(index);
+    }
+
+    private ArrayList<String> loadDescriptions(int resourceId) {
+        TypedArray array = getContext().getResources().obtainTypedArray(resourceId);
+        final int count = array.length();
+        ArrayList<String> targetContentDescriptions = new ArrayList<String>(count);
+        for (int i = 0; i < count; i++) {
+            String contentDescription = array.getString(i);
+            targetContentDescriptions.add(contentDescription);
+        }
+        array.recycle();
+        return targetContentDescriptions;
+    }
+
+    public int getResourceIdForTarget(int index) {
+        final TargetDrawable drawable = mTargetDrawables.get(index);
+        return drawable == null ? 0 : drawable.getResourceId();
+    }
+
+    public void setEnableTarget(int resourceId, boolean enabled) {
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            final TargetDrawable target = mTargetDrawables.get(i);
+            if (target.getResourceId() == resourceId) {
+                target.setEnabled(enabled);
+                break; // should never be more than one match
+            }
+        }
+    }
+
+    /**
+     * Gets the position of a target in the array that matches the given resource.
+     * @param resourceId
+     * @return the index or -1 if not found
+     */
+    public int getTargetPosition(int resourceId) {
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            final TargetDrawable target = mTargetDrawables.get(i);
+            if (target.getResourceId() == resourceId) {
+                return i; // should never be more than one match
+            }
+        }
+        return -1;
+    }
+
+    private boolean replaceTargetDrawables(Resources res, int existingResourceId,
+            int newResourceId) {
+        if (existingResourceId == 0 || newResourceId == 0) {
+            return false;
+        }
+
+        boolean result = false;
+        final ArrayList<TargetDrawable> drawables = mTargetDrawables;
+        final int size = drawables.size();
+        for (int i = 0; i < size; i++) {
+            final TargetDrawable target = drawables.get(i);
+            if (target != null && target.getResourceId() == existingResourceId) {
+                target.setDrawable(res, newResourceId);
+                result = true;
+            }
+        }
+
+        if (result) {
+            requestLayout(); // in case any given drawable's size changes
+        }
+
+        return result;
+    }
+
+    /**
+     * Searches the given package for a resource to use to replace the Drawable on the
+     * target with the given resource id
+     * @param component of the .apk that contains the resource
+     * @param name of the metadata in the .apk
+     * @param existingResId the resource id of the target to search for
+     * @return true if found in the given package and replaced at least one target Drawables
+     */
+    public boolean replaceTargetDrawablesIfPresent(ComponentName component, String name,
+                int existingResId) {
+        if (existingResId == 0) return false;
+
+        try {
+            PackageManager packageManager = mContext.getPackageManager();
+            // Look for the search icon specified in the activity meta-data
+            Bundle metaData = packageManager.getActivityInfo(
+                    component, PackageManager.GET_META_DATA).metaData;
+            if (metaData != null) {
+                int iconResId = metaData.getInt(name);
+                if (iconResId != 0) {
+                    Resources res = packageManager.getResourcesForActivity(component);
+                    return replaceTargetDrawables(res, existingResId, iconResId);
+                }
+            }
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Failed to swap drawable; "
+                    + component.flattenToShortString() + " not found", e);
+        } catch (Resources.NotFoundException nfe) {
+            Log.w(TAG, "Failed to swap drawable from "
+                    + component.flattenToShortString(), nfe);
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 89dbd1b..afeac00 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -117,8 +117,6 @@
     private float mWaveCenterY;
     private int mMaxTargetHeight;
     private int mMaxTargetWidth;
-    private float mHorizontalOffset;
-    private float mVerticalOffset;
 
     private float mOuterRadius = 0.0f;
     private float mHitRadius = 0.0f;
@@ -215,9 +213,6 @@
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView);
         mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius);
-//        mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset,
-//                mHorizontalOffset);
-//        mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset, mVerticalOffset);
         mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius);
         mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin);
         mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration,
@@ -230,7 +225,6 @@
         mOuterRing = new TargetDrawable(res,
                 a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
         mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false);
-        mGravity = a.getInt(R.styleable.MultiWaveView_gravity, Gravity.TOP);
 
         // Read array of chevron drawables
         TypedValue outValue = new TypedValue();
@@ -244,24 +238,6 @@
             }
         }
 
-        // Support old-style chevron specification if new specification not found
-        if (mChevronDrawables.size() == 0) {
-            final int chevronResIds[] = {
-                    R.styleable.MultiWaveView_rightChevronDrawable,
-                    R.styleable.MultiWaveView_topChevronDrawable,
-                    R.styleable.MultiWaveView_leftChevronDrawable,
-                    R.styleable.MultiWaveView_bottomChevronDrawable
-            };
-
-            for (int i = 0; i < chevronResIds.length; i++) {
-                TypedValue typedValue = a.peekValue(chevronResIds[i]);
-                for (int k = 0; k < mFeedbackCount; k++) {
-                    mChevronDrawables.add(
-                        typedValue != null ? new TargetDrawable(res, typedValue.resourceId) : null);
-                }
-            }
-        }
-
         // Read array of target drawables
         if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) {
             internalSetTargetResources(outValue.resourceId);
@@ -289,6 +265,12 @@
         }
 
         a.recycle();
+
+        // Use gravity attribute from LinearLayout
+        a = context.obtainStyledAttributes(attrs, android.R.styleable.LinearLayout);
+        mGravity = a.getInt(android.R.styleable.LinearLayout_gravity, Gravity.TOP);
+        a.recycle();
+
         setVibrateEnabled(mVibrationDuration > 0);
         assignDefaultsIfNeeded();
     }
@@ -302,8 +284,6 @@
         Log.v(TAG, "TapRadius = " + mTapRadius);
         Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
         Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
-        Log.v(TAG, "HorizontalOffset = " + mHorizontalOffset);
-        Log.v(TAG, "VerticalOffset = " + mVerticalOffset);
     }
 
     public void suspendAnimations() {
@@ -1042,9 +1022,9 @@
         // width or the specified outer radius.
         final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
         final float placementHeight = Math.max(mOuterRing.getHeight(), 2 * mOuterRadius);
-        float newWaveCenterX = mHorizontalOffset + mHorizontalInset
+        float newWaveCenterX = mHorizontalInset
                 + Math.max(width, mMaxTargetWidth + placementWidth) / 2;
-        float newWaveCenterY = mVerticalOffset + mVerticalInset
+        float newWaveCenterY = mVerticalInset
                 + Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
 
         if (mInitialLayout) {
diff --git a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
new file mode 100644
index 0000000..2ef8c78
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import java.util.ArrayList;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.util.FloatMath;
+import android.util.Log;
+
+public class PointCloud {
+    private static final float MIN_POINT_SIZE = 2.0f;
+    private static final float MAX_POINT_SIZE = 4.0f;
+    private static final int INNER_POINTS = 8;
+    private static final String TAG = "PointCloud";
+    private ArrayList<Point> mPointCloud = new ArrayList<Point>();
+    private Drawable mDrawable;
+    private float mCenterX;
+    private float mCenterY;
+    private Paint mPaint;
+    private float mScale = 1.0f;
+    private static final float PI = (float) Math.PI;
+
+    // These allow us to have multiple concurrent animations.
+    WaveManager waveManager = new WaveManager();
+    GlowManager glowManager = new GlowManager();
+    private float mOuterRadius;
+
+    public class WaveManager {
+        private float radius = 50;
+        private float width = 200.0f; // TODO: Make configurable
+        private float alpha = 0.0f;
+        public void setRadius(float r) {
+            radius = r;
+        }
+
+        public float getRadius() {
+            return radius;
+        }
+
+        public void setAlpha(float a) {
+            alpha = a;
+        }
+
+        public float getAlpha() {
+            return alpha;
+        }
+    };
+
+    public class GlowManager {
+        private float x;
+        private float y;
+        private float radius = 0.0f;
+        private float alpha = 0.0f;
+
+        public void setX(float x1) {
+            x = x1;
+        }
+
+        public float getX() {
+            return x;
+        }
+
+        public void setY(float y1) {
+            y = y1;
+        }
+
+        public float getY() {
+            return y;
+        }
+
+        public void setAlpha(float a) {
+            alpha = a;
+        }
+
+        public float getAlpha() {
+            return alpha;
+        }
+
+        public void setRadius(float r) {
+            radius = r;
+        }
+
+        public float getRadius() {
+            return radius;
+        }
+    }
+
+    class Point {
+        float x;
+        float y;
+        float radius;
+
+        public Point(float x2, float y2, float r) {
+            x = (float) x2;
+            y = (float) y2;
+            radius = r;
+        }
+    }
+
+    public PointCloud(Drawable drawable) {
+        mPaint = new Paint();
+        mPaint.setFilterBitmap(true);
+        mPaint.setColor(Color.rgb(255, 255, 255)); // TODO: make configurable
+        mPaint.setAntiAlias(true);
+        mPaint.setDither(true);
+
+        mDrawable = drawable;
+        if (mDrawable != null) {
+            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+        }
+    }
+
+    public void setCenter(float x, float y) {
+        mCenterX = x;
+        mCenterY = y;
+    }
+
+    public void makePointCloud(float innerRadius, float outerRadius) {
+        if (innerRadius == 0) {
+            Log.w(TAG, "Must specify an inner radius");
+            return;
+        }
+        mOuterRadius = outerRadius;
+        mPointCloud.clear();
+        final float pointAreaRadius =  (outerRadius - innerRadius);
+        final float ds = (2.0f * PI * innerRadius / INNER_POINTS);
+        final int bands = (int) Math.round(pointAreaRadius / ds);
+        final float dr = pointAreaRadius / bands;
+        float r = innerRadius;
+        for (int b = 0; b <= bands; b++, r += dr) {
+            float circumference = 2.0f * PI * r;
+            final int pointsInBand = (int) (circumference / ds);
+            float eta = PI/2.0f;
+            float dEta = 2.0f * PI / pointsInBand;
+            for (int i = 0; i < pointsInBand; i++) {
+                float x = r * FloatMath.cos(eta);
+                float y = r * FloatMath.sin(eta);
+                eta += dEta;
+                mPointCloud.add(new Point(x, y, r));
+            }
+        }
+    }
+
+    public void setScale(float scale) {
+        mScale  = scale;
+    }
+
+    public float getScale() {
+        return mScale;
+    }
+
+    private static float hypot(float x, float y) {
+        return FloatMath.sqrt(x*x + y*y);
+    }
+
+    private static float max(float a, float b) {
+        return a > b ? a : b;
+    }
+
+    public int getAlphaForPoint(Point point) {
+        // Contribution from positional glow
+        float glowDistance = hypot(glowManager.x - point.x, glowManager.y - point.y);
+        float glowAlpha = 0.0f;
+        if (glowDistance < glowManager.radius) {
+            float cosf = FloatMath.cos(PI * 0.5f * glowDistance / glowManager.radius);
+            glowAlpha = glowManager.alpha * max(0.0f, (float) Math.pow(cosf, 0.5f));
+        }
+
+        // Compute contribution from Wave
+        float radius = hypot(point.x, point.y);
+        float distanceToWaveRing = Math.abs(radius - waveManager.radius);
+        float waveAlpha = 0.0f;
+        if (distanceToWaveRing < waveManager.width * 0.5f) {
+            float cosf = FloatMath.cos(PI * 0.5f * distanceToWaveRing / waveManager.width);
+            waveAlpha = waveManager.alpha * max(0.0f, (float) Math.pow(cosf, 15.0f));
+        }
+
+        return (int) (max(glowAlpha, waveAlpha) * 255);
+    }
+
+    private float interp(float min, float max, float f) {
+        return min + (max - min) * f;
+    }
+
+    public void draw(Canvas canvas) {
+        ArrayList<Point> points = mPointCloud;
+        final float cx = mDrawable != null ? (-mDrawable.getIntrinsicWidth() / 2) : 0;
+        final float cy = mDrawable != null ? (-mDrawable.getIntrinsicHeight() / 2) : 0;
+        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.scale(mScale, mScale, mCenterX, mCenterY);
+        for (int i = 0; i < points.size(); i++) {
+            Point point = points.get(i);
+            final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE,
+                    point.radius / mOuterRadius);
+            final float px = point.x + cx + mCenterX;
+            final float py = point.y + cy + mCenterY;
+            int alpha = getAlphaForPoint(point);
+
+            if (alpha == 0) continue;
+
+            if (mDrawable != null) {
+                canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                float s = pointSize / MAX_POINT_SIZE;
+                canvas.scale(s, s, px, py);
+                canvas.translate(px, py);
+                mDrawable.setAlpha(alpha);
+                mDrawable.draw(canvas);
+                canvas.restore();
+            } else {
+                mPaint.setAlpha(alpha);
+                canvas.drawCircle(px, py, pointSize, mPaint);
+            }
+        }
+        canvas.restore();
+    }
+
+}
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_glowdot.png b/core/res/res/drawable-hdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..983c45e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_glowdot.png b/core/res/res/drawable-mdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..056c3f17
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_glowdot.png b/core/res/res/drawable-xhdpi/ic_lockscreen_glowdot.png
new file mode 100644
index 0000000..cbd039a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_glowdot.png
Binary files differ
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
index a666077..cd9c913 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
@@ -82,7 +82,7 @@
             android:drawablePadding="4dip"
             />
 
-        <com.android.internal.widget.multiwaveview.MultiWaveView
+        <com.android.internal.widget.multiwaveview.GlowPadView
             android:id="@+id/unlock_widget"
             android:orientation="horizontal"
             android:layout_width="wrap_content"
@@ -94,13 +94,15 @@
             android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
             android:directionDescriptions="@array/lockscreen_direction_descriptions"
             android:handleDrawable="@drawable/ic_lockscreen_handle"
-            android:waveDrawable="@drawable/ic_lockscreen_outerring"
-            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
-            android:snapMargin="@dimen/multiwaveview_snap_margin"
-            android:hitRadius="@dimen/multiwaveview_hit_radius"
-            android:chevronDrawables="@array/lockscreen_chevron_drawables"
-            android:feedbackCount="3"
+            android:outerRingDrawable="@drawable/ic_lockscreen_outerring"
+            android:outerRadius="@dimen/glowpadview_target_placement_radius"
+            android:innerRadius="@dimen/glowpadview_inner_radius"
+            android:snapMargin="@dimen/glowpadview_snap_margin"
+            android:hitRadius="@dimen/glowpadview_hit_radius"
+            android:feedbackCount="1"
             android:vibrationDuration="20"
+            android:glowRadius="@dimen/glowpadview_glow_radius"
+            android:pointDrawable="@drawable/ic_lockscreen_glowdot"
             />
 
         <!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
index 17a3c84..32ca602 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
@@ -82,7 +82,7 @@
             android:layout_alignParentTop="true"
             android:drawablePadding="4dip"/>
 
-        <com.android.internal.widget.multiwaveview.MultiWaveView
+        <com.android.internal.widget.multiwaveview.GlowPadView
             android:id="@+id/unlock_widget"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -94,13 +94,15 @@
             android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
             android:directionDescriptions="@array/lockscreen_direction_descriptions"
             android:handleDrawable="@drawable/ic_lockscreen_handle"
-            android:waveDrawable="@drawable/ic_lockscreen_outerring"
-            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
-            android:snapMargin="@dimen/multiwaveview_snap_margin"
-            android:hitRadius="@dimen/multiwaveview_hit_radius"
-            android:chevronDrawables="@array/lockscreen_chevron_drawables"
-            android:feedbackCount="3"
+            android:outerRingDrawable="@drawable/ic_lockscreen_outerring"
+            android:outerRadius="@dimen/glowpadview_target_placement_radius"
+            android:innerRadius="@dimen/glowpadview_inner_radius"
+            android:snapMargin="@dimen/glowpadview_snap_margin"
+            android:hitRadius="@dimen/glowpadview_hit_radius"
+            android:feedbackCount="1"
             android:vibrationDuration="20"
+            android:glowRadius="@dimen/glowpadview_glow_radius"
+            android:pointDrawable="@drawable/ic_lockscreen_glowdot"
         />
 
         <!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 2dcb774..4e646a6 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -123,7 +123,7 @@
         android:layout_width="match_parent"
         android:layout_height="302dip">
 
-        <com.android.internal.widget.multiwaveview.MultiWaveView
+        <com.android.internal.widget.multiwaveview.GlowPadView
             android:id="@+id/unlock_widget"
             android:orientation="horizontal"
             android:layout_width="match_parent"
@@ -135,13 +135,15 @@
             android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
             android:directionDescriptions="@array/lockscreen_direction_descriptions"
             android:handleDrawable="@drawable/ic_lockscreen_handle"
-            android:waveDrawable="@drawable/ic_lockscreen_outerring"
-            android:outerRadius="@dimen/multiwaveview_target_placement_radius"
-            android:snapMargin="@dimen/multiwaveview_snap_margin"
-            android:hitRadius="@dimen/multiwaveview_hit_radius"
-            android:chevronDrawables="@array/lockscreen_chevron_drawables"
-            android:feedbackCount="3"
+            android:outerRingDrawable="@drawable/ic_lockscreen_outerring"
+            android:outerRadius="@dimen/glowpadview_target_placement_radius"
+            android:innerRadius="@dimen/glowpadview_inner_radius"
+            android:snapMargin="@dimen/glowpadview_snap_margin"
+            android:hitRadius="@dimen/glowpadview_hit_radius"
+            android:feedbackCount="1"
             android:vibrationDuration="20"
+            android:glowRadius="@dimen/glowpadview_glow_radius"
+            android:pointDrawable="@drawable/ic_lockscreen_glowdot"
             />
 
         <TextView
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 10ddd1e..5a357fb 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -129,24 +129,26 @@
     <Space android:layout_width="64dip" android:layout_rowSpan="7" />
 
     <!-- Column 2 -->
-    <com.android.internal.widget.multiwaveview.MultiWaveView
+    <com.android.internal.widget.multiwaveview.GlowPadView
         android:id="@+id/unlock_widget"
         android:layout_width="302dip"
         android:layout_height="match_parent"
         android:layout_rowSpan="7"
-        android:gravity="center"
+        android:gravity="left|center_vertical"
 
         android:targetDrawables="@array/lockscreen_targets_with_camera"
         android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
         android:directionDescriptions="@array/lockscreen_direction_descriptions"
         android:handleDrawable="@drawable/ic_lockscreen_handle"
-        android:waveDrawable="@drawable/ic_lockscreen_outerring"
-        android:outerRadius="@dimen/multiwaveview_target_placement_radius"
-        android:snapMargin="@dimen/multiwaveview_snap_margin"
-        android:hitRadius="@dimen/multiwaveview_hit_radius"
-        android:chevronDrawables="@array/lockscreen_chevron_drawables"
-        android:feedbackCount="3"
+        android:outerRingDrawable="@drawable/ic_lockscreen_outerring"
+        android:outerRadius="@dimen/glowpadview_target_placement_radius"
+        android:innerRadius="@dimen/glowpadview_inner_radius"
+        android:snapMargin="@dimen/glowpadview_snap_margin"
+        android:hitRadius="@dimen/glowpadview_hit_radius"
+        android:feedbackCount="1"
         android:vibrationDuration="20"
+        android:glowRadius="@dimen/glowpadview_glow_radius"
+        android:pointDrawable="@drawable/ic_lockscreen_glowdot"
         />
 
     <!-- Music transport control -->
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index 7095c02..f2df3fa 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -19,7 +19,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Resources for MultiWaveView in LockScreen -->
+    <!-- Resources for GlowPadView in LockScreen -->
     <array name="lockscreen_targets_when_silent">
         <item>@null</item>"
         <item>@drawable/ic_lockscreen_unlock</item>
diff --git a/core/res/res/values-sw600dp-land/arrays.xml b/core/res/res/values-sw600dp-land/arrays.xml
index 6a09cf8..2b5fd99 100644
--- a/core/res/res/values-sw600dp-land/arrays.xml
+++ b/core/res/res/values-sw600dp-land/arrays.xml
@@ -19,7 +19,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Resources for MultiWaveView in LockScreen -->
+    <!-- Resources for GlowPadView in LockScreen -->
     <array name="lockscreen_targets_when_silent">
         <item>@drawable/ic_lockscreen_unlock</item>
         <item>@null</item>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index d26666e..8937c2a 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -45,8 +45,8 @@
     <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
     <dimen name="keyguard_lockscreen_outerring_diameter">364dp</dimen>
 
-    <!-- target placement radius for MultiWaveView -->
-    <dimen name="multiwaveview_target_placement_radius">182dip</dimen>
+    <!-- target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
+    <dimen name="glowpadview_target_placement_radius">182dip</dimen>
 
     <!-- Size of status line font in LockScreen. -->
     <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 1eeca59..aeb6b4f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -350,7 +350,7 @@
         <item>中文 (繁體)</item>
     </string-array>
 
-    <!-- Resources for MultiWaveView in LockScreen -->
+    <!-- Resources for GlowPadView in LockScreen -->
     <array name="lockscreen_targets_when_silent">
         <item>@drawable/ic_lockscreen_unlock</item>
         <item>@drawable/ic_lockscreen_search</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a68011d..00077512 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5377,6 +5377,54 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- GlowPadView class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+    <declare-styleable name="GlowPadView">
+        <!-- Reference to an array resource that be shown as targets around a circle. -->
+        <attr name="targetDrawables"/>
+
+        <!-- Reference to an array resource that be used as description for the targets around the circle. -->
+        <attr name="targetDescriptions"/>
+
+        <!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->
+        <attr name="directionDescriptions"/>
+
+        <!-- Sets a drawable as the center. -->
+        <attr name="handleDrawable"/>
+
+        <!-- Drawable to use for wave ripple animation. -->
+        <attr name="outerRingDrawable" format="reference"/>
+
+        <!-- Drawble used for drawing points -->
+        <attr name="pointDrawable" format="reference" />
+
+        <!-- Inner radius of glow area. -->
+        <attr name="innerRadius"/>
+
+        <!-- Outer radius of glow area. Target icons will be drawn on this circle. -->
+        <attr name="outerRadius"/>
+
+        <!-- Size of target radius. Points within this distance of target center is a "hit". -->
+        <attr name="hitRadius"/>
+
+        <!-- Radius of glow under finger. -->
+        <attr name="glowRadius" format="dimension" />
+
+        <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
+        <attr name="vibrationDuration"/>
+
+        <!-- How close we need to be before snapping to a target. -->
+        <attr name="snapMargin"/>
+
+        <!-- Number of waves/chevrons to show in animation. -->
+        <attr name="feedbackCount"/>
+
+        <!-- Used when the handle shouldn't wait to be hit before following the finger -->
+        <attr name="alwaysTrackFinger"/>
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- MultiWaveView class attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -5393,22 +5441,6 @@
         <!-- Sets a drawable as the drag center. -->
         <attr name="handleDrawable" format="reference" />
 
-        <!-- Drawable to use for chevron animation on the left. May be null.
-            @deprecated use chevronDrawables instead -->
-        <attr name="leftChevronDrawable" format="reference" />
-
-        <!-- Drawable to use for chevron animation on the right. May be null.
-            @deprecated use chevronDrawables instead -->
-        <attr name="rightChevronDrawable" format="reference" />
-
-        <!-- Drawable to use for chevron animation on the top. May be null.
-            @deprecated use chevronDrawables instead -->
-        <attr name="topChevronDrawable" format="reference" />
-
-        <!-- Drawable to use for chevron animation on the bottom. May be null.
-            @deprecated use chevronDrawables instead -->
-        <attr name="bottomChevronDrawable" format="reference" />
-
         <!-- Drawables to use for chevron animations. May be null. -->
         <attr name="chevronDrawables" format="reference"/>
 
@@ -5430,17 +5462,6 @@
         <!-- Number of waves/chevrons to show in animation. -->
         <attr name="feedbackCount" format="integer" />
 
-        <!-- {@deprecated Not used by the framework. Use android:gravity instead}
-            Used to shift center of pattern vertically. -->
-        <attr name="verticalOffset" format="dimension" />
-
-        <!-- {@deprecated Not used by the framework. Use android:gravity instead}
-            Used to shift center of pattern horizontally. -->
-        <attr name="horizontalOffset" format="dimension" />
-
-        <!-- How the items in this layout should be positioned -->
-        <attr name="gravity" />
-
         <!-- Used when the handle shouldn't wait to be hit before following the finger -->
         <attr name="alwaysTrackFinger" format="boolean" />
     </declare-styleable>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index d549644..ffbcb95 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -73,14 +73,20 @@
     <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
     <dimen name="keyguard_lockscreen_outerring_diameter">270dp</dimen>
 
-    <!-- Default target placement radius for MultiWaveView -->
-    <dimen name="multiwaveview_target_placement_radius">135dip</dimen>
+    <!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
+    <dimen name="glowpadview_target_placement_radius">135dip</dimen>
 
-    <!-- Default distance beyond which MultiWaveView snaps to the target radius -->
-    <dimen name="multiwaveview_snap_margin">20dip</dimen>
+    <!-- Default glow radius for GlowPadView -->
+    <dimen name="glowpadview_glow_radius">75dip</dimen>
 
-    <!-- Default distance from each snap target that MultiWaveView considers a "hit" -->
-    <dimen name="multiwaveview_hit_radius">60dip</dimen>
+    <!-- Default distance beyond which GlowPadView snaps to the target radius -->
+    <dimen name="glowpadview_snap_margin">20dip</dimen>
+
+    <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
+    <dimen name="glowpadview_hit_radius">60dip</dimen>
+
+    <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
+    <dimen name="glowpadview_inner_radius">15dip</dimen>
 
     <!-- Preference activity side margins -->
     <dimen name="preference_screen_side_margin">0dp</dimen>
@@ -228,10 +234,10 @@
          a few are present. -->
     <dimen name="action_bar_stacked_tab_max_width">180dp</dimen>
 
-	<!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
+    <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
     <dimen name="notification_text_size">14dp</dimen>
-	<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
+    <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
     <dimen name="notification_title_text_size">18dp</dimen>
-	<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
+    <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/drawable-hdpi/navbar_search_bg_scrim.9.png b/packages/SystemUI/res/drawable-hdpi/navbar_search_bg_scrim.9.png
deleted file mode 100644
index 4c163a2..0000000
--- a/packages/SystemUI/res/drawable-hdpi/navbar_search_bg_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/navbar_search_bg_scrim.9.png b/packages/SystemUI/res/drawable-mdpi/navbar_search_bg_scrim.9.png
deleted file mode 100644
index 21c5abd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/navbar_search_bg_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/navbar_search_bg_scrim.9.png b/packages/SystemUI/res/drawable-xhdpi/navbar_search_bg_scrim.9.png
deleted file mode 100644
index 7874c63..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/navbar_search_bg_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
index ae81167..e6c0087 100644
--- a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -38,25 +38,29 @@
             android:layout_height="match_parent"
             android:layout_alignParentRight="true">
 
-            <com.android.internal.widget.multiwaveview.MultiWaveView
-                android:id="@+id/multi_wave_view"
+            <com.android.internal.widget.multiwaveview.GlowPadView
+                android:id="@+id/glow_pad_view"
                 android:orientation="vertical"
                 android:layout_width="@dimen/navbar_search_panel_height"
                 android:layout_height="match_parent"
                 android:layout_alignParentBottom="true"
-                android:background="@drawable/navbar_search_bg_scrim"
                 android:gravity="left"
 
                 prvandroid:targetDrawables="@array/navbar_search_targets"
                 prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
                 prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
                 prvandroid:handleDrawable="@drawable/navbar_search_handle"
-                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRingDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
+                prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
                 prvandroid:vibrationDuration="@integer/config_vibration_duration"
-                prvandroid:alwaysTrackFinger="true"/>
+                prvandroid:alwaysTrackFinger="true"
+                prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+                prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"
+                />
 
         </RelativeLayout>
 
diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
index 785d5dd..3828136 100644
--- a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
@@ -38,25 +38,29 @@
             android:layout_height="wrap_content"
             android:layout_alignParentBottom="true">
 
-            <com.android.internal.widget.multiwaveview.MultiWaveView
-                android:id="@+id/multi_wave_view"
+            <com.android.internal.widget.multiwaveview.GlowPadView
+                android:id="@+id/glow_pad_view"
                 android:orientation="horizontal"
                 android:layout_width="match_parent"
                 android:layout_height="@dimen/navbar_search_panel_height"
                 android:layout_alignParentBottom="true"
-                android:background="@drawable/navbar_search_bg_scrim"
                 android:gravity="top"
 
                 prvandroid:targetDrawables="@array/navbar_search_targets"
                 prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
                 prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
                 prvandroid:handleDrawable="@drawable/navbar_search_handle"
-                prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRingDrawable="@drawable/navbar_search_outerring"
+                prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
+                prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
                 prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
                 prvandroid:feedbackCount="0"
                 prvandroid:vibrationDuration="@integer/config_vibration_duration"
-                prvandroid:alwaysTrackFinger="true"/>
+                prvandroid:alwaysTrackFinger="true"
+                prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+                prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"
+               />
 
         </RelativeLayout>
 
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
index 74a15f2..c17f858 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
@@ -25,23 +25,26 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
-    <com.android.internal.widget.multiwaveview.MultiWaveView
-        android:id="@+id/multi_wave_view"
+    <com.android.internal.widget.multiwaveview.GlowPadView
+        android:id="@+id/glow_pad_view"
         android:layout_width="wrap_content"
         android:layout_height="@dimen/navbar_search_panel_height"
         android:layout_gravity="center_horizontal|bottom"
         android:gravity="center_horizontal|top"
-        android:background="@drawable/navbar_search_bg_scrim"
 
         prvandroid:targetDrawables="@array/navbar_search_targets"
         prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
         prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
         prvandroid:handleDrawable="@drawable/navbar_search_handle"
-        prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+        prvandroid:outerRingDrawable="@drawable/navbar_search_outerring"
+        prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
+        prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
         prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
         prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
         prvandroid:feedbackCount="0"
         prvandroid:vibrationDuration="@integer/config_vibration_duration"
-        prvandroid:alwaysTrackFinger="true"/>
+        prvandroid:alwaysTrackFinger="true"
+        prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+        prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"/>
 
 </com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
index 2a97307..100f81d 100644
--- a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
@@ -25,24 +25,27 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
-    <com.android.internal.widget.multiwaveview.MultiWaveView
-        android:id="@+id/multi_wave_view"
+    <com.android.internal.widget.multiwaveview.GlowPadView
+        android:id="@+id/glow_pad_view"
         android:layout_width="wrap_content"
         android:layout_height="@dimen/navbar_search_panel_height"
         android:layout_gravity="left|bottom"
         android:gravity="top|right"
         android:layout_marginLeft="-150dip"
-        android:background="@drawable/navbar_search_bg_scrim"
 
         prvandroid:targetDrawables="@array/navbar_search_targets"
         prvandroid:targetDescriptions="@array/navbar_search_target_descriptions"
         prvandroid:directionDescriptions="@array/navbar_search_direction_descriptions"
         prvandroid:handleDrawable="@drawable/navbar_search_handle"
-        prvandroid:waveDrawable="@drawable/navbar_search_outerring"
+        prvandroid:outerRingDrawable="@drawable/navbar_search_outerring"
+        prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
+        prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
         prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
         prvandroid:hitRadius="@dimen/navbar_search_hit_radius"
         prvandroid:feedbackCount="0"
         prvandroid:vibrationDuration="@integer/config_vibration_duration"
-        prvandroid:alwaysTrackFinger="true"/>
+        prvandroid:alwaysTrackFinger="true"
+        prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+        prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"/>
 
 </com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1bf59b0..2b5248f 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -30,6 +30,9 @@
     <!-- Diameter of outer shape drawable shown in navbar search-->
     <dimen name="navbar_search_outerring_diameter">430dip</dimen>
 
+    <!-- Diameter of outer shape drawable shown in navbar search. Should be 1/2 of above value. -->
+    <dimen name="navbar_search_outerring_radius">215dip</dimen>
+
     <!-- Height of search panel including navigation bar height -->
     <dimen name="navbar_search_panel_height">280dip</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f40ffd4..c88ae2a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -119,6 +119,9 @@
     <!-- Diameter of outer shape drawable shown in navbar search-->
     <dimen name="navbar_search_outerring_diameter">340dp</dimen>
 
+    <!-- Diameter of outer shape drawable shown in navbar search. Should be 1/2 of above value -->
+    <dimen name="navbar_search_outerring_radius">170dp</dimen>
+
     <!-- Threshold for swipe-up gesture to activate search dialog -->
     <dimen name="navbar_search_up_threshhold">40dip</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 8b8a814..923bcba 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -35,8 +35,8 @@
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.widget.FrameLayout;
-import com.android.internal.widget.multiwaveview.MultiWaveView;
-import com.android.internal.widget.multiwaveview.MultiWaveView.OnTriggerListener;
+import com.android.internal.widget.multiwaveview.GlowPadView;
+import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
 import com.android.systemui.R;
 import com.android.systemui.recent.StatusBarTouchProxy;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -58,7 +58,7 @@
 
     private boolean mShowing;
     private View mSearchTargetsContainer;
-    private MultiWaveView mMultiWaveView;
+    private GlowPadView mGlowPadView;
 
     public SearchPanelView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -125,7 +125,7 @@
         }
     }
 
-    class MultiWaveTriggerListener implements MultiWaveView.OnTriggerListener {
+    class GlowPadTriggerListener implements GlowPadView.OnTriggerListener {
         boolean mWaitingForLaunch;
 
         public void onGrabbed(View v, int handle) {
@@ -141,7 +141,7 @@
         }
 
         public void onTrigger(View v, final int target) {
-            final int resId = mMultiWaveView.getResourceIdForTarget(target);
+            final int resId = mGlowPadView.getResourceIdForTarget(target);
             switch (resId) {
                 case com.android.internal.R.drawable.ic_lockscreen_search:
                     mWaitingForLaunch = true;
@@ -154,13 +154,13 @@
         public void onFinishFinalAnimation() {
         }
     }
-    final MultiWaveTriggerListener mMultiWaveViewListener = new MultiWaveTriggerListener();
+    final GlowPadTriggerListener mGlowPadViewListener = new GlowPadTriggerListener();
 
     @Override
     public void onAnimationStarted() {
         postDelayed(new Runnable() {
             public void run() {
-                mMultiWaveViewListener.mWaitingForLaunch = false;
+                mGlowPadViewListener.mWaitingForLaunch = false;
                 mBar.hideSearchPanel();
             }
         }, SEARCH_PANEL_HOLD_DURATION);
@@ -173,13 +173,13 @@
         mSearchTargetsContainer = findViewById(R.id.search_panel_container);
         mStatusBarTouchProxy = (StatusBarTouchProxy) findViewById(R.id.status_bar_touch_proxy);
         // TODO: fetch views
-        mMultiWaveView = (MultiWaveView) findViewById(R.id.multi_wave_view);
-        mMultiWaveView.setOnTriggerListener(mMultiWaveViewListener);
+        mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
+        mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
         SearchManager searchManager = getSearchManager();
         if (searchManager != null) {
             ComponentName component = searchManager.getGlobalSearchActivity();
             if (component != null) {
-                if (!mMultiWaveView.replaceTargetDrawablesIfPresent(component,
+                if (!mGlowPadView.replaceTargetDrawablesIfPresent(component,
                         ASSIST_ICON_METADATA_NAME,
                         com.android.internal.R.drawable.ic_lockscreen_search)) {
                     Slog.w(TAG, "Couldn't grab icon from component " + component);
@@ -214,7 +214,7 @@
     private final OnPreDrawListener mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
         public boolean onPreDraw() {
             getViewTreeObserver().removeOnPreDrawListener(this);
-            mMultiWaveView.resumeAnimations();
+            mGlowPadView.resumeAnimations();
             return false;
         }
     };
@@ -240,7 +240,8 @@
                 setVisibility(View.VISIBLE);
                 // Don't start the animation until we've created the layer, which is done
                 // right before we are drawn
-                mMultiWaveView.suspendAnimations();
+                mGlowPadView.suspendAnimations();
+                mGlowPadView.ping();
                 getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
                 vibrate();
             }
@@ -299,7 +300,7 @@
     public void setStatusBarView(final View statusBarView) {
         if (mStatusBarTouchProxy != null) {
             mStatusBarTouchProxy.setStatusBar(statusBarView);
-//            mMultiWaveView.setOnTouchListener(new OnTouchListener() {
+//            mGlowPadView.setOnTouchListener(new OnTouchListener() {
 //                public boolean onTouch(View v, MotionEvent event) {
 //                    return statusBarView.onTouchEvent(event);
 //                }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 8df9b85..9b46af8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -404,6 +404,7 @@
         mRecentsPanel.updateValuesFromResources();
         mShowSearchHoldoff = mContext.getResources().getInteger(
                 R.integer.config_show_search_delay);
+        updateSearchPanel();
     }
 
     protected void loadDimens() {
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index d37207c..c9388cb 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -23,7 +23,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.SlidingTab;
 import com.android.internal.widget.WaveView;
-import com.android.internal.widget.multiwaveview.MultiWaveView;
+import com.android.internal.widget.multiwaveview.GlowPadView;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -286,16 +286,16 @@
         return mSearchManager;
     }
 
-    class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
+    class GlowPadViewMethods implements GlowPadView.OnTriggerListener,
             UnlockWidgetCommonMethods {
-        private final MultiWaveView mMultiWaveView;
+        private final GlowPadView mGlowPadView;
 
-        MultiWaveViewMethods(MultiWaveView multiWaveView) {
-            mMultiWaveView = multiWaveView;
+        GlowPadViewMethods(GlowPadView glowPadView) {
+            mGlowPadView = glowPadView;
         }
 
         public boolean isTargetPresent(int resId) {
-            return mMultiWaveView.getTargetPosition(resId) != -1;
+            return mGlowPadView.getTargetPosition(resId) != -1;
         }
 
         public void updateResources() {
@@ -307,8 +307,8 @@
             } else {
                 resId = R.array.lockscreen_targets_with_camera;
             }
-            if (mMultiWaveView.getTargetResourceId() != resId) {
-                mMultiWaveView.setTargetResources(resId);
+            if (mGlowPadView.getTargetResourceId() != resId) {
+                mGlowPadView.setTargetResources(resId);
             }
 
             // Update the search icon with drawable from the search .apk
@@ -317,7 +317,7 @@
                 if (searchManager != null) {
                     ComponentName component = searchManager.getGlobalSearchActivity();
                     if (component != null) {
-                        if (!mMultiWaveView.replaceTargetDrawablesIfPresent(component,
+                        if (!mGlowPadView.replaceTargetDrawablesIfPresent(component,
                                 ASSIST_ICON_METADATA_NAME,
                                 com.android.internal.R.drawable.ic_lockscreen_search)) {
                             Slog.w(TAG, "Couldn't grab icon from package " + component);
@@ -343,7 +343,7 @@
         }
 
         public void onTrigger(View v, int target) {
-            final int resId = mMultiWaveView.getResourceIdForTarget(target);
+            final int resId = mGlowPadView.getResourceIdForTarget(target);
             switch (resId) {
                 case com.android.internal.R.drawable.ic_lockscreen_search:
                     Intent assistIntent = getAssistIntent();
@@ -393,33 +393,33 @@
             // Don't poke the wake lock when returning to a state where the handle is
             // not grabbed since that can happen when the system (instead of the user)
             // cancels the grab.
-            if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) {
+            if (handle != GlowPadView.OnTriggerListener.NO_HANDLE) {
                 mCallback.pokeWakelock();
             }
         }
 
         public View getView() {
-            return mMultiWaveView;
+            return mGlowPadView;
         }
 
         public void reset(boolean animate) {
-            mMultiWaveView.reset(animate);
+            mGlowPadView.reset(animate);
         }
 
         public void ping() {
-            mMultiWaveView.ping();
+            mGlowPadView.ping();
         }
 
         public void setEnabled(int resourceId, boolean enabled) {
-            mMultiWaveView.setEnableTarget(resourceId, enabled);
+            mGlowPadView.setEnableTarget(resourceId, enabled);
         }
 
         public int getTargetPosition(int resourceId) {
-            return mMultiWaveView.getTargetPosition(resourceId);
+            return mGlowPadView.getTargetPosition(resourceId);
         }
 
         public void cleanUp() {
-            mMultiWaveView.setOnTriggerListener(null);
+            mGlowPadView.setOnTriggerListener(null);
         }
 
         public void onFinishFinalAnimation() {
@@ -531,11 +531,11 @@
             WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
             waveView.setOnTriggerListener(waveViewMethods);
             return waveViewMethods;
-        } else if (unlockWidget instanceof MultiWaveView) {
-            MultiWaveView multiWaveView = (MultiWaveView) unlockWidget;
-            MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
-            multiWaveView.setOnTriggerListener(multiWaveViewMethods);
-            return multiWaveViewMethods;
+        } else if (unlockWidget instanceof GlowPadView) {
+            GlowPadView glowPadView = (GlowPadView) unlockWidget;
+            GlowPadViewMethods glowPadViewMethods = new GlowPadViewMethods(glowPadView);
+            glowPadView.setOnTriggerListener(glowPadViewMethods);
+            return glowPadViewMethods;
         } else {
             throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget);
         }
@@ -545,12 +545,12 @@
         boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager()
                 .getCameraDisabled(null);
         boolean disabledBySimState = mUpdateMonitor.isSimLocked();
-        boolean cameraTargetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
-                ? ((MultiWaveViewMethods) mUnlockWidgetMethods)
+        boolean cameraTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods)
+                ? ((GlowPadViewMethods) mUnlockWidgetMethods)
                         .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera)
                         : false;
-        boolean searchTargetPresent = (mUnlockWidgetMethods instanceof MultiWaveViewMethods)
-                ? ((MultiWaveViewMethods) mUnlockWidgetMethods)
+        boolean searchTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods)
+                ? ((GlowPadViewMethods) mUnlockWidgetMethods)
                         .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_search)
                         : false;