Update FloatingActionButton's elevation handling

We now use a StateListAnimator for both the elevation
and translationZ handling. Matches the framework's button
impl more closely.

Also adds a disabled state which we didn't previously
handle.

Change-Id: I1c86d71495d75680d542a4fab7a1e87834ed572d
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 189060a..329db1a 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -26,9 +26,14 @@
 import android.support.annotation.Nullable;
 import android.support.design.R;
 import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
 
 abstract class FloatingActionButtonImpl {
 
+    static final Interpolator ANIM_INTERPOLATOR = AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR;
+    static final long PRESSED_ANIM_DURATION = 100;
+    static final long PRESSED_ANIM_DELAY = 100;
+
     Drawable mShapeDrawable;
     Drawable mRippleDrawable;
     CircularBorderDrawable mBorderDrawable;
@@ -48,6 +53,7 @@
             android.R.attr.state_enabled};
     static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused,
             android.R.attr.state_enabled};
+    static final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled};
     static final int[] EMPTY_STATE_SET = new int[0];
 
     final VisibilityAwareImageButton mView;
@@ -74,7 +80,7 @@
     final void setElevation(float elevation) {
         if (mElevation != elevation) {
             mElevation = elevation;
-            onElevationChanged(elevation);
+            onElevationsChanged(elevation, mPressedTranslationZ);
         }
     }
 
@@ -83,13 +89,11 @@
     final void setPressedTranslationZ(float translationZ) {
         if (mPressedTranslationZ != translationZ) {
             mPressedTranslationZ = translationZ;
-            onTranslationZChanged(translationZ);
+            onElevationsChanged(mElevation, translationZ);
         }
     }
 
-    abstract void onElevationChanged(float elevation);
-
-    abstract void onTranslationZChanged(float translationZ);
+    abstract void onElevationsChanged(float elevation, float pressedTranslationZ);
 
     abstract void onDrawableStateChanged(int[] state);
 
diff --git a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
index a6fa8d7..148aa32 100644
--- a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
+++ b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
@@ -33,7 +33,6 @@
 
 class FloatingActionButtonGingerbread extends FloatingActionButtonImpl {
 
-    private int mAnimationDuration;
     private StateListAnimator mStateListAnimator;
     private boolean mIsHiding;
 
@@ -43,8 +42,6 @@
             ShadowViewDelegate shadowViewDelegate) {
         super(view, shadowViewDelegate);
 
-        mAnimationDuration = view.getResources().getInteger(android.R.integer.config_shortAnimTime);
-
         mStateListAnimator = new StateListAnimator();
         mStateListAnimator.setTarget(view);
 
@@ -54,8 +51,11 @@
         mStateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
                 setupAnimation(new ElevateToTranslationZAnimation()));
         // Reset back to elevation by default
-        mStateListAnimator.addState(EMPTY_STATE_SET,
+        mStateListAnimator.addState(ENABLED_STATE_SET,
                 setupAnimation(new ResetElevationAnimation()));
+        // Set to 0 when disabled
+        mStateListAnimator.addState(EMPTY_STATE_SET,
+                setupAnimation(new DisabledElevationAnimation()));
     }
 
     @Override
@@ -128,7 +128,7 @@
     }
 
     @Override
-    void onElevationChanged(float elevation) {
+    void onElevationsChanged(float elevation, float pressedTranslationZ) {
         if (mShadowDrawable != null) {
             mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
             updatePadding();
@@ -136,14 +136,6 @@
     }
 
     @Override
-    void onTranslationZChanged(float translationZ) {
-        if (mShadowDrawable != null) {
-            mShadowDrawable.setMaxShadowSize(mElevation + translationZ);
-            updatePadding();
-        }
-    }
-
-    @Override
     void onDrawableStateChanged(int[] state) {
         mStateListAnimator.setState(state);
     }
@@ -223,8 +215,8 @@
     }
 
     private Animation setupAnimation(Animation animation) {
-        animation.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-        animation.setDuration(mAnimationDuration);
+        animation.setInterpolator(ANIM_INTERPOLATOR);
+        animation.setDuration(PRESSED_ANIM_DURATION);
         return animation;
     }
 
@@ -265,6 +257,13 @@
         }
     }
 
+    private class DisabledElevationAnimation extends BaseShadowAnimation {
+        @Override
+        protected float getTargetShadowSize() {
+            return 0f;
+        }
+    }
+
     private static ColorStateList createColorStateList(int selectedColor) {
         final int[][] states = new int[3][];
         final int[] colors = new int[3];
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index 89d78b7..f41578b 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -17,6 +17,7 @@
 package android.support.design.widget;
 
 import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.StateListAnimator;
 import android.annotation.TargetApi;
@@ -29,23 +30,18 @@
 import android.graphics.drawable.RippleDrawable;
 import android.os.Build;
 import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.ViewCompat;
+import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class FloatingActionButtonLollipop extends FloatingActionButtonIcs {
 
-    private final Interpolator mInterpolator;
     private InsetDrawable mInsetDrawable;
 
     FloatingActionButtonLollipop(VisibilityAwareImageButton view,
             ShadowViewDelegate shadowViewDelegate) {
         super(view, shadowViewDelegate);
-
-        mInterpolator = view.isInEditMode() ? null
-                : AnimationUtils.loadInterpolator(mView.getContext(),
-                        android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
@@ -85,24 +81,42 @@
     }
 
     @Override
-    public void onElevationChanged(float elevation) {
-        mView.setElevation(elevation);
-        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
-            updatePadding();
-        }
-    }
+    void onElevationsChanged(final float elevation, final float pressedTranslationZ) {
+        final StateListAnimator stateListAnimator = new StateListAnimator();
 
-    @Override
-    void onTranslationZChanged(float translationZ) {
-        StateListAnimator stateListAnimator = new StateListAnimator();
-        // Animate translationZ to our value when pressed or focused
-        stateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
-                setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
-        stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
-                setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
-        // Animate translationZ to 0 otherwise
-        stateListAnimator.addState(EMPTY_STATE_SET,
-                setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", 0f)));
+        // Animate elevation and translationZ to our values when pressed
+        AnimatorSet set = new AnimatorSet();
+        set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation));
+        set.play(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ)
+                .setDuration(PRESSED_ANIM_DURATION));
+        set.setInterpolator(ANIM_INTERPOLATOR);
+        stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set);
+
+        // Same deal for when we're focused
+        set = new AnimatorSet();
+        set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation));
+        set.play(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ)
+                .setDuration(PRESSED_ANIM_DURATION));
+        set.setInterpolator(ANIM_INTERPOLATOR);
+        stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set);
+
+        // Animate translationZ to 0 if not pressed
+        set = new AnimatorSet();
+        set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation));
+        Animator anim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f);
+        anim.setDuration(PRESSED_ANIM_DURATION);
+        anim.setStartDelay(PRESSED_ANIM_DELAY);
+        set.play(anim);
+        set.setInterpolator(ANIM_INTERPOLATOR);
+        stateListAnimator.addState(ENABLED_STATE_SET, set);
+
+        // Animate everything to 0 when disabled
+        set = new AnimatorSet();
+        set.play(ObjectAnimator.ofFloat(mView, "elevation", 0f));
+        set.play(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f));
+        set.setInterpolator(ANIM_INTERPOLATOR);
+        stateListAnimator.addState(EMPTY_STATE_SET, set);
+
         mView.setStateListAnimator(stateListAnimator);
 
         if (mShadowViewDelegate.isCompatPaddingEnabled()) {
@@ -146,11 +160,6 @@
         return false;
     }
 
-    private Animator setupAnimator(Animator animator) {
-        animator.setInterpolator(mInterpolator);
-        return animator;
-    }
-
     @Override
     CircularBorderDrawable newCircularDrawable() {
         return new CircularBorderDrawableLollipop();