From 072707dfad1da6f49f4d3ce58ca104f6c46a7266 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 15 Sep 2014 17:20:08 +0200 Subject: [PATCH] Use RenderThread for navigation bar ripples Bug: 17506181 Change-Id: Icf3b80f8c4bc29fe85313381d4019dda3ef85ea9 --- core/java/android/view/GLES20Canvas.java | 13 + core/java/android/view/HardwareCanvas.java | 5 + core/jni/android_view_GLES20Canvas.cpp | 15 + libs/hwui/DisplayListOp.h | 28 ++ libs/hwui/DisplayListRenderer.cpp | 17 + libs/hwui/DisplayListRenderer.h | 4 + packages/SystemUI/proguard.flags | 5 +- packages/SystemUI/res/values/dimens.xml | 3 + .../statusbar/policy/KeyButtonRipple.java | 361 ++++++++++++++++++ .../statusbar/policy/KeyButtonView.java | 128 +------ 10 files changed, 457 insertions(+), 122 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 076f1e29fd32d..1b57c242b5578 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -724,6 +724,19 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint); + @Override + public void drawRoundRect(CanvasProperty left, CanvasProperty top, + CanvasProperty right, CanvasProperty bottom, CanvasProperty rx, + CanvasProperty ry, CanvasProperty paint) { + nDrawRoundRect(mRenderer, left.getNativeContainer(), top.getNativeContainer(), + right.getNativeContainer(), bottom.getNativeContainer(), + rx.getNativeContainer(), ry.getNativeContainer(), + paint.getNativeContainer()); + } + + private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, + long propRight, long propBottom, long propRx, long propRy, long propPaint); + @Override public void drawColor(int color) { drawColor(color, PorterDuff.Mode.SRC_OVER); diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index c17296920599d..e3eee71f25c51 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -113,6 +113,11 @@ public abstract class HardwareCanvas extends Canvas { public abstract void drawCircle(CanvasProperty cx, CanvasProperty cy, CanvasProperty radius, CanvasProperty paint); + public abstract void drawRoundRect(CanvasProperty left, CanvasProperty top, + CanvasProperty right, CanvasProperty bottom, + CanvasProperty rx, CanvasProperty ry, + CanvasProperty paint); + public static void setProperty(String name, String value) { GLES20Canvas.setProperty(name, value); } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 6080f2a21b160..2e2b23f25d3d7 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -480,6 +480,20 @@ static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject clazz, renderer->drawRoundRect(left, top, right, bottom, rx, ry, paint); } +static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject clazz, + jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr, + jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) { + DisplayListRenderer* renderer = reinterpret_cast(rendererPtr); + CanvasPropertyPrimitive* leftProp = reinterpret_cast(leftPropPtr); + CanvasPropertyPrimitive* topProp = reinterpret_cast(topPropPtr); + CanvasPropertyPrimitive* rightProp = reinterpret_cast(rightPropPtr); + CanvasPropertyPrimitive* bottomProp = reinterpret_cast(bottomPropPtr); + CanvasPropertyPrimitive* rxProp = reinterpret_cast(rxPropPtr); + CanvasPropertyPrimitive* ryProp = reinterpret_cast(ryPropPtr); + CanvasPropertyPaint* paintProp = reinterpret_cast(paintPropPtr); + renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp); +} + static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat x, jfloat y, jfloat radius, jlong paintPtr) { DisplayListRenderer* renderer = reinterpret_cast(rendererPtr); @@ -912,6 +926,7 @@ static JNINativeMethod gMethods[] = { { "nDrawRect", "(JFFFFJ)V", (void*) android_view_GLES20Canvas_drawRect }, { "nDrawRects", "(JJJ)V", (void*) android_view_GLES20Canvas_drawRegionAsRects }, { "nDrawRoundRect", "(JFFFFFFJ)V", (void*) android_view_GLES20Canvas_drawRoundRect }, + { "nDrawRoundRect", "(JJJJJJJJ)V", (void*) android_view_GLES20Canvas_drawRoundRectProps }, { "nDrawCircle", "(JFFFJ)V", (void*) android_view_GLES20Canvas_drawCircle }, { "nDrawCircle", "(JJJJJ)V", (void*) android_view_GLES20Canvas_drawCircleProps }, { "nDrawOval", "(JFFFFJ)V", (void*) android_view_GLES20Canvas_drawOval }, diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 5ff7b7f004650..cb3ef9b962a1c 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1105,6 +1105,34 @@ private: float mRy; }; +class DrawRoundRectPropsOp : public DrawOp { +public: + DrawRoundRectPropsOp(float* left, float* top, float* right, float* bottom, + float *rx, float *ry, const SkPaint* paint) + : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom), + mRx(rx), mRy(ry) {} + + virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { + return renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom, + *mRx, *mRy, getPaint(renderer)); + } + + virtual void output(int level, uint32_t logFlags) const { + OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f", + *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy); + } + + virtual const char* name() { return "DrawRoundRectProps"; } + +private: + float* mLeft; + float* mTop; + float* mRight; + float* mBottom; + float* mRx; + float* mRy; +}; + class DrawCircleOp : public DrawStrokableOp { public: DrawCircleOp(float x, float y, float radius, const SkPaint* paint) diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 7ee83e609d10a..1f7092147686c 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -275,6 +275,23 @@ status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, return DrawGlInfo::kStatusDone; } +status_t DisplayListRenderer::drawRoundRect( + CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint) { + mDisplayListData->refProperty(left); + mDisplayListData->refProperty(top); + mDisplayListData->refProperty(right); + mDisplayListData->refProperty(bottom); + mDisplayListData->refProperty(rx); + mDisplayListData->refProperty(ry); + mDisplayListData->refProperty(paint); + addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value, + &right->value, &bottom->value, &rx->value, &ry->value, &paint->value)); + return DrawGlInfo::kStatusDone; +} + status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint* paint) { paint = refPaint(paint); addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint)); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index e9c937cbeb0c6..3a3fc3af9f0fa 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -123,6 +123,10 @@ public: virtual status_t drawRects(const float* rects, int count, const SkPaint* paint); virtual status_t drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, const SkPaint* paint); + virtual status_t drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint); virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint); virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint); diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index c9e16180b42f7..47e24e8e82f3c 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -1,8 +1,11 @@ -keep class com.android.systemui.statusbar.policy.KeyButtonView { public float getDrawingAlpha(); + public void setDrawingAlpha(float); +} + +-keep class com.android.systemui.statusbar.policy.KeyButtonRipple { public float getGlowAlpha(); public float getGlowScale(); - public void setDrawingAlpha(float); public void setGlowAlpha(float); public void setGlowScale(float); } diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8fe0af8fe0e82..37ee0aea13019 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -489,4 +489,7 @@ 3dp + + + 95dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java new file mode 100644 index 0000000000000..a3765aa9a8fe0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.policy; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.CanvasProperty; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.view.HardwareCanvas; +import android.view.RenderNodeAnimator; +import android.view.View; +import android.view.animation.Interpolator; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.PhoneStatusBar; + +import java.util.ArrayList; +import java.util.HashSet; + +public class KeyButtonRipple extends Drawable { + + private static final float GLOW_MAX_SCALE_FACTOR = 1.35f; + private static final float GLOW_MAX_ALPHA = 0.2f; + private static final int ANIMATION_DURATION_SCALE = 350; + private static final int ANIMATION_DURATION_FADE = 450; + + private Paint mRipplePaint; + private CanvasProperty mLeftProp; + private CanvasProperty mTopProp; + private CanvasProperty mRightProp; + private CanvasProperty mBottomProp; + private CanvasProperty mRxProp; + private CanvasProperty mRyProp; + private CanvasProperty mPaintProp; + private float mGlowAlpha = 0f; + private float mGlowScale = 1f; + private boolean mPressed; + private boolean mDrawingHardwareGlow; + private int mMaxWidth; + + private final Interpolator mInterpolator = new LogInterpolator(); + private final Interpolator mAlphaExitInterpolator = PhoneStatusBar.ALPHA_OUT; + private boolean mSupportHardware; + private final View mTargetView; + + private final HashSet mRunningAnimations = new HashSet<>(); + private final ArrayList mTmpArray = new ArrayList<>(); + + public KeyButtonRipple(Context ctx, View targetView) { + mMaxWidth = ctx.getResources().getDimensionPixelSize(R.dimen.key_button_ripple_max_width); + mTargetView = targetView; + } + + private Paint getRipplePaint() { + if (mRipplePaint == null) { + mRipplePaint = new Paint(); + mRipplePaint.setAntiAlias(true); + mRipplePaint.setColor(0xffffffff); + } + return mRipplePaint; + } + + private void drawSoftware(Canvas canvas) { + if (mGlowAlpha > 0f) { + final Paint p = getRipplePaint(); + p.setAlpha((int)(mGlowAlpha * 255f)); + + final float w = getBounds().width(); + final float h = getBounds().height(); + final boolean horizontal = w > h; + final float diameter = getRippleSize() * mGlowScale; + final float radius = diameter * .5f; + final float cx = w * .5f; + final float cy = h * .5f; + final float rx = horizontal ? radius : cx; + final float ry = horizontal ? cy : radius; + final float corner = horizontal ? cy : cx; + + canvas.drawRoundRect(cx - rx, cy - ry, + cx + rx, cy + ry, + corner, corner, p); + } + } + + + @Override + public void draw(Canvas canvas) { + mSupportHardware = canvas.isHardwareAccelerated(); + if (mSupportHardware) { + drawHardware((HardwareCanvas) canvas); + } else { + drawSoftware(canvas); + } + } + + @Override + public void setAlpha(int alpha) { + // Not supported. + } + + @Override + public void setColorFilter(ColorFilter cf) { + // Not supported. + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + private boolean isHorizontal() { + return getBounds().width() > getBounds().height(); + } + + private void drawHardware(HardwareCanvas c) { + if (mDrawingHardwareGlow) { + c.drawRoundRect(mLeftProp, mTopProp, mRightProp, mBottomProp, mRxProp, mRyProp, + mPaintProp); + } + } + + public float getGlowAlpha() { + return mGlowAlpha; + } + + public void setGlowAlpha(float x) { + mGlowAlpha = x; + invalidateSelf(); + } + + public float getGlowScale() { + return mGlowScale; + } + + public void setGlowScale(float x) { + mGlowScale = x; + invalidateSelf(); + } + + @Override + protected boolean onStateChange(int[] state) { + boolean pressed = false; + for (int i = 0; i < state.length; i++) { + if (state[i] == android.R.attr.state_pressed) { + pressed = true; + break; + } + } + if (pressed != mPressed) { + setPressed(pressed); + mPressed = pressed; + return true; + } else { + return false; + } + } + + @Override + public boolean isStateful() { + return true; + } + + public void setPressed(boolean pressed) { + if (mSupportHardware) { + setPressedHardware(pressed); + } else { + setPressedSoftware(pressed); + } + } + + private void cancelAnimations() { + mTmpArray.addAll(mRunningAnimations); + int size = mTmpArray.size(); + for (int i = 0; i < size; i++) { + Animator a = mTmpArray.get(i); + a.cancel(); + } + mTmpArray.clear(); + mRunningAnimations.clear(); + } + + private void setPressedSoftware(boolean pressed) { + if (pressed) { + enterSoftware(); + } else { + exitSoftware(); + } + } + + private void enterSoftware() { + cancelAnimations(); + mGlowAlpha = GLOW_MAX_ALPHA; + ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale", + 0f, GLOW_MAX_SCALE_FACTOR); + scaleAnimator.setInterpolator(mInterpolator); + scaleAnimator.setDuration(ANIMATION_DURATION_SCALE); + scaleAnimator.addListener(mAnimatorListener); + scaleAnimator.start(); + mRunningAnimations.add(scaleAnimator); + } + + private void exitSoftware() { + ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f); + alphaAnimator.setInterpolator(mAlphaExitInterpolator); + alphaAnimator.setDuration(ANIMATION_DURATION_FADE); + alphaAnimator.addListener(mAnimatorListener); + alphaAnimator.start(); + mRunningAnimations.add(alphaAnimator); + } + + private void setPressedHardware(boolean pressed) { + if (pressed) { + enterHardware(); + } else { + exitHardware(); + } + } + + /** + * Sets the left/top property for the round rect to {@code prop} depending on whether we are + * horizontal or vertical mode. + */ + private void setExtendStart(CanvasProperty prop) { + if (isHorizontal()) { + mLeftProp = prop; + } else { + mTopProp = prop; + } + } + + private CanvasProperty getExtendStart() { + return isHorizontal() ? mLeftProp : mTopProp; + } + + /** + * Sets the right/bottom property for the round rect to {@code prop} depending on whether we are + * horizontal or vertical mode. + */ + private void setExtendEnd(CanvasProperty prop) { + if (isHorizontal()) { + mRightProp = prop; + } else { + mBottomProp = prop; + } + } + + private CanvasProperty getExtendEnd() { + return isHorizontal() ? mRightProp : mBottomProp; + } + + private int getExtendSize() { + return isHorizontal() ? getBounds().width() : getBounds().height(); + } + + private int getRippleSize() { + int size = isHorizontal() ? getBounds().width() : getBounds().height(); + return Math.min(size, mMaxWidth); + } + + private void enterHardware() { + cancelAnimations(); + mDrawingHardwareGlow = true; + setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2)); + final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(), + getExtendSize()/2 - GLOW_MAX_SCALE_FACTOR * getRippleSize()/2); + startAnim.setDuration(ANIMATION_DURATION_SCALE); + startAnim.setInterpolator(mInterpolator); + startAnim.addListener(mAnimatorListener); + startAnim.setTarget(mTargetView); + + setExtendEnd(CanvasProperty.createFloat(getExtendSize() / 2)); + final RenderNodeAnimator endAnim = new RenderNodeAnimator(getExtendEnd(), + getExtendSize()/2 + GLOW_MAX_SCALE_FACTOR * getRippleSize()/2); + endAnim.setDuration(ANIMATION_DURATION_SCALE); + endAnim.setInterpolator(mInterpolator); + endAnim.addListener(mAnimatorListener); + endAnim.setTarget(mTargetView); + + if (isHorizontal()) { + mTopProp = CanvasProperty.createFloat(0f); + mBottomProp = CanvasProperty.createFloat(getBounds().height()); + mRxProp = CanvasProperty.createFloat(getBounds().height()/2); + mRyProp = CanvasProperty.createFloat(getBounds().height()/2); + } else { + mLeftProp = CanvasProperty.createFloat(0f); + mRightProp = CanvasProperty.createFloat(getBounds().width()); + mRxProp = CanvasProperty.createFloat(getBounds().width()/2); + mRyProp = CanvasProperty.createFloat(getBounds().width()/2); + } + + mGlowScale = GLOW_MAX_SCALE_FACTOR; + mGlowAlpha = GLOW_MAX_ALPHA; + mRipplePaint = getRipplePaint(); + mRipplePaint.setAlpha((int) (mGlowAlpha * 255)); + mPaintProp = CanvasProperty.createPaint(mRipplePaint); + + startAnim.start(); + endAnim.start(); + mRunningAnimations.add(startAnim); + mRunningAnimations.add(endAnim); + + invalidateSelf(); + } + + private void exitHardware() { + mPaintProp = CanvasProperty.createPaint(getRipplePaint()); + final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp, + RenderNodeAnimator.PAINT_ALPHA, 0); + opacityAnim.setDuration(ANIMATION_DURATION_FADE); + opacityAnim.setInterpolator(mAlphaExitInterpolator); + opacityAnim.addListener(mAnimatorListener); + opacityAnim.setTarget(mTargetView); + + opacityAnim.start(); + mRunningAnimations.add(opacityAnim); + + invalidateSelf(); + } + + private final AnimatorListenerAdapter mAnimatorListener = + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mRunningAnimations.remove(animation); + if (mRunningAnimations.isEmpty() && !mPressed) { + mDrawingHardwareGlow = false; + invalidateSelf(); + } + } + }; + + /** + * Interpolator with a smooth log deceleration + */ + private static final class LogInterpolator implements Interpolator { + @Override + public float getInterpolation(float input) { + return 1 - (float) Math.pow(400, -input * 1.4); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index b814b61ce6566..7cc75da1db537 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -24,6 +24,7 @@ import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.RectF; import android.hardware.input.InputManager; @@ -32,11 +33,14 @@ import android.os.Bundle; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; +import android.util.MathUtils; import android.view.HapticFeedbackConstants; +import android.view.HardwareCanvas; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.RenderNodeAnimator; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewConfiguration; @@ -44,6 +48,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; import java.lang.Math; +import java.util.ArrayList; import com.android.systemui.R; @@ -56,22 +61,15 @@ public class KeyButtonView extends ImageView { // TODO: Get rid of this public static final float DEFAULT_QUIESCENT_ALPHA = 1f; - public static final float MAX_ALPHA = 0.15f; - public static final float GLOW_MAX_SCALE_FACTOR = 1.5f; private long mDownTime; private int mCode; private int mTouchSlop; - private float mGlowAlpha = 0f; - private float mGlowScale = 1f; private float mDrawingAlpha = 1f; private float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA; private boolean mSupportsLongpress = true; - private AnimatorSet mPressedAnim; - private Animator mAnimateToQuiescent = new ObjectAnimator(); - private Paint mRipplePaint; - private final TimeInterpolator mInterpolator = (TimeInterpolator) new LogInterpolator(); private AudioManager mAudioManager; + private Animator mAnimateToQuiescent = new ObjectAnimator(); private final Runnable mCheckLongPress = new Runnable() { public void run() { @@ -110,6 +108,7 @@ public class KeyButtonView extends ImageView { setClickable(true); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + setBackground(new KeyButtonRipple(context, this)); } @Override @@ -141,38 +140,6 @@ public class KeyButtonView extends ImageView { return super.performAccessibilityAction(action, arguments); } - private Paint getRipplePaint() { - if (mRipplePaint == null) { - mRipplePaint = new Paint(); - mRipplePaint.setAntiAlias(true); - mRipplePaint.setColor(0xffffffff); - } - return mRipplePaint; - } - - @Override - protected void onDraw(Canvas canvas) { - final Paint p = getRipplePaint(); - p.setAlpha((int)(MAX_ALPHA * mDrawingAlpha * mGlowAlpha * 255)); - - final float w = getWidth(); - final float h = getHeight(); - final boolean horizontal = w > h; - final float diameter = (horizontal ? w : h) * mGlowScale; - final float radius = diameter * .5f; - final float cx = w * .5f; - final float cy = h * .5f; - final float rx = horizontal ? radius : cx; - final float ry = horizontal ? cy : radius; - final float corner = horizontal ? cy : cx; - - canvas.drawRoundRect(cx - rx, cy - ry, - cx + rx, cy + ry, - corner, corner, p); - - super.onDraw(canvas); - } - public void setQuiescentAlpha(float alpha, boolean animate) { mAnimateToQuiescent.cancel(); alpha = Math.min(Math.max(alpha, 0), 1); @@ -204,76 +171,6 @@ public class KeyButtonView extends ImageView { mDrawingAlpha = x; } - public float getGlowAlpha() { - return mGlowAlpha; - } - - public void setGlowAlpha(float x) { - mGlowAlpha = x; - invalidate(); - } - - public float getGlowScale() { - return mGlowScale; - } - - public void setGlowScale(float x) { - mGlowScale = x; - final float w = getWidth(); - final float h = getHeight(); - if (GLOW_MAX_SCALE_FACTOR <= 1.0f) { - // this only works if we know the glow will never leave our bounds - invalidate(); - } else { - final float rx = (w * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f; - final float ry = (h * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f; - com.android.systemui.SwipeHelper.invalidateGlobalRegion( - this, - new RectF(getLeft() - rx, - getTop() - ry, - getRight() + rx, - getBottom() + ry)); - - // also invalidate our immediate parent to help avoid situations where nearby glows - // interfere - ((View)getParent()).invalidate(); - } - } - - public void setPressed(boolean pressed) { - if (pressed != isPressed()) { - if (mPressedAnim != null && mPressedAnim.isRunning()) { - mPressedAnim.cancel(); - } - final AnimatorSet as = mPressedAnim = new AnimatorSet(); - final ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, - "glowScale", GLOW_MAX_SCALE_FACTOR); - scaleAnimator.setInterpolator(mInterpolator); - if (pressed) { - mGlowScale = 0f; - if (mGlowAlpha < mQuiescentAlpha) - mGlowAlpha = mQuiescentAlpha; - setDrawingAlpha(1f); - as.playTogether( - ObjectAnimator.ofFloat(this, "glowAlpha", 1f), - scaleAnimator - ); - as.setDuration(500); - } else { - mAnimateToQuiescent.cancel(); - mAnimateToQuiescent = animateToQuiescent(); - as.playTogether( - ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, mGlowAlpha * .2f, 0f), - scaleAnimator, - mAnimateToQuiescent - ); - as.setDuration(500); - } - as.start(); - } - super.setPressed(pressed); - } - public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); int x, y; @@ -354,17 +251,6 @@ public class KeyButtonView extends ImageView { InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); } - - /** - * Interpolator with a smooth log deceleration - */ - private static final class LogInterpolator implements TimeInterpolator { - @Override - public float getInterpolation(float input) { - return 1 - (float) Math.pow(400, -input * 1.4); - } - } - }