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.internal.policy.impl.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 32import com.android.internal.R; 33 34/** 35 * A layout which animates a strip of horizontal, pulsing dots on request. This is used 36 * to indicate the presence of pages to the left / right. 37 */ 38public class KeyguardGlowStripView extends LinearLayout { 39 private static final int DURATION = 500; 40 41 private static final float SLIDING_WINDOW_SIZE = 0.4f; 42 private int mDotStripTop; 43 private int mHorizontalDotGap; 44 45 private int mDotSize; 46 private int mNumDots; 47 private Drawable mDotDrawable; 48 private boolean mLeftToRight = true; 49 50 private float mAnimationProgress = 0f; 51 private boolean mDrawDots = false; 52 private ValueAnimator mAnimator; 53 private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f); 54 55 public KeyguardGlowStripView(Context context) { 56 this(context, null, 0); 57 } 58 59 public KeyguardGlowStripView(Context context, AttributeSet attrs) { 60 this(context, attrs, 0); 61 } 62 63 public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) { 64 super(context, attrs, defStyle); 65 66 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView); 67 mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize); 68 mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots); 69 mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot); 70 mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight); 71 } 72 73 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 74 int availableWidth = w - getPaddingLeft() - getPaddingRight(); 75 mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) / (mNumDots - 1); 76 mDotStripTop = getPaddingTop(); 77 invalidate(); 78 } 79 80 @Override 81 protected void dispatchDraw(Canvas canvas) { 82 super.dispatchDraw(canvas); 83 84 if (!mDrawDots) return; 85 86 int xOffset = getPaddingLeft(); 87 mDotDrawable.setBounds(0, 0, mDotSize, mDotSize); 88 89 for (int i = 0; i < mNumDots; i++) { 90 // We fudge the relative position to provide a fade in of the first dot and a fade 91 // out of the final dot. 92 float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) * 93 (1 - SLIDING_WINDOW_SIZE); 94 float distance = Math.abs(relativeDotPosition - mAnimationProgress); 95 float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2)); 96 97 alpha = mDotAlphaInterpolator.getInterpolation(alpha); 98 99 canvas.save(); 100 canvas.translate(xOffset, mDotStripTop); 101 mDotDrawable.setAlpha((int) (alpha * 255)); 102 mDotDrawable.draw(canvas); 103 canvas.restore(); 104 xOffset += mDotSize + mHorizontalDotGap; 105 } 106 } 107 108 public void makeEmGo() { 109 if (mAnimator != null) { 110 mAnimator.cancel(); 111 } 112 float from = mLeftToRight ? 0f : 1f; 113 float to = mLeftToRight ? 1f : 0f; 114 mAnimator = ValueAnimator.ofFloat(from, to); 115 mAnimator.setDuration(DURATION); 116 mAnimator.setInterpolator(new LinearInterpolator()); 117 mAnimator.addListener(new AnimatorListenerAdapter() { 118 @Override 119 public void onAnimationEnd(Animator animation) { 120 mDrawDots = false; 121 // make sure we draw one frame at the end with everything gone. 122 invalidate(); 123 } 124 125 @Override 126 public void onAnimationStart(Animator animation) { 127 mDrawDots = true; 128 } 129 }); 130 mAnimator.addUpdateListener(new AnimatorUpdateListener() { 131 @Override 132 public void onAnimationUpdate(ValueAnimator animation) { 133 mAnimationProgress = (Float) animation.getAnimatedValue(); 134 invalidate(); 135 } 136 }); 137 mAnimator.start(); 138 } 139} 140