From 42310965fa2c0d2c91bea0a76730a21f6dd308a2 Mon Sep 17 00:00:00 2001 From: Christian Robertson Date: Sun, 14 Sep 2014 02:14:46 -0400 Subject: [PATCH] Customized ripple animation for navigation bar To implement the new gel-cap shaped ripple I resurrected the onDraw and setPressed methods from the KitKat implementation. The KitKat animation timings were adjusted to match the material ripple, but the structure of the animators is the same as KitKat. Since the new ripple is drawn directly to the canvas, the references to the KitKat background image were removed. The LogInterpolator is copied from the framework Ripple to match the material animation curves. Bug: 17112935 Change-Id: If6a3eb92de794b526338166bf8cb096eb9764cf6 --- .../res/layout-sw600dp/navigation_bar.xml | 17 +- .../SystemUI/res/layout/navigation_bar.xml | 14 +- .../statusbar/policy/KeyButtonView.java | 153 ++++++++++++++---- 3 files changed, 128 insertions(+), 56 deletions(-) diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml index b5983bb8cd953..c2733fb0aff2a 100644 --- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml +++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml @@ -59,7 +59,6 @@ android:src="@drawable/ic_sysbar_back" systemui:keyCode="4" android:layout_weight="0" - android:background="@drawable/ripple_drawable" android:contentDescription="@string/accessibility_back" /> + android:contentDescription="@string/accessibility_ime_switch_button" /> @@ -205,7 +200,6 @@ android:src="@drawable/ic_sysbar_back" systemui:keyCode="4" android:layout_weight="0" - android:background="@drawable/ripple_drawable" android:contentDescription="@string/accessibility_back" /> + android:contentDescription="@string/accessibility_menu" /> + android:scaleType="centerInside" /> diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index a165940616baf..16027d96f0c06 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -55,7 +55,6 @@ systemui:keyCode="4" android:layout_weight="0" android:scaleType="center" - android:background="@drawable/ripple_drawable" android:contentDescription="@string/accessibility_back" /> + android:visibility="invisible" /> @@ -202,8 +197,7 @@ android:contentDescription="@string/accessibility_ime_switch_button" android:scaleType="centerInside" android:src="@drawable/ic_ime_switcher_default" - android:visibility="invisible" - android:background="@drawable/ripple_drawable" /> + android:visibility="invisible" /> @@ -222,7 +215,6 @@ android:src="@drawable/ic_sysbar_recent_land" android:layout_weight="0" android:contentDescription="@string/accessibility_recent" - android:background="@drawable/ripple_drawable" /> 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); if (alpha == mQuiescentAlpha && alpha == mDrawingAlpha) return; mQuiescentAlpha = alpha; if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha); - if (mBackground != null && animate) { + if (animate) { mAnimateToQuiescent = animateToQuiescent(); mAnimateToQuiescent.start(); } else { @@ -162,34 +201,79 @@ public class KeyButtonView extends ImageView { public void setDrawingAlpha(float x) { setImageAlpha((int) (x * 255)); - if (mBackground != null) { - mBackground.setAlpha((int)(x * 255)); - } mDrawingAlpha = x; } - public void setPressed(boolean pressed) { - if (mBackground != null) { - if (pressed != isPressed()) { - if (pressed) { - setDrawingAlpha(1f); - } else { - mAnimateToQuiescent.cancel(); - mAnimateToQuiescent = animateToQuiescent(); - mAnimateToQuiescent.setDuration(500); - mAnimateToQuiescent.start(); - } - } - } - super.setPressed(pressed); + public float getGlowAlpha() { + return mGlowAlpha; } - private void setHotspot(float x, float y) { - if (mBackground != null) { - mBackground.setHotspot(x, y); + 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; @@ -209,7 +293,6 @@ public class KeyButtonView extends ImageView { removeCallbacks(mCheckLongPress); postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); } - setHotspot(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_MOVE: x = (int)ev.getX(); @@ -218,7 +301,6 @@ public class KeyButtonView extends ImageView { && x < getWidth() + mTouchSlop && y >= -mTouchSlop && y < getHeight() + mTouchSlop); - setHotspot(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_CANCEL: setPressed(false); @@ -272,6 +354,17 @@ 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); + } + } + }