blob: 98a44a6ca6d02a84879b47486bbfa4658da1b9cd [file] [log] [blame]
Jim Millerc1aa6a52012-09-28 19:37:26 -07001/*
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 */
Jim Miller5ecd8112013-01-09 18:50:26 -080016package com.android.keyguard;
Jim Millerc1aa6a52012-09-28 19:37:26 -070017
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
Jim Millerc1aa6a52012-09-28 19:37:26 -070032/**
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}