Merge "Add proguard rule for CoordinatorLayout.Bahavior" into lmp-mr1-ub-dev
diff --git a/design/res/layout/design_layout_snackbar_include.xml b/design/res/layout/design_layout_snackbar_include.xml
index f1fd08e..0e0cde4 100644
--- a/design/res/layout/design_layout_snackbar_include.xml
+++ b/design/res/layout/design_layout_snackbar_include.xml
@@ -31,19 +31,19 @@
             android:layout_gravity="center_vertical|left|start"
             android:ellipsize="end"/>
 
-    <TextView
+    <Button
             android:id="@+id/snackbar_action"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginLeft="@dimen/design_snackbar_extra_spacing_horizontal"
             android:layout_marginStart="@dimen/design_snackbar_extra_spacing_horizontal"
             android:layout_gravity="center_vertical|right|end"
-            android:background="?attr/selectableItemBackground"
             android:paddingTop="@dimen/design_snackbar_padding_vertical"
             android:paddingBottom="@dimen/design_snackbar_padding_vertical"
             android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
             android:paddingRight="@dimen/design_snackbar_padding_horizontal"
             android:visibility="gone"
-            android:textAppearance="@style/TextAppearance.Design.Snackbar.Action"/>
+            android:textColor="?attr/colorAccent"
+            style="?attr/borderlessButtonStyle"/>
 
 </merge>
\ No newline at end of file
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index 034809d..c7f8cef 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -16,7 +16,7 @@
 -->
 <resources>
 
-    <dimen name="design_fab_elevation">8dp</dimen>
+    <dimen name="design_fab_elevation">6dp</dimen>
     <dimen name="design_fab_translation_z_pressed">6dp</dimen>
     <dimen name="design_fab_content_size">24dp</dimen>
     <dimen name="design_fab_size_normal">56dp</dimen>
@@ -24,7 +24,7 @@
     <dimen name="design_fab_border_width">0.5dp</dimen>
 
     <dimen name="design_navigation_max_width">320dp</dimen>
-    <dimen name="design_navigation_elevation">12dp</dimen>
+    <dimen name="design_navigation_elevation">16dp</dimen>
     <dimen name="design_navigation_icon_padding">32dp</dimen>
     <dimen name="design_navigation_icon_size">24dp</dimen>
     <dimen name="design_navigation_separator_vertical_padding">8dp</dimen>
@@ -36,7 +36,7 @@
 
     <dimen name="design_snackbar_min_width">-1px</dimen>
     <dimen name="design_snackbar_max_width">-1px</dimen>
-    <dimen name="design_snackbar_elevation">2dp</dimen>
+    <dimen name="design_snackbar_elevation">6dp</dimen>
     <dimen name="design_snackbar_background_corner_radius">0dp</dimen>
 
     <dimen name="design_snackbar_padding_horizontal">12dp</dimen>
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index 8736183..6624894 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -77,10 +77,6 @@
         <item name="android:textColor">?android:textColorPrimary</item>
     </style>
 
-    <style name="TextAppearance.Design.Snackbar.Action" parent="TextAppearance.AppCompat.Button">
-        <item name="android:textColor">?colorAccent</item>
-    </style>
-
     <style name="Widget.Design.Snackbar" parent="android:Widget">
         <item name="android:theme">@style/ThemeOverlay.AppCompat.Dark</item>
         <item name="android:minWidth">@dimen/design_snackbar_min_width</item>
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index 9808e5e..12024ba 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -33,9 +33,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -130,7 +128,7 @@
 
     private WindowInsetsCompat mLastInsets;
 
-    private final List<WeakReference<OnOffsetChangedListener>> mListeners;
+    private final List<OnOffsetChangedListener> mListeners;
 
     public AppBarLayout(Context context) {
         this(context, null);
@@ -175,14 +173,9 @@
      * @see #removeOnOffsetChangedListener(OnOffsetChangedListener)
      */
     public void addOnOffsetChangedListener(OnOffsetChangedListener listener) {
-        for (int i = 0, z = mListeners.size(); i < z; i++) {
-            final WeakReference<OnOffsetChangedListener> ref = mListeners.get(i);
-            if (ref != null && ref.get() == listener) {
-                // Listener already added
-                return;
-            }
+        if (listener != null && !mListeners.contains(listener)) {
+            mListeners.add(listener);
         }
-        mListeners.add(new WeakReference<>(listener));
     }
 
     /**
@@ -191,14 +184,8 @@
      * @param listener the listener to remove.
      */
     public void removeOnOffsetChangedListener(OnOffsetChangedListener listener) {
-        final Iterator<WeakReference<OnOffsetChangedListener>> i = mListeners.iterator();
-        while (i.hasNext()) {
-            final WeakReference<OnOffsetChangedListener> ref = i.next();
-            final OnOffsetChangedListener item = ref.get();
-            if (item == listener || item == null) {
-                // If the item is null, or is our given listener, remove
-                i.remove();
-            }
+        if (listener != null) {
+            mListeners.remove(listener);
         }
     }
 
@@ -915,14 +902,12 @@
         }
 
         private void dispatchOffsetUpdates(AppBarLayout layout) {
-            final List<WeakReference<OnOffsetChangedListener>> listeners = layout.mListeners;
+            final List<OnOffsetChangedListener> listeners = layout.mListeners;
 
             // Iterate backwards through the list so that most recently added listeners
             // get the first chance to decide
             for (int i = 0, z = listeners.size(); i < z; i++) {
-                final WeakReference<OnOffsetChangedListener> ref = listeners.get(i);
-                final OnOffsetChangedListener listener = ref != null ? ref.get() : null;
-
+                final OnOffsetChangedListener listener = listeners.get(i);
                 if (listener != null) {
                     listener.onOffsetChanged(layout, getTopAndBottomOffset());
                 }
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 2a19fa8..4e325fa 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -77,7 +77,7 @@
     private static final int PRESENTER_NAVIGATION_VIEW_ID = 1;
 
     private final NavigationMenu mMenu;
-    private final NavigationMenuPresenter mPresenter;
+    private final NavigationMenuPresenter mPresenter = new NavigationMenuPresenter();
 
     private OnNavigationItemSelectedListener mListener;
     private int mMaxWidth;
@@ -140,10 +140,6 @@
 
         final Drawable itemBackground = a.getDrawable(R.styleable.NavigationView_itemBackground);
 
-        if (a.hasValue(R.styleable.NavigationView_menu)) {
-            inflateMenu(a.getResourceId(R.styleable.NavigationView_menu, 0));
-        }
-
         mMenu.setCallback(new MenuBuilder.Callback() {
             @Override
             public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
@@ -153,7 +149,6 @@
             @Override
             public void onMenuModeChange(MenuBuilder menu) {}
         });
-        mPresenter = new NavigationMenuPresenter();
         mPresenter.setId(PRESENTER_NAVIGATION_VIEW_ID);
         mPresenter.initForMenu(context, mMenu);
         mPresenter.setItemIconTintList(itemIconTint);
@@ -165,6 +160,10 @@
         mMenu.addMenuPresenter(mPresenter);
         addView((View) mPresenter.getMenuView(this));
 
+        if (a.hasValue(R.styleable.NavigationView_menu)) {
+            inflateMenu(a.getResourceId(R.styleable.NavigationView_menu, 0));
+        }
+
         if (a.hasValue(R.styleable.NavigationView_headerLayout)) {
             inflateHeaderView(a.getResourceId(R.styleable.NavigationView_headerLayout, 0));
         }
@@ -224,14 +223,10 @@
      * @param resId ID of a menu resource to inflate
      */
     public void inflateMenu(int resId) {
-        if (mPresenter != null) {
-            mPresenter.setUpdateSuspended(true);
-        }
+        mPresenter.setUpdateSuspended(true);
         getMenuInflater().inflate(resId, mMenu);
-        if (mPresenter != null) {
-            mPresenter.setUpdateSuspended(false);
-            mPresenter.updateMenuView(false);
-        }
+        mPresenter.setUpdateSuspended(false);
+        mPresenter.updateMenuView(false);
     }
 
     /**
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index aa1a291..e0c17ef 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -38,6 +38,7 @@
 import android.view.ViewParent;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -548,7 +549,7 @@
      */
     public static class SnackbarLayout extends LinearLayout {
         private TextView mMessageView;
-        private TextView mActionView;
+        private Button mActionView;
 
         private int mMaxWidth;
         private int mMaxInlineActionWidth;
@@ -587,14 +588,14 @@
         protected void onFinishInflate() {
             super.onFinishInflate();
             mMessageView = (TextView) findViewById(R.id.snackbar_text);
-            mActionView = (TextView) findViewById(R.id.snackbar_action);
+            mActionView = (Button) findViewById(R.id.snackbar_action);
         }
 
         TextView getMessageView() {
             return mMessageView;
         }
 
-        TextView getActionView() {
+        Button getActionView() {
             return mActionView;
         }
 
diff --git a/v4/api/current.txt b/v4/api/current.txt
index ec5ae3e..45912fb 100644
--- a/v4/api/current.txt
+++ b/v4/api/current.txt
@@ -1044,8 +1044,10 @@
     method public final android.graphics.Paint getPaint();
     method public boolean hasAntiAlias();
     method public boolean hasMipMap();
+    method public boolean isCircular();
     method public void setAlpha(int);
     method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setCornerRadius(float);
     method public void setGravity(int);
diff --git a/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java b/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
index 7231a38..0256ebb 100644
--- a/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
+++ b/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
@@ -41,7 +41,7 @@
  */
 public abstract class RoundedBitmapDrawable extends Drawable {
     private static final int DEFAULT_PAINT_FLAGS =
-            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
+            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG;
     Bitmap mBitmap;
     private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
     private int mGravity = Gravity.FILL;
@@ -53,8 +53,9 @@
     final RectF mDstRectF = new RectF();
 
     private boolean mApplyGravity = true;
+    private boolean mIsCircular;
 
-     // These are scaled to match the target density.
+    // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
 
@@ -217,8 +218,12 @@
 
     void updateDstRect() {
         if (mApplyGravity) {
-            gravityCompatApply(mGravity, mBitmapWidth, mBitmapHeight,
-                    getBounds(), mDstRect);
+            if (mIsCircular) {
+                final int minDimen = Math.min(mBitmapWidth, mBitmapHeight);
+                gravityCompatApply(Gravity.CENTER, minDimen, minDimen, getBounds(), mDstRect);
+            } else {
+                gravityCompatApply(mGravity, mBitmapWidth, mBitmapHeight, getBounds(), mDstRect);
+            }
             mDstRectF.set(mDstRect);
             mApplyGravity = false;
         }
@@ -266,6 +271,35 @@
     }
 
     /**
+     * Sets the image shape to circular.
+     * <p>This overwrites any calls made to {@link #setCornerRadius(float)} so far.</p>
+     * <p>Further, circular images are being placed using {@link Gravity#CENTER}.</p>
+     */
+    public void setCircular(boolean circular) {
+        mIsCircular = circular;
+        mApplyGravity = true;
+        if (circular) {
+            updateCircularCornerRadius();
+            mPaint.setShader(getDefaultShader());
+            invalidateSelf();
+        } else {
+            setCornerRadius(0);
+        }
+    }
+
+    private void updateCircularCornerRadius() {
+        final int minCircularSize = Math.min(mBitmapHeight, mBitmapWidth);
+        mCornerRadius = minCircularSize / 2;
+    }
+
+    /**
+     * @return <code>true</code> if the image is circular, else <code>false</code>.
+     */
+    public boolean isCircular() {
+        return mIsCircular;
+    }
+
+    /**
      * Sets the corner radius to be applied when drawing the bitmap.
      */
     public void setCornerRadius(float cornerRadius) {
@@ -274,7 +308,19 @@
         } else {
             mPaint.setShader(null);
         }
-        mCornerRadius = cornerRadius;
+        if (mCornerRadius != cornerRadius) {
+            invalidateSelf();
+            mCornerRadius = cornerRadius;
+        }
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        if (mIsCircular) {
+            updateCircularCornerRadius();
+            mApplyGravity = true;
+        }
     }
 
     /**
@@ -296,7 +342,7 @@
 
     @Override
     public int getOpacity() {
-        if (mGravity != Gravity.FILL) {
+        if (mGravity != Gravity.FILL || mIsCircular) {
             return PixelFormat.TRANSLUCENT;
         }
         Bitmap bm = mBitmap;
@@ -315,12 +361,19 @@
         mBitmap = bitmap;
         if (mBitmap != null) {
             computeBitmapSize();
-            mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+            mBitmapShader = getDefaultShader();
         } else {
             mBitmapWidth = mBitmapHeight = -1;
         }
     }
 
+    private BitmapShader getDefaultShader() {
+        if (mBitmapShader == null) {
+            mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        }
+        return mBitmapShader;
+    }
+
     private static boolean isGreaterThanZero(float toCompare) {
         return Float.compare(toCompare, +0.0f) > 0;
     }
diff --git a/v4/java/android/support/v4/view/ActionProvider.java b/v4/java/android/support/v4/view/ActionProvider.java
index f11876a..d195a3a 100644
--- a/v4/java/android/support/v4/view/ActionProvider.java
+++ b/v4/java/android/support/v4/view/ActionProvider.java
@@ -242,6 +242,14 @@
     }
 
     /**
+     * @hide
+     */
+    public void reset() {
+        mVisibilityListener = null;
+        mSubUiVisibilityListener = null;
+    }
+
+    /**
      * @hide Internal use only
      */
     public interface SubUiVisibilityListener {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
index d38faf9..ffddb31 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
@@ -654,7 +654,7 @@
     @Override
     public SupportMenuItem setSupportActionProvider(ActionProvider actionProvider) {
         if (mActionProvider != null) {
-            mActionProvider.setVisibilityListener(null);
+            mActionProvider.reset();
         }
         mActionView = null;
         mActionProvider = actionProvider;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
index 999fc6d..cfad4b4 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
@@ -210,7 +211,7 @@
         final Context context = mContextRef.get();
         if (context == null) return false;
 
-        PorterDuff.Mode tintMode = null;
+        PorterDuff.Mode tintMode = DEFAULT_MODE;
         boolean colorAttrSet = false;
         int colorAttr = 0;
         int alpha = -1;
@@ -233,7 +234,7 @@
 
         if (colorAttrSet) {
             final int color = getThemeAttrColor(context, colorAttr);
-            setPorterDuffColorFilter(drawable, color, tintMode);
+            drawable.setColorFilter(getPorterDuffColorFilter(color, tintMode));
 
             if (alpha != -1) {
                 drawable.setAlpha(alpha);
@@ -554,12 +555,11 @@
 
     public static void tintViewBackground(View view, TintInfo tint) {
         final Drawable background = view.getBackground();
-        if (tint.mHasTintList) {
-            setPorterDuffColorFilter(
-                    background,
-                    tint.mTintList.getColorForState(view.getDrawableState(),
-                            tint.mTintList.getDefaultColor()),
-                    tint.mHasTintMode ? tint.mTintMode : null);
+        if (tint.mHasTintList || tint.mHasTintMode) {
+            background.setColorFilter(createTintFilter(
+                    tint.mHasTintList ? tint.mTintList : null,
+                    tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
+                    view.getDrawableState()));
         } else {
             background.clearColorFilter();
         }
@@ -571,12 +571,16 @@
         }
     }
 
-    private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {
-        if (mode == null) {
-            // If we don't have a blending mode specified, use our default
-            mode = DEFAULT_MODE;
+    private static PorterDuffColorFilter createTintFilter(ColorStateList tint,
+            PorterDuff.Mode tintMode, final int[] state) {
+        if (tint == null || tintMode == null) {
+            return null;
         }
+        final int color = tint.getColorForState(state, Color.TRANSPARENT);
+        return getPorterDuffColorFilter(color, tintMode);
+    }
 
+    private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
         // First, lets see if the cache already contains the color filter
         PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
 
@@ -586,6 +590,6 @@
             COLOR_FILTER_CACHE.put(color, mode, filter);
         }
 
-        d.setColorFilter(filter);
+        return filter;
     }
 }