1072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi/*
2072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
3072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi *
4072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
5072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * you may not use this file except in compliance with the License.
6072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * You may obtain a copy of the License at
7072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi *
8072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
9072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi *
10072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
11072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
12072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * See the License for the specific language governing permissions and
14072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi * limitations under the License
15072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi */
16072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
17072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggipackage com.android.systemui.statusbar.policy;
18072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
19072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.animation.Animator;
20072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.animation.AnimatorListenerAdapter;
21072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.animation.ObjectAnimator;
22072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.content.Context;
23072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.Canvas;
24072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.CanvasProperty;
25072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.ColorFilter;
26072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.Paint;
27072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.PixelFormat;
28072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.graphics.drawable.Drawable;
29072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.view.HardwareCanvas;
30072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.view.RenderNodeAnimator;
31072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.view.View;
32072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport android.view.animation.Interpolator;
33072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
34072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport com.android.systemui.R;
35072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport com.android.systemui.statusbar.phone.PhoneStatusBar;
36072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
37072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport java.util.ArrayList;
38072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggiimport java.util.HashSet;
39072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
40072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggipublic class KeyButtonRipple extends Drawable {
41072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
42072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private static final float GLOW_MAX_SCALE_FACTOR = 1.35f;
43072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private static final float GLOW_MAX_ALPHA = 0.2f;
44072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private static final int ANIMATION_DURATION_SCALE = 350;
45072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private static final int ANIMATION_DURATION_FADE = 450;
46072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
47072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private Paint mRipplePaint;
48072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mLeftProp;
49072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mTopProp;
50072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mRightProp;
51072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mBottomProp;
52072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mRxProp;
53072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> mRyProp;
54072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Paint> mPaintProp;
55072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private float mGlowAlpha = 0f;
56072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private float mGlowScale = 1f;
57072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private boolean mPressed;
58072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private boolean mDrawingHardwareGlow;
59072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private int mMaxWidth;
60072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
61072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final Interpolator mInterpolator = new LogInterpolator();
62072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final Interpolator mAlphaExitInterpolator = PhoneStatusBar.ALPHA_OUT;
63072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private boolean mSupportHardware;
64072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final View mTargetView;
65072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
66072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final HashSet<Animator> mRunningAnimations = new HashSet<>();
67072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final ArrayList<Animator> mTmpArray = new ArrayList<>();
68072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
69072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public KeyButtonRipple(Context ctx, View targetView) {
70072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mMaxWidth =  ctx.getResources().getDimensionPixelSize(R.dimen.key_button_ripple_max_width);
71072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mTargetView = targetView;
72072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
73072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
74072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private Paint getRipplePaint() {
75072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (mRipplePaint == null) {
76072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRipplePaint = new Paint();
77072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRipplePaint.setAntiAlias(true);
78072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRipplePaint.setColor(0xffffffff);
79072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
80072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return mRipplePaint;
81072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
82072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
83072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void drawSoftware(Canvas canvas) {
84072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (mGlowAlpha > 0f) {
85072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final Paint p = getRipplePaint();
86072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            p.setAlpha((int)(mGlowAlpha * 255f));
87072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
88072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float w = getBounds().width();
89072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float h = getBounds().height();
90072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final boolean horizontal = w > h;
91072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float diameter = getRippleSize() * mGlowScale;
92072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float radius = diameter * .5f;
93072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float cx = w * .5f;
94072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float cy = h * .5f;
95072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float rx = horizontal ? radius : cx;
96072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float ry = horizontal ? cy : radius;
97072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            final float corner = horizontal ? cy : cx;
98072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
99072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            canvas.drawRoundRect(cx - rx, cy - ry,
100072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                    cx + rx, cy + ry,
101072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                    corner, corner, p);
102072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
103072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
104072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
105072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
106072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void draw(Canvas canvas) {
107072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mSupportHardware = canvas.isHardwareAccelerated();
108072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (mSupportHardware) {
109072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            drawHardware((HardwareCanvas) canvas);
110072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
111072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            drawSoftware(canvas);
112072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
113072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
114072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
115072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
116072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void setAlpha(int alpha) {
117072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        // Not supported.
118072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
119072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
120072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
121072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void setColorFilter(ColorFilter cf) {
122072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        // Not supported.
123072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
124072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
125072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
126072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public int getOpacity() {
127072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return PixelFormat.TRANSLUCENT;
128072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
129072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
130072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private boolean isHorizontal() {
131072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return getBounds().width() > getBounds().height();
132072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
133072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
134072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void drawHardware(HardwareCanvas c) {
135072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (mDrawingHardwareGlow) {
136072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            c.drawRoundRect(mLeftProp, mTopProp, mRightProp, mBottomProp, mRxProp, mRyProp,
137072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                    mPaintProp);
138072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
139072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
140072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
141072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public float getGlowAlpha() {
142072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return mGlowAlpha;
143072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
144072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
145072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void setGlowAlpha(float x) {
146072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mGlowAlpha = x;
147072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        invalidateSelf();
148072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
149072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
150072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public float getGlowScale() {
151072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return mGlowScale;
152072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
153072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
154072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void setGlowScale(float x) {
155072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mGlowScale = x;
156072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        invalidateSelf();
157072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
158072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
159072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
160072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    protected boolean onStateChange(int[] state) {
161072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        boolean pressed = false;
162072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        for (int i = 0; i < state.length; i++) {
163072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            if (state[i] == android.R.attr.state_pressed) {
164072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                pressed = true;
165072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                break;
166072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            }
167072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
168072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (pressed != mPressed) {
169072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            setPressed(pressed);
170072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mPressed = pressed;
171072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            return true;
172072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
173072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            return false;
174072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
175072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
176072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
177072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    @Override
178b9e290c7136fb7c76b7238426ccd598dec2d2643Jorim Jaggi    public void jumpToCurrentState() {
179b9e290c7136fb7c76b7238426ccd598dec2d2643Jorim Jaggi        cancelAnimations();
180b9e290c7136fb7c76b7238426ccd598dec2d2643Jorim Jaggi    }
181b9e290c7136fb7c76b7238426ccd598dec2d2643Jorim Jaggi
182b9e290c7136fb7c76b7238426ccd598dec2d2643Jorim Jaggi    @Override
183072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public boolean isStateful() {
184072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return true;
185072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
186072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
187072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    public void setPressed(boolean pressed) {
188072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (mSupportHardware) {
189072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            setPressedHardware(pressed);
190072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
191072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            setPressedSoftware(pressed);
192072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
193072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
194072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
195072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void cancelAnimations() {
196072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mTmpArray.addAll(mRunningAnimations);
197072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        int size = mTmpArray.size();
198072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        for (int i = 0; i < size; i++) {
199072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            Animator a = mTmpArray.get(i);
200072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            a.cancel();
201072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
202072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mTmpArray.clear();
203072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.clear();
204072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
205072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
206072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void setPressedSoftware(boolean pressed) {
207072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (pressed) {
208072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            enterSoftware();
209072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
210072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            exitSoftware();
211072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
212072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
213072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
214072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void enterSoftware() {
215072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        cancelAnimations();
216072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mGlowAlpha = GLOW_MAX_ALPHA;
217072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale",
218072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                0f, GLOW_MAX_SCALE_FACTOR);
219072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        scaleAnimator.setInterpolator(mInterpolator);
220072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        scaleAnimator.setDuration(ANIMATION_DURATION_SCALE);
221072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        scaleAnimator.addListener(mAnimatorListener);
222072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        scaleAnimator.start();
223072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.add(scaleAnimator);
224072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
225072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
226072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void exitSoftware() {
227072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f);
228072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        alphaAnimator.setInterpolator(mAlphaExitInterpolator);
229072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        alphaAnimator.setDuration(ANIMATION_DURATION_FADE);
230072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        alphaAnimator.addListener(mAnimatorListener);
231072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        alphaAnimator.start();
232072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.add(alphaAnimator);
233072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
234072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
235072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void setPressedHardware(boolean pressed) {
236072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (pressed) {
237072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            enterHardware();
238072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
239072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            exitHardware();
240072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
241072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
242072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
243072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    /**
244072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     * Sets the left/top property for the round rect to {@code prop} depending on whether we are
245072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     * horizontal or vertical mode.
246072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     */
247072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void setExtendStart(CanvasProperty<Float> prop) {
248072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (isHorizontal()) {
249072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mLeftProp = prop;
250072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
251072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mTopProp = prop;
252072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
253072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
254072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
255072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> getExtendStart() {
256072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return isHorizontal() ? mLeftProp : mTopProp;
257072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
258072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
259072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    /**
260072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     * Sets the right/bottom property for the round rect to {@code prop} depending on whether we are
261072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     * horizontal or vertical mode.
262072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     */
263072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void setExtendEnd(CanvasProperty<Float> prop) {
264072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (isHorizontal()) {
265072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRightProp = prop;
266072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
267072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mBottomProp = prop;
268072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
269072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
270072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
271072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private CanvasProperty<Float> getExtendEnd() {
272072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return isHorizontal() ? mRightProp : mBottomProp;
273072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
274072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
275072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private int getExtendSize() {
276072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return isHorizontal() ? getBounds().width() : getBounds().height();
277072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
278072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
279072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private int getRippleSize() {
280072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        int size = isHorizontal() ? getBounds().width() : getBounds().height();
281072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return Math.min(size, mMaxWidth);
282072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
283072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
284072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void enterHardware() {
285072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        cancelAnimations();
286072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mDrawingHardwareGlow = true;
287072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
288072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
289072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                getExtendSize()/2 - GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
290072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        startAnim.setDuration(ANIMATION_DURATION_SCALE);
291072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        startAnim.setInterpolator(mInterpolator);
292072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        startAnim.addListener(mAnimatorListener);
293072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        startAnim.setTarget(mTargetView);
294072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
295072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        setExtendEnd(CanvasProperty.createFloat(getExtendSize() / 2));
296072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        final RenderNodeAnimator endAnim = new RenderNodeAnimator(getExtendEnd(),
297072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                getExtendSize()/2 + GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
298072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        endAnim.setDuration(ANIMATION_DURATION_SCALE);
299072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        endAnim.setInterpolator(mInterpolator);
300072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        endAnim.addListener(mAnimatorListener);
301072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        endAnim.setTarget(mTargetView);
302072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
303072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        if (isHorizontal()) {
304072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mTopProp = CanvasProperty.createFloat(0f);
305072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mBottomProp = CanvasProperty.createFloat(getBounds().height());
306072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRxProp = CanvasProperty.createFloat(getBounds().height()/2);
307072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRyProp = CanvasProperty.createFloat(getBounds().height()/2);
308072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        } else {
309072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mLeftProp = CanvasProperty.createFloat(0f);
310072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRightProp = CanvasProperty.createFloat(getBounds().width());
311072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRxProp = CanvasProperty.createFloat(getBounds().width()/2);
312072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRyProp = CanvasProperty.createFloat(getBounds().width()/2);
313072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
314072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
315072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mGlowScale = GLOW_MAX_SCALE_FACTOR;
316072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mGlowAlpha = GLOW_MAX_ALPHA;
317072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRipplePaint = getRipplePaint();
318072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRipplePaint.setAlpha((int) (mGlowAlpha * 255));
319072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mPaintProp = CanvasProperty.createPaint(mRipplePaint);
320072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
321072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        startAnim.start();
322072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        endAnim.start();
323072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.add(startAnim);
324072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.add(endAnim);
325072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
326072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        invalidateSelf();
327072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
328072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
329072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private void exitHardware() {
330072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mPaintProp = CanvasProperty.createPaint(getRipplePaint());
331072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
332072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                RenderNodeAnimator.PAINT_ALPHA, 0);
333072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        opacityAnim.setDuration(ANIMATION_DURATION_FADE);
334072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        opacityAnim.setInterpolator(mAlphaExitInterpolator);
335072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        opacityAnim.addListener(mAnimatorListener);
336072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        opacityAnim.setTarget(mTargetView);
337072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
338072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        opacityAnim.start();
339072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        mRunningAnimations.add(opacityAnim);
340072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
341072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        invalidateSelf();
342072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
343072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
344072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private final AnimatorListenerAdapter mAnimatorListener =
345072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            new AnimatorListenerAdapter() {
346072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        @Override
347072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        public void onAnimationEnd(Animator animation) {
348072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            mRunningAnimations.remove(animation);
349072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            if (mRunningAnimations.isEmpty() && !mPressed) {
350072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                mDrawingHardwareGlow = false;
351072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi                invalidateSelf();
352072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            }
353072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
354072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    };
355072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
356072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    /**
357072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     * Interpolator with a smooth log deceleration
358072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi     */
359072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    private static final class LogInterpolator implements Interpolator {
360072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        @Override
361072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        public float getInterpolation(float input) {
362072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi            return 1 - (float) Math.pow(400, -input * 1.4);
363072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        }
364072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    }
365072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi}
366