FileDocCategorySizeDatePackage
KeyguardAffordanceView.javaAPI DocAndroid 5.1 API20204Thu Mar 12 22:22:42 GMT 2015com.android.systemui.statusbar

KeyguardAffordanceView

public class KeyguardAffordanceView extends android.widget.ImageView
An ImageView which does not have overlapping renderings commands and therefore does not need a layer when alpha is changed.

Fields Summary
private static final long
CIRCLE_APPEAR_DURATION
private static final long
CIRCLE_DISAPPEAR_MAX_DURATION
private static final long
NORMAL_ANIMATION_DURATION
public static final float
MAX_ICON_SCALE_AMOUNT
public static final float
MIN_ICON_SCALE_AMOUNT
private final int
mMinBackgroundRadius
private final android.graphics.Paint
mCirclePaint
private final android.view.animation.Interpolator
mAppearInterpolator
private final android.view.animation.Interpolator
mDisappearInterpolator
private final int
mInverseColor
private final int
mNormalColor
private final android.animation.ArgbEvaluator
mColorInterpolator
private final FlingAnimationUtils
mFlingAnimationUtils
private final android.graphics.drawable.Drawable
mArrowDrawable
private final int
mHintChevronPadding
private float
mCircleRadius
private int
mCenterX
private int
mCenterY
private android.animation.ValueAnimator
mCircleAnimator
private android.animation.ValueAnimator
mAlphaAnimator
private android.animation.ValueAnimator
mScaleAnimator
private android.animation.ValueAnimator
mArrowAnimator
private float
mCircleStartValue
private boolean
mCircleWillBeHidden
private int[]
mTempPoint
private float
mImageScale
private int
mCircleColor
private boolean
mIsLeft
private float
mArrowAlpha
private android.view.View
mPreviewView
private float
mCircleStartRadius
private float
mMaxCircleSize
private android.animation.Animator
mPreviewClipper
private android.animation.AnimatorListenerAdapter
mClipEndListener
private android.animation.AnimatorListenerAdapter
mCircleEndListener
private android.animation.AnimatorListenerAdapter
mScaleEndListener
private android.animation.AnimatorListenerAdapter
mAlphaEndListener
private android.animation.AnimatorListenerAdapter
mArrowEndListener
Constructors Summary
public KeyguardAffordanceView(android.content.Context context)


       
        this(context, null);
    
public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs)

        this(context, attrs, 0);
    
public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)

        this(context, attrs, defStyleAttr, 0);
    
public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)

        super(context, attrs, defStyleAttr, defStyleRes);
        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);
        mCircleColor = 0xffffffff;
        mCirclePaint.setColor(mCircleColor);

        mNormalColor = 0xffffffff;
        mInverseColor = 0xff000000;
        mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
                R.dimen.keyguard_affordance_min_background_radius);
        mHintChevronPadding = mContext.getResources().getDimensionPixelSize(
                R.dimen.hint_chevron_circle_padding);
        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
                android.R.interpolator.linear_out_slow_in);
        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
                android.R.interpolator.fast_out_linear_in);
        mColorInterpolator = new ArgbEvaluator();
        mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
        mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left);
        mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(),
                mArrowDrawable.getIntrinsicHeight());
    
Methods Summary
private voidcancelAnimator(android.animation.Animator animator)

        if (animator != null) {
            animator.cancel();
        }
    
private voiddrawArrow(android.graphics.Canvas canvas)

        if (mArrowAlpha > 0) {
            canvas.save();
            canvas.translate(mCenterX, mCenterY);
            if (mIsLeft) {
                canvas.scale(-1.0f, 1.0f);
            }
            canvas.translate(- mCircleRadius - mHintChevronPadding
                    - mArrowDrawable.getIntrinsicWidth() / 2,
                    - mArrowDrawable.getIntrinsicHeight() / 2);
            mArrowDrawable.setAlpha((int) (mArrowAlpha * 255));
            mArrowDrawable.draw(canvas);
            canvas.restore();
        }
    
private voiddrawBackgroundCircle(android.graphics.Canvas canvas)

        if (mCircleRadius > 0) {
            updateCircleColor();
            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint);
        }
    
public voidfinishAnimation(float velocity, java.lang.Runnable mAnimationEndRunnable)

        cancelAnimator(mCircleAnimator);
        cancelAnimator(mPreviewClipper);
        mCircleStartRadius = mCircleRadius;
        float maxCircleSize = getMaxCircleSize();
        ValueAnimator animatorToRadius = getAnimatorToRadius(maxCircleSize);
        mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize,
                velocity, maxCircleSize);
        animatorToRadius.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mAnimationEndRunnable.run();
            }
        });
        animatorToRadius.start();
        setImageAlpha(0, true);
        if (mPreviewView != null) {
            mPreviewView.setVisibility(View.VISIBLE);
            mPreviewClipper = ViewAnimationUtils.createCircularReveal(
                    mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
                    maxCircleSize);
            mFlingAnimationUtils.applyDismissing(mPreviewClipper, mCircleRadius, maxCircleSize,
                    velocity, maxCircleSize);
            mPreviewClipper.addListener(mClipEndListener);
            mPreviewClipper.start();
        }
    
private android.animation.ValueAnimatorgetAnimatorToRadius(float circleRadius)

        ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius);
        mCircleAnimator = animator;
        mCircleStartValue = mCircleRadius;
        mCircleWillBeHidden = circleRadius == 0.0f;
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCircleRadius = (float) animation.getAnimatedValue();
                updateIconColor();
                invalidate();
            }
        });
        animator.addListener(mCircleEndListener);
        return animator;
    
public floatgetCircleRadius()

        return mCircleRadius;
    
private Animator.AnimatorListenergetEndListener(java.lang.Runnable runnable)

        return new AnimatorListenerAdapter() {
            boolean mCancelled;
            @Override
            public void onAnimationCancel(Animator animation) {
                mCancelled = true;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!mCancelled) {
                    runnable.run();
                }
            }
        };
    
private floatgetMaxCircleSize()

        getLocationInWindow(mTempPoint);
        float rootWidth = getRootView().getWidth();
        float width = mTempPoint[0] + mCenterX;
        width = Math.max(rootWidth - width, width);
        float height = mTempPoint[1] + mCenterY;
        return (float) Math.hypot(width, height);
    
protected voidonDraw(android.graphics.Canvas canvas)

        drawBackgroundCircle(canvas);
        drawArrow(canvas);
        canvas.save();
        canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2);
        super.onDraw(canvas);
        canvas.restore();
    
protected voidonLayout(boolean changed, int left, int top, int right, int bottom)

        super.onLayout(changed, left, top, right, bottom);
        mCenterX = getWidth() / 2;
        mCenterY = getHeight() / 2;
        mMaxCircleSize = getMaxCircleSize();
    
public booleanperformClick()

        if (isClickable()) {
            return super.performClick();
        } else {
            return false;
        }
    
public voidsetCircleRadius(float circleRadius)

        setCircleRadius(circleRadius, false, false);
    
public voidsetCircleRadius(float circleRadius, boolean slowAnimation)

        setCircleRadius(circleRadius, slowAnimation, false);
    
private voidsetCircleRadius(float circleRadius, boolean slowAnimation, boolean noAnimation)


        // Check if we need a new animation
        boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden)
                || (mCircleAnimator == null && mCircleRadius == 0.0f);
        boolean nowHidden = circleRadius == 0.0f;
        boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation;
        if (!radiusNeedsAnimation) {
            if (mCircleAnimator == null) {
                mCircleRadius = circleRadius;
                updateIconColor();
                invalidate();
                if (nowHidden) {
                    if (mPreviewView != null) {
                        mPreviewView.setVisibility(View.INVISIBLE);
                    }
                }
            } else if (!mCircleWillBeHidden) {

                // We just update the end value
                float diff = circleRadius - mMinBackgroundRadius;
                PropertyValuesHolder[] values = mCircleAnimator.getValues();
                values[0].setFloatValues(mCircleStartValue + diff, circleRadius);
                mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime());
            }
        } else {
            cancelAnimator(mCircleAnimator);
            cancelAnimator(mPreviewClipper);
            ValueAnimator animator = getAnimatorToRadius(circleRadius);
            Interpolator interpolator = circleRadius == 0.0f
                    ? mDisappearInterpolator
                    : mAppearInterpolator;
            animator.setInterpolator(interpolator);
            long duration = 250;
            if (!slowAnimation) {
                float durationFactor = Math.abs(mCircleRadius - circleRadius)
                        / (float) mMinBackgroundRadius;
                duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor);
                duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION);
            }
            animator.setDuration(duration);
            animator.start();
            if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) {
                mPreviewView.setVisibility(View.VISIBLE);
                mPreviewClipper = ViewAnimationUtils.createCircularReveal(
                        mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
                        circleRadius);
                mPreviewClipper.setInterpolator(interpolator);
                mPreviewClipper.setDuration(duration);
                mPreviewClipper.addListener(mClipEndListener);
                mPreviewClipper.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mPreviewView.setVisibility(View.INVISIBLE);
                    }
                });
                mPreviewClipper.start();
            }
        }
    
public voidsetCircleRadiusWithoutAnimation(float circleRadius)

        cancelAnimator(mCircleAnimator);
        setCircleRadius(circleRadius, false ,true);
    
public voidsetImageAlpha(float alpha, boolean animate)

        setImageAlpha(alpha, animate, -1, null, null);
    
public voidsetImageAlpha(float alpha, boolean animate, long duration, android.view.animation.Interpolator interpolator, java.lang.Runnable runnable)
Sets the alpha of the containing image

param
alpha The new alpha.
param
animate Should an animation be performed
param
duration If animate, whats the duration? When -1 we take the default duration
param
interpolator If animate, whats the interpolator? When null we take the default interpolator.

        cancelAnimator(mAlphaAnimator);
        int endAlpha = (int) (alpha * 255);
        final Drawable background = getBackground();
        if (!animate) {
            if (background != null) background.mutate().setAlpha(endAlpha);
            setImageAlpha(endAlpha);
        } else {
            int currentAlpha = getImageAlpha();
            ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
            mAlphaAnimator = animator;
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int alpha = (int) animation.getAnimatedValue();
                    if (background != null) background.mutate().setAlpha(alpha);
                    setImageAlpha(alpha);
                }
            });
            animator.addListener(mAlphaEndListener);
            if (interpolator == null) {
                interpolator = alpha == 0.0f
                        ? mDisappearInterpolator
                        : mAppearInterpolator;
            }
            animator.setInterpolator(interpolator);
            if (duration == -1) {
                float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f;
                durationFactor = Math.min(1.0f, durationFactor);
                duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
            }
            animator.setDuration(duration);
            if (runnable != null) {
                animator.addListener(getEndListener(runnable));
            }
            animator.start();
        }
    
public voidsetImageScale(float imageScale, boolean animate)

        setImageScale(imageScale, animate, -1, null);
    
public voidsetImageScale(float imageScale, boolean animate, long duration, android.view.animation.Interpolator interpolator)
Sets the scale of the containing image

param
imageScale The new Scale.
param
animate Should an animation be performed
param
duration If animate, whats the duration? When -1 we take the default duration
param
interpolator If animate, whats the interpolator? When null we take the default interpolator.

        cancelAnimator(mScaleAnimator);
        if (!animate) {
            mImageScale = imageScale;
            invalidate();
        } else {
            ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale);
            mScaleAnimator = animator;
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mImageScale = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            animator.addListener(mScaleEndListener);
            if (interpolator == null) {
                interpolator = imageScale == 0.0f
                        ? mDisappearInterpolator
                        : mAppearInterpolator;
            }
            animator.setInterpolator(interpolator);
            if (duration == -1) {
                float durationFactor = Math.abs(mImageScale - imageScale)
                        / (1.0f - MIN_ICON_SCALE_AMOUNT);
                durationFactor = Math.min(1.0f, durationFactor);
                duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
            }
            animator.setDuration(duration);
            animator.start();
        }
    
public voidsetIsLeft(boolean left)

        mIsLeft = left;
    
public voidsetPreviewView(android.view.View v)

        mPreviewView = v;
        if (mPreviewView != null) {
            mPreviewView.setVisibility(INVISIBLE);
        }
    
public voidshowArrow(boolean show)

        cancelAnimator(mArrowAnimator);
        float targetAlpha = show ? 1.0f : 0.0f;
        if (mArrowAlpha == targetAlpha) {
            return;
        }
        ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha);
        mArrowAnimator = animator;
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mArrowAlpha = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.addListener(mArrowEndListener);
        Interpolator interpolator = show
                    ? mAppearInterpolator
                    : mDisappearInterpolator;
        animator.setInterpolator(interpolator);
        float durationFactor = Math.abs(mArrowAlpha - targetAlpha);
        long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
        animator.setDuration(duration);
        animator.start();
    
private voidupdateCircleColor()

        float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f,
                (mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius)));
        if (mPreviewView != null) {
            float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius)
                    / (mMaxCircleSize - mCircleStartRadius);
            fraction *= finishingFraction;
        }
        int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction),
                Color.red(mCircleColor),
                Color.green(mCircleColor), Color.blue(mCircleColor));
        mCirclePaint.setColor(color);
    
private voidupdateIconColor()

        Drawable drawable = getDrawable().mutate();
        float alpha = mCircleRadius / mMinBackgroundRadius;
        alpha = Math.min(1.0f, alpha);
        int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor);
        drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);