KeyguardGlowStripView.java revision 5ecd81154fa039961f65bb4e36d18ac555b0d1d6
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.keyguard;
17
18import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.ValueAnimator;
21import android.animation.ValueAnimator.AnimatorUpdateListener;
22import android.content.Context;
23import android.content.res.TypedArray;
24import android.graphics.Canvas;
25import android.graphics.drawable.Drawable;
26import android.util.AttributeSet;
27import android.view.animation.DecelerateInterpolator;
28import android.view.animation.Interpolator;
29import android.view.animation.LinearInterpolator;
30import android.widget.LinearLayout;
31
32/**
33 * A layout which animates a strip of horizontal, pulsing dots on request. This is used
34 * to indicate the presence of pages to the left / right.
35 */
36public class KeyguardGlowStripView extends LinearLayout {
37    private static final int DURATION = 500;
38
39    private static final float SLIDING_WINDOW_SIZE = 0.4f;
40    private int mDotStripTop;
41    private int mHorizontalDotGap;
42
43    private int mDotSize;
44    private int mNumDots;
45    private Drawable mDotDrawable;
46    private boolean mLeftToRight = true;
47
48    private float mAnimationProgress = 0f;
49    private boolean mDrawDots = false;
50    private ValueAnimator mAnimator;
51    private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f);
52
53    public KeyguardGlowStripView(Context context) {
54        this(context, null, 0);
55    }
56
57    public KeyguardGlowStripView(Context context, AttributeSet attrs) {
58        this(context, attrs, 0);
59    }
60
61    public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) {
62        super(context, attrs, defStyle);
63
64        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView);
65        mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize);
66        mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots);
67        mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot);
68        mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight);
69    }
70
71    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
72        int availableWidth = w - getPaddingLeft() - getPaddingRight();
73        mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) /  (mNumDots - 1);
74        mDotStripTop = getPaddingTop();
75        invalidate();
76    }
77
78    @Override
79    protected void dispatchDraw(Canvas canvas) {
80        super.dispatchDraw(canvas);
81
82        if (!mDrawDots) return;
83
84        int xOffset = getPaddingLeft();
85        mDotDrawable.setBounds(0, 0, mDotSize, mDotSize);
86
87        for (int i = 0; i < mNumDots; i++) {
88            // We fudge the relative position to provide a fade in of the first dot and a fade
89            // out of the final dot.
90            float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) *
91                    (1 - SLIDING_WINDOW_SIZE);
92            float distance = Math.abs(relativeDotPosition - mAnimationProgress);
93            float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2));
94
95            alpha = mDotAlphaInterpolator.getInterpolation(alpha);
96
97            canvas.save();
98            canvas.translate(xOffset, mDotStripTop);
99            mDotDrawable.setAlpha((int) (alpha * 255));
100            mDotDrawable.draw(canvas);
101            canvas.restore();
102            xOffset += mDotSize + mHorizontalDotGap;
103        }
104    }
105
106    public void makeEmGo() {
107        if (mAnimator != null) {
108            mAnimator.cancel();
109        }
110        float from = mLeftToRight ? 0f : 1f;
111        float to = mLeftToRight ? 1f : 0f;
112        mAnimator = ValueAnimator.ofFloat(from, to);
113        mAnimator.setDuration(DURATION);
114        mAnimator.setInterpolator(new LinearInterpolator());
115        mAnimator.addListener(new AnimatorListenerAdapter() {
116            @Override
117            public void onAnimationEnd(Animator animation) {
118                mDrawDots = false;
119                // make sure we draw one frame at the end with everything gone.
120                invalidate();
121            }
122
123            @Override
124            public void onAnimationStart(Animator animation) {
125                mDrawDots = true;
126            }
127        });
128        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
129            @Override
130            public void onAnimationUpdate(ValueAnimator animation) {
131                mAnimationProgress = (Float) animation.getAnimatedValue();
132                invalidate();
133            }
134        });
135        mAnimator.start();
136    }
137}
138