public SoundLevels(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); // Safe source, replaced with system one when attached. mLevelSource = new AudioLevelSource(); mLevelSource.setSpeechLevel(0); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SoundLevels, defStyle, 0); mMaximumLevelSize = a.getDimensionPixelOffset(R.styleable.SoundLevels_maxLevelRadius, 0); mMinimumLevelSize = a.getDimensionPixelOffset(R.styleable.SoundLevels_minLevelRadius, 0); mMinimumLevel = mMinimumLevelSize / mMaximumLevelSize; mPrimaryLevelPaint = new Paint(); mPrimaryLevelPaint.setColor(a.getColor(R.styleable.SoundLevels_primaryColor, Color.BLACK)); mPrimaryLevelPaint.setFlags(Paint.ANTI_ALIAS_FLAG); a.recycle(); // This animator generates ticks that invalidate the // view so that the animation is synced with the global animation loop. // TODO: We could probably remove this in favor of using postInvalidateOnAnimation // which might improve things further. mSpeechLevelsAnimator = new TimeAnimator(); mSpeechLevelsAnimator.setRepeatCount(ObjectAnimator.INFINITE); mSpeechLevelsAnimator.setTimeListener( new TimeListener() { @Override public void onTimeUpdate( final TimeAnimator animation, final long totalTime, final long deltaTime) { invalidate(); } }); }
public PanelView(Context context, AttributeSet attrs) { super(context, attrs); mTimeAnimator = new TimeAnimator(); mTimeAnimator.setTimeListener(mAnimationCallback); }
private void animationTick(long dtms) { if (!mTimeAnimator.isStarted()) { // XXX HAX to work around bug in TimeAnimator.end() not resetting its last time mTimeAnimator = new TimeAnimator(); mTimeAnimator.setTimeListener(mAnimationCallback); if (mPeekAnimator != null) mPeekAnimator.cancel(); mTimeAnimator.start(); mRubberbanding = mRubberbandingEnabled // is it enabled at all? && mExpandedHeight > getFullHeight() // are we past the end? && mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture? if (mRubberbanding) { mClosing = true; } else if (mVel == 0) { // if the panel is less than halfway open, close it mClosing = (mFinalTouchY / getFullHeight()) < 0.5f; } else { mClosing = mExpandedHeight > 0 && mVel < 0; } } else if (dtms > 0) { final float dt = dtms * 0.001f; // ms -> s if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt); if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight); final float fh = getFullHeight(); boolean braking = false; if (BRAKES) { if (mClosing) { braking = mExpandedHeight <= mCollapseBrakingDistancePx; mAccel = braking ? 10 * mCollapseAccelPx : -mCollapseAccelPx; } else { braking = mExpandedHeight >= (fh - mExpandBrakingDistancePx); mAccel = braking ? 10 * -mExpandAccelPx : mExpandAccelPx; } } else { mAccel = mClosing ? -mCollapseAccelPx : mExpandAccelPx; } mVel += mAccel * dt; if (braking) { if (mClosing && mVel > -mBrakingSpeedPx) { mVel = -mBrakingSpeedPx; } else if (!mClosing && mVel < mBrakingSpeedPx) { mVel = mBrakingSpeedPx; } } else { if (mClosing && mVel > -mFlingCollapseMinVelocityPx) { mVel = -mFlingCollapseMinVelocityPx; } else if (!mClosing && mVel > mFlingGestureMaxOutputVelocityPx) { mVel = mFlingGestureMaxOutputVelocityPx; } } float h = mExpandedHeight + mVel * dt; if (mRubberbanding && h < fh) { h = fh; } if (DEBUG) LOG("tick: new h=%d closing=%s", (int) h, mClosing ? "true" : "false"); setExpandedHeightInternal(h); mBar.panelExpansionChanged(PanelView.this, mExpandedFraction); if (mVel == 0 || (mClosing && mExpandedHeight == 0) || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) { post(mStopAnimator); } } }