Use RenderThread for navigation bar ripples

Bug: 17506181
Change-Id: Icf3b80f8c4bc29fe85313381d4019dda3ef85ea9
This commit is contained in:
Jorim Jaggi
2014-09-15 17:20:08 +02:00
parent 9ed2d5f746
commit 072707dfad
10 changed files with 457 additions and 122 deletions

View File

@@ -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<Float> left, CanvasProperty<Float> top,
CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
CanvasProperty<Float> ry, CanvasProperty<Paint> 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);

View File

@@ -113,6 +113,11 @@ public abstract class HardwareCanvas extends Canvas {
public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
public abstract void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
CanvasProperty<Float> right, CanvasProperty<Float> bottom,
CanvasProperty<Float> rx, CanvasProperty<Float> ry,
CanvasProperty<Paint> paint);
public static void setProperty(String name, String value) {
GLES20Canvas.setProperty(name, value);
}

View File

@@ -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<DisplayListRenderer*>(rendererPtr);
CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(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<DisplayListRenderer*>(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 },

View File

@@ -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)

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -489,4 +489,7 @@
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide for the tile in quick settings. -->
<dimen name="wide_type_icon_start_padding_qs">3dp</dimen>
<!-- The maximum width of the navigation bar ripples. -->
<dimen name="key_button_ripple_max_width">95dp</dimen>
</resources>

View File

@@ -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<Float> mLeftProp;
private CanvasProperty<Float> mTopProp;
private CanvasProperty<Float> mRightProp;
private CanvasProperty<Float> mBottomProp;
private CanvasProperty<Float> mRxProp;
private CanvasProperty<Float> mRyProp;
private CanvasProperty<Paint> 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<Animator> mRunningAnimations = new HashSet<>();
private final ArrayList<Animator> 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<Float> prop) {
if (isHorizontal()) {
mLeftProp = prop;
} else {
mTopProp = prop;
}
}
private CanvasProperty<Float> 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<Float> prop) {
if (isHorizontal()) {
mRightProp = prop;
} else {
mBottomProp = prop;
}
}
private CanvasProperty<Float> 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);
}
}
}

View File

@@ -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);
}
}
}