Merge "Make RecyclerView requestDisallowInterceptTouchEvent(true)" into lmp-mr1-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index 27b0a30..0e638cf 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -127,6 +127,7 @@
     method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
     method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
     method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
     method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
     method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
     method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
@@ -179,6 +180,7 @@
     ctor public FloatingActionButton.Behavior();
     method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
     method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
     method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
   }
 
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index 90ad3d2..e80e677 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -101,7 +101,7 @@
             }
             mHeader = (LinearLayout) mLayoutInflater.inflate(R.layout.design_navigation_item_header,
                     mMenuView, false);
-            mMenuView.addHeaderView(mHeader);
+            mMenuView.addHeaderView(mHeader, null, false);
             mMenuView.setAdapter(mAdapter);
             mMenuView.setOnItemClickListener(this);
         }
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index e2081b7..8675e6d 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -149,6 +149,8 @@
     private boolean mDrawStatusBarBackground;
     private Drawable mStatusBarBackground;
 
+    private OnHierarchyChangeListener mOnHierarchyChangeListener;
+
     private final NestedScrollingParentHelper mNestedScrollingParentHelper =
             new NestedScrollingParentHelper(this);
 
@@ -181,6 +183,12 @@
         if (INSETS_HELPER != null) {
             INSETS_HELPER.setupForWindowInsets(this, new ApplyInsetsListener());
         }
+        super.setOnHierarchyChangeListener(new HierarchyChangeListener());
+    }
+
+    @Override
+    public void setOnHierarchyChangeListener(OnHierarchyChangeListener onHierarchyChangeListener) {
+        mOnHierarchyChangeListener = onHierarchyChangeListener;
     }
 
     @Override
@@ -1110,6 +1118,19 @@
         }
     }
 
+    void dispatchDependentViewRemoved(View removedChild) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Behavior b = lp.getBehavior();
+
+            if (b != null && b.layoutDependsOn(this, child, removedChild)) {
+                b.onDependentViewRemoved(this, child, removedChild);
+            }
+        }
+    }
+
     /**
      * Allows the caller to manually dispatch
      * {@link Behavior#onDependentViewChanged(CoordinatorLayout, View, View)} to the associated
@@ -1734,6 +1755,23 @@
         }
 
         /**
+         * Respond to a child's dependent view being removed.
+         *
+         * <p>This method is called after a dependent view has been removed from the parent.
+         * A Behavior may use this method to appropriately update the child view in response.</p>
+         *
+         * <p>A view's dependency is determined by
+         * {@link #layoutDependsOn(CoordinatorLayout, android.view.View, android.view.View)} or
+         * if {@code child} has set another view as it's anchor.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view to manipulate
+         * @param dependency the dependent view that has been removed
+         */
+        public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency) {
+        }
+
+        /**
          * Determine whether the given child view should be considered dirty.
          *
          * <p>If a property determined by the Behavior such as other dependent views would change,
@@ -2457,6 +2495,24 @@
         }
     }
 
+    final class HierarchyChangeListener implements OnHierarchyChangeListener {
+        @Override
+        public void onChildViewAdded(View parent, View child) {
+            if (mOnHierarchyChangeListener != null) {
+                mOnHierarchyChangeListener.onChildViewAdded(parent, child);
+            }
+        }
+
+        @Override
+        public void onChildViewRemoved(View parent, View child) {
+            dispatchDependentViewRemoved(child);
+
+            if (mOnHierarchyChangeListener != null) {
+                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
+            }
+        }
+    }
+
     @Override
     protected void onRestoreInstanceState(Parcelable state) {
         final SavedState ss = (SavedState) state;
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 42af049..b275174 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -351,6 +351,19 @@
             return false;
         }
 
+        @Override
+        public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionButton child,
+                View dependency) {
+            if (dependency instanceof Snackbar.SnackbarLayout) {
+                // If the removed view is a SnackbarLayout, we will animate back to our normal
+                // position
+                ViewCompat.animate(child)
+                        .translationY(0f)
+                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+                        .setListener(null);
+            }
+        }
+
         private boolean updateFabVisibility(CoordinatorLayout parent,
                 AppBarLayout appBarLayout, FloatingActionButton child) {
             final CoordinatorLayout.LayoutParams lp =
@@ -389,18 +402,8 @@
             if (translationY != mTranslationY) {
                 // First, cancel any current animation
                 ViewCompat.animate(fab).cancel();
-
-                if (Math.abs(translationY - mTranslationY) == snackbar.getHeight()) {
-                    // If we're travelling by the height of the Snackbar then we probably need to
-                    // animate to the value
-                    ViewCompat.animate(fab)
-                            .translationY(translationY)
-                            .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
-                            .setListener(null);
-                } else {
-                    // Else we'll set use setTranslationY
-                    ViewCompat.setTranslationY(fab, translationY);
-                }
+                // Else we'll set use setTranslationY
+                ViewCompat.setTranslationY(fab, translationY);
                 mTranslationY = translationY;
             }
         }
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 9ed7a8a..610b1a4 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -1497,7 +1497,9 @@
         }
 
         @Override
-        protected void onDraw(Canvas canvas) {
+        public void draw(Canvas canvas) {
+            super.draw(canvas);
+
             // Thick colored underline below the current selection
             if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
                 canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index 4f88cd4..0a24f7e 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -1518,6 +1518,25 @@
 
 }
 
+package android.support.v7.graphics.drawable {
+
+  public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
+    ctor public DrawerArrowDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public int getDirection();
+    method public int getOpacity();
+    method public float getProgress();
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDirection(int);
+    method public void setProgress(float);
+    method public void setVerticalMirror(boolean);
+    field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
+    field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
+  }
+
+}
+
 package android.support.v7.view {
 
   public abstract class ActionMode {
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
index 93a79a6..02acb27 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
@@ -27,11 +27,11 @@
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.DrawerLayout;
+import android.support.v7.graphics.drawable.DrawerArrowDrawable;
 import android.support.v7.widget.Toolbar;
 import android.util.Log;
 import android.view.MenuItem;
 import android.view.View;
-import android.support.v7.appcompat.R;
 
 /**
  * This class provides a handy way to tie together the functionality of
@@ -465,9 +465,7 @@
         return mActivityImpl.getThemeUpIndicator();
     }
 
-    static class DrawerArrowDrawableToggle extends DrawerArrowDrawable
-            implements DrawerToggle {
-
+    static class DrawerArrowDrawableToggle extends DrawerArrowDrawable implements DrawerToggle {
         private final Activity mActivity;
 
         public DrawerArrowDrawableToggle(Activity activity, Context themedContext) {
@@ -476,22 +474,23 @@
         }
 
         public void setPosition(float position) {
+            if (ViewCompat.getLayoutDirection(mActivity.getWindow().getDecorView())
+                    == ViewCompat.LAYOUT_DIRECTION_RTL) {
+                setDirection(ARROW_DIRECTION_RIGHT);
+            } else {
+                setDirection(ARROW_DIRECTION_LEFT);
+            }
+
             if (position == 1f) {
                 setVerticalMirror(true);
             } else if (position == 0f) {
                 setVerticalMirror(false);
             }
-            super.setProgress(position);
-        }
-
-        @Override
-        boolean isLayoutRtl() {
-            return ViewCompat.getLayoutDirection(mActivity.getWindow().getDecorView())
-                    == ViewCompat.LAYOUT_DIRECTION_RTL;
+            setProgress(position);
         }
 
         public float getPosition() {
-            return super.getProgress();
+            return getProgress();
         }
     }
 
diff --git a/v7/appcompat/src/android/support/v7/app/DrawerArrowDrawable.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
similarity index 64%
rename from v7/appcompat/src/android/support/v7/app/DrawerArrowDrawable.java
rename to v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
index 06bb360..439b3fb 100644
--- a/v7/appcompat/src/android/support/v7/app/DrawerArrowDrawable.java
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
@@ -13,25 +13,53 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.v7.app;
 
+package android.support.v7.graphics.drawable;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntDef;
 import android.support.v7.appcompat.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
- * A drawable that can draw a "Drawer hamburger" menu or an Arrow and animate between them.
+ * A drawable that can draw a "Drawer hamburger" menu or an arrow and animate between them.
+ * <p>
+ * The progress between the two states is controlled via {@link #setProgress(float)}.
+ * </p>
  */
-abstract class DrawerArrowDrawable extends Drawable {
+public class DrawerArrowDrawable extends Drawable {
+
+    /**
+     * Direction to make the arrow point from right to left.
+     *
+     * @see #setDirection(int)
+     * @see #getDirection()
+     */
+    public static final int ARROW_DIRECTION_LEFT = 0;
+
+    /**
+     * Direction to make the arrow point from left to right.
+     *
+     * @see #setDirection(int)
+     * @see #getDirection()
+     */
+    public static final int ARROW_DIRECTION_RIGHT = 1;
+
+    /** @hide */
+    @IntDef({ARROW_DIRECTION_LEFT, ARROW_DIRECTION_RIGHT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ArrowDirection {}
 
     private final Paint mPaint = new Paint();
 
@@ -61,34 +89,34 @@
     private float mMaxCutForBarSize;
     // The distance of arrow's center from top when horizontal
     private float mCenterOffset;
+    // The arrow direction
+    private int mDirection = ARROW_DIRECTION_LEFT;
 
     /**
      * @param context used to get the configuration for the drawable from
      */
-    DrawerArrowDrawable(Context context) {
-        final TypedArray typedArray = context.getTheme()
+    public DrawerArrowDrawable(Context context) {
+        final TypedArray a = context.getTheme()
                 .obtainStyledAttributes(null, R.styleable.DrawerArrowToggle,
                         R.attr.drawerArrowStyle,
                         R.style.Base_Widget_AppCompat_DrawerArrowToggle);
         mPaint.setAntiAlias(true);
-        mPaint.setColor(typedArray.getColor(R.styleable.DrawerArrowToggle_color, 0));
-        mSize = typedArray.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0);
+        mPaint.setColor(a.getColor(R.styleable.DrawerArrowToggle_color, 0));
+        mSize = a.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0);
         // round this because having this floating may cause bad measurements
-        mBarSize = Math.round(typedArray.getDimension(R.styleable.DrawerArrowToggle_barSize, 0));
+        mBarSize = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_barSize, 0));
         // round this because having this floating may cause bad measurements
-        mTopBottomArrowSize = Math.round(typedArray.getDimension(
+        mTopBottomArrowSize = Math.round(a.getDimension(
                 R.styleable.DrawerArrowToggle_topBottomBarArrowSize, 0));
-        mBarThickness = typedArray.getDimension(R.styleable.DrawerArrowToggle_thickness, 0);
+        mBarThickness = a.getDimension(R.styleable.DrawerArrowToggle_thickness, 0);
         // round this because having this floating may cause bad measurements
-        mBarGap = Math.round(typedArray.getDimension(
-                R.styleable.DrawerArrowToggle_gapBetweenBars, 0));
-        mSpin = typedArray.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true);
-        mMiddleArrowSize = typedArray
-                .getDimension(R.styleable.DrawerArrowToggle_middleBarArrowSize, 0);
+        mBarGap = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0));
+        mSpin = a.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true);
+        mMiddleArrowSize = a.getDimension(R.styleable.DrawerArrowToggle_middleBarArrowSize, 0);
         final int remainingSpace = (int) (mSize - mBarThickness * 3 - mBarGap * 2);
         mCenterOffset = (remainingSpace / 4) * 2; //making sure it is a multiple of 2.
         mCenterOffset += mBarThickness * 1.5 + mBarGap;
-        typedArray.recycle();
+        a.recycle();
 
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeJoin(Paint.Join.MITER);
@@ -98,19 +126,38 @@
         mMaxCutForBarSize = (float) (mBarThickness / 2 * Math.cos(ARROW_HEAD_ANGLE));
     }
 
-    abstract boolean isLayoutRtl();
+    /**
+     * Set the arrow direction.
+     */
+    public void setDirection(@ArrowDirection int direction) {
+        if (direction != mDirection) {
+            mDirection = direction;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * Returns the arrow direction.
+     */
+    @ArrowDirection
+    public int getDirection() {
+        return mDirection;
+    }
 
     /**
      * If set, canvas is flipped when progress reached to end and going back to start.
      */
-    protected void setVerticalMirror(boolean verticalMirror) {
-        mVerticalMirror = verticalMirror;
+    public void setVerticalMirror(boolean verticalMirror) {
+        if (mVerticalMirror != verticalMirror) {
+            mVerticalMirror = verticalMirror;
+            invalidateSelf();
+        }
     }
 
     @Override
     public void draw(Canvas canvas) {
         Rect bounds = getBounds();
-        final boolean isRtl = isLayoutRtl();
+        final boolean flipToPointRight = mDirection == ARROW_DIRECTION_RIGHT;
         // Interpolated widths of arrow bars
         final float arrowSize = lerp(mBarSize, mTopBottomArrowSize, mProgress);
         final float middleBarSize = lerp(mBarSize, mMiddleArrowSize, mProgress);
@@ -120,11 +167,12 @@
         final float rotation = lerp(0, ARROW_HEAD_ANGLE, mProgress);
 
         // The whole canvas rotates as the transition happens
-        final float canvasRotate = lerp(isRtl ? 0 : -180, isRtl ? 180 : 0, mProgress);
+        final float canvasRotate = lerp(flipToPointRight ? 0 : -180,
+                flipToPointRight ? 180 : 0, mProgress);
+
         final float arrowWidth = Math.round(arrowSize * Math.cos(rotation));
         final float arrowHeight = Math.round(arrowSize * Math.sin(rotation));
 
-
         mPath.rewind();
         final float topBottomBarOffset = lerp(mBarGap + mBarThickness, -mMaxCutForBarSize,
                 mProgress);
@@ -149,8 +197,8 @@
         // the arrow pointing the other way for RTL.
         canvas.translate(bounds.centerX(), mCenterOffset);
         if (mSpin) {
-            canvas.rotate(canvasRotate * ((mVerticalMirror ^ isRtl) ? -1 : 1));
-        } else if (isRtl) {
+            canvas.rotate(canvasRotate * ((mVerticalMirror ^ flipToPointRight) ? -1 : 1));
+        } else if (flipToPointRight) {
             canvas.rotate(180);
         }
         canvas.drawPath(mPath, mPaint);
@@ -159,14 +207,8 @@
     }
 
     @Override
-    public void setAlpha(int i) {
-        mPaint.setAlpha(i);
-    }
-
-    // override
-    public boolean isAutoMirrored() {
-        // Draws rotated 180 degrees in RTL mode.
-        return true;
+    public void setAlpha(int alpha) {
+        mPaint.setAlpha(alpha);
     }
 
     @Override
@@ -189,11 +231,22 @@
         return PixelFormat.TRANSLUCENT;
     }
 
+    /**
+     * Returns the current progress of the arrow.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
     public float getProgress() {
         return mProgress;
     }
 
-    public void setProgress(float progress) {
+    /**
+     * Set the progress of the arrow.
+     *
+     * <p>A value of {@code 0.0} indicates that the arrow should be drawn in it's starting
+     * position. A value of {@code 1.0} indicates that the arrow should be drawn in it's ending
+     * position.</p>
+     */
+    public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
         mProgress = progress;
         invalidateSelf();
     }