Use RenderThread for navigation bar ripples
Bug: 17506181 Change-Id: Icf3b80f8c4bc29fe85313381d4019dda3ef85ea9
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user