Merge "Fix Snackbar sw600dp gravity" into lmp-mr1-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index 217ba99..9dc6e20 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -170,7 +170,9 @@
     ctor public FloatingActionButton(android.content.Context);
     ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
     ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+    method public void hide();
     method public void setRippleColor(int);
+    method public void show();
   }
 
   public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 6c154d4..7fcb147 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -26,6 +26,8 @@
 
 abstract class FloatingActionButtonImpl {
 
+    static final int SHOW_HIDE_ANIM_DURATION = 200;
+
     static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed,
             android.R.attr.state_enabled};
     static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused,
@@ -57,6 +59,10 @@
 
     abstract void jumpDrawableToCurrentState();
 
+    abstract void hide();
+
+    abstract void show();
+
     Drawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
         final Resources resources = mView.getResources();
         CircularBorderDrawable borderDrawable = newCircularDrawable();
diff --git a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
index 36ddd89..1aa0b683 100644
--- a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
+++ b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
@@ -23,6 +23,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.LayerDrawable;
+import android.support.design.R;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.view.View;
 import android.view.animation.Animation;
@@ -42,6 +43,8 @@
 
     ShadowDrawableWrapper mShadowDrawable;
 
+    private boolean mIsHiding;
+
     FloatingActionButtonEclairMr1(View view, ShadowViewDelegate shadowViewDelegate) {
         super(view, shadowViewDelegate);
 
@@ -153,6 +156,41 @@
         mStateListAnimator.jumpToCurrentState();
     }
 
+    @Override
+    void hide() {
+        if (mIsHiding) {
+            // There is currently an hide animation running, return
+            return;
+        }
+
+        Animation anim = android.view.animation.AnimationUtils.loadAnimation(
+                mView.getContext(), R.anim.fab_out);
+        anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+        anim.setDuration(SHOW_HIDE_ANIM_DURATION);
+        anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animation animation) {
+                mIsHiding = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animation animation) {
+                mIsHiding = false;
+                mView.setVisibility(View.GONE);
+            }
+        });
+        mView.startAnimation(anim);
+    }
+
+    @Override
+    void show() {
+        Animation anim = android.view.animation.AnimationUtils.loadAnimation(
+                mView.getContext(), R.anim.fab_in);
+        anim.setDuration(SHOW_HIDE_ANIM_DURATION);
+        anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+        mView.startAnimation(anim);
+    }
+
     private void updatePadding() {
         Rect rect = new Rect();
         mShadowDrawable.getPadding(rect);
diff --git a/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
new file mode 100644
index 0000000..62da58e
--- /dev/null
+++ b/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 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 android.support.design.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.view.View;
+
+class FloatingActionButtonHoneycombMr1 extends FloatingActionButtonEclairMr1 {
+
+    private boolean mIsHiding;
+
+    FloatingActionButtonHoneycombMr1(View view, ShadowViewDelegate shadowViewDelegate) {
+        super(view, shadowViewDelegate);
+    }
+
+    @Override
+    void hide() {
+        if (mIsHiding) {
+            // A hide animation is in progress, skip the call
+            return;
+        }
+
+        mView.animate()
+                .scaleX(0f)
+                .scaleY(0f)
+                .alpha(0f)
+                .setDuration(SHOW_HIDE_ANIM_DURATION)
+                .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        mIsHiding = true;
+                    }
+
+                    @Override
+                    public void onAnimationCancel(Animator animation) {
+                        mIsHiding = false;
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mIsHiding = false;
+                        mView.setVisibility(View.GONE);
+                    }
+                });
+    }
+
+    @Override
+    void show() {
+        mView.animate()
+                .scaleX(1f)
+                .scaleY(1f)
+                .alpha(1f)
+                .setDuration(SHOW_HIDE_ANIM_DURATION)
+                .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+                .setListener(null);
+    }
+}
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index c21d341..a440427 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -33,7 +33,7 @@
 import android.view.animation.Interpolator;
 
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-class FloatingActionButtonLollipop extends FloatingActionButtonImpl {
+class FloatingActionButtonLollipop extends FloatingActionButtonHoneycombMr1 {
 
     private Drawable mShapeDrawable;
     private RippleDrawable mRippleDrawable;
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index bd2ce10..13262a2 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -27,10 +27,8 @@
 import android.support.annotation.Nullable;
 import android.support.design.R;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.Animation;
 import android.widget.ImageView;
 
 import java.util.List;
@@ -119,8 +117,11 @@
             }
         };
 
-        if (Build.VERSION.SDK_INT >= 21) {
+        final int sdk = Build.VERSION.SDK_INT;
+        if (sdk >= 21) {
             mImpl = new FloatingActionButtonLollipop(this, delegate);
+        } else if (sdk >= 12) {
+            mImpl = new FloatingActionButtonHoneycombMr1(this, delegate);
         } else {
             mImpl = new FloatingActionButtonEclairMr1(this, delegate);
         }
@@ -220,7 +221,36 @@
     public void setBackgroundDrawable(Drawable background) {
         if (mImpl != null) {
             mImpl.setBackgroundDrawable(
-                background, mBackgroundTint, mBackgroundTintMode, mRippleColor, mBorderWidth);
+                    background, mBackgroundTint, mBackgroundTintMode, mRippleColor, mBorderWidth);
+        }
+    }
+
+    /**
+     * Shows the button.
+     * <p>This method will animate it the button show if the view has already been laid out.</p>
+     */
+    public void show() {
+        if (getVisibility() == VISIBLE) {
+            return;
+        }
+        setVisibility(VISIBLE);
+        if (ViewCompat.isLaidOut(this)) {
+            mImpl.show();
+        }
+    }
+
+    /**
+     * Hides the button.
+     * <p>This method will animate the button hide if the view has already been laid out.</p>
+     */
+    public void hide() {
+        if (getVisibility() != VISIBLE) {
+            return;
+        }
+        if (ViewCompat.isLaidOut(this)) {
+            mImpl.hide();
+        } else {
+            setVisibility(GONE);
         }
     }
 
@@ -299,13 +329,11 @@
         private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
 
         private Rect mTmpRect;
-        private boolean mIsAnimatingOut;
         private float mTranslationY;
 
         @Override
         public boolean layoutDependsOn(CoordinatorLayout parent,
-                FloatingActionButton child,
-                View dependency) {
+                FloatingActionButton child, View dependency) {
             // We're dependent on all SnackbarLayouts (if enabled)
             return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
         }
@@ -316,32 +344,47 @@
             if (dependency instanceof Snackbar.SnackbarLayout) {
                 updateFabTranslationForSnackbar(parent, child, dependency);
             } else if (dependency instanceof AppBarLayout) {
-                final AppBarLayout appBarLayout = (AppBarLayout) dependency;
-                if (mTmpRect == null) {
-                    mTmpRect = new Rect();
-                }
-
-                // First, let's get the visible rect of the dependency
-                final Rect rect = mTmpRect;
-                ViewGroupUtils.getDescendantRect(parent, dependency, rect);
-
-                if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
-                    // If the anchor's bottom is below the seam, we'll animate our FAB out
-                    if (!mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {
-                        animateOut(child);
-                    }
-                } else {
-                    // Else, we'll animate our FAB back in
-                    if (child.getVisibility() != View.VISIBLE) {
-                        animateIn(child);
-                    }
-                }
+                // If we're depending on an AppBarLayout we will show/hide it automatically
+                // if the FAB is anchored to the AppBarLayout
+                updateFabVisibility(parent, (AppBarLayout) dependency, child);
             }
             return false;
         }
 
+        private boolean updateFabVisibility(CoordinatorLayout parent,
+                AppBarLayout appBarLayout, FloatingActionButton child) {
+            final CoordinatorLayout.LayoutParams lp =
+                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
+            if (lp.getAnchorId() != appBarLayout.getId()) {
+                // The anchor ID doesn't match the dependency, so we won't automatically
+                // show/hide the FAB
+                return false;
+            }
+
+            if (mTmpRect == null) {
+                mTmpRect = new Rect();
+            }
+
+            // First, let's get the visible rect of the dependency
+            final Rect rect = mTmpRect;
+            ViewGroupUtils.getDescendantRect(parent, appBarLayout, rect);
+
+            if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
+                // If the anchor's bottom is below the seam, we'll animate our FAB out
+                child.hide();
+            } else {
+                // Else, we'll animate our FAB back in
+                child.show();
+            }
+            return true;
+        }
+
         private void updateFabTranslationForSnackbar(CoordinatorLayout parent,
                 FloatingActionButton fab, View snackbar) {
+            if (fab.getVisibility() != View.VISIBLE) {
+                return;
+            }
+
             final float translationY = getFabTranslationYForSnackbar(parent, fab);
             if (translationY != mTranslationY) {
                 // First, cancel any current animation
@@ -377,83 +420,25 @@
             return minOffset;
         }
 
-        private void animateIn(FloatingActionButton button) {
-            button.setVisibility(View.VISIBLE);
-
-            if (Build.VERSION.SDK_INT >= 14) {
-                ViewCompat.animate(button)
-                        .scaleX(1f)
-                        .scaleY(1f)
-                        .alpha(1f)
-                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                        .withLayer()
-                        .setListener(null)
-                        .start();
-            } else {
-                Animation anim = android.view.animation.AnimationUtils.loadAnimation(
-                        button.getContext(), R.anim.fab_in);
-                anim.setDuration(200);
-                anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-                button.startAnimation(anim);
-            }
-        }
-
         @Override
         public boolean onLayoutChild(CoordinatorLayout parent, FloatingActionButton child,
                 int layoutDirection) {
-            // Let the CoordinatorLayout lay out the FAB
+            // First, lets make sure that the visibility of the FAB is consistent
+            final List<View> dependencies = parent.getDependencies(child);
+            for (int i = 0, count = dependencies.size(); i < count; i++) {
+                final View dependency = dependencies.get(i);
+                if (dependency instanceof AppBarLayout
+                        && updateFabVisibility(parent, (AppBarLayout) dependency, child)) {
+                    break;
+                }
+            }
+            // Now let the CoordinatorLayout lay out the FAB
             parent.onLayoutChild(child, layoutDirection);
             // Now offset it if needed
             offsetIfNeeded(parent, child);
             return true;
         }
 
-        private void animateOut(final FloatingActionButton button) {
-            if (Build.VERSION.SDK_INT >= 14) {
-                ViewCompat.animate(button)
-                        .scaleX(0f)
-                        .scaleY(0f)
-                        .alpha(0f)
-                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                        .withLayer()
-                        .setListener(new ViewPropertyAnimatorListener() {
-                            @Override
-                            public void onAnimationStart(View view) {
-                                mIsAnimatingOut = true;
-                            }
-
-                            @Override
-                            public void onAnimationCancel(View view) {
-                                mIsAnimatingOut = false;
-                            }
-
-                            @Override
-                            public void onAnimationEnd(View view) {
-                                mIsAnimatingOut = false;
-                                view.setVisibility(View.GONE);
-                            }
-                        }).start();
-            } else {
-                Animation anim = android.view.animation.AnimationUtils.loadAnimation(
-                        button.getContext(), R.anim.fab_out);
-                anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-                anim.setDuration(200);
-                anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
-                    @Override
-                    public void onAnimationStart(Animation animation) {
-                        mIsAnimatingOut = true;
-                    }
-
-                    @Override
-                    public void onAnimationEnd(Animation animation) {
-                        mIsAnimatingOut = false;
-                        button.setVisibility(View.GONE);
-                    }
-                });
-                button.startAnimation(anim);
-            }
-        }
-
         /**
          * Pre-Lollipop we use padding so that the shadow has enough space to be drawn. This method
          * offsets our layout position so that we're positioned correctly if we're on one of
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 3e2c841..5db9d05 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -571,7 +571,7 @@
         <item name="isLightTheme">true</item>
     </style>
 
-    <style name="Base.ThemeOverlay.AppCompat.Dark">
+    <style name="Base.ThemeOverlay.AppCompat.Dark" parent="Platform.ThemeOverlay.AppCompat.Dark">
         <item name="android:windowBackground">@color/background_material_dark</item>
         <item name="android:colorForeground">@color/bright_foreground_material_dark</item>
         <item name="android:colorForegroundInverse">@color/bright_foreground_material_light</item>