Merge "Allow AppBarLayout to handle size changes" into lmp-mr1-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index 615ae54..217ba99 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -195,8 +195,10 @@
     method public void setItemBackground(android.graphics.drawable.Drawable);
     method public void setItemBackgroundResource(int);
     method public void setItemIconTintList(android.content.res.ColorStateList);
+    method public void setItemTextAppearance(int);
     method public void setItemTextColor(android.content.res.ColorStateList);
     method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
+    method public void setCheckedItem(int);
   }
 
   public static abstract interface NavigationView.OnNavigationItemSelectedListener {
@@ -336,6 +338,7 @@
     method public void setError(java.lang.CharSequence);
     method public void setErrorEnabled(boolean);
     method public void setHint(java.lang.CharSequence);
+    method public void setTypeface(android.graphics.Typeface);
   }
 
    class ViewOffsetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
diff --git a/design/base/android/support/design/widget/CircularBorderDrawable.java b/design/base/android/support/design/widget/CircularBorderDrawable.java
index f522277..ff57777 100644
--- a/design/base/android/support/design/widget/CircularBorderDrawable.java
+++ b/design/base/android/support/design/widget/CircularBorderDrawable.java
@@ -50,6 +50,8 @@
     private int mBottomOuterStrokeColor;
     private int mBottomInnerStrokeColor;
 
+    private int mTintColor;
+
     private boolean mInvalidateShader = true;
 
     public CircularBorderDrawable() {
@@ -113,6 +115,12 @@
         invalidateSelf();
     }
 
+    void setTintColor(int tintColor) {
+        mTintColor = tintColor;
+        mInvalidateShader = true;
+        invalidateSelf();
+    }
+
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
         mPaint.setColorFilter(colorFilter);
@@ -140,12 +148,14 @@
         final float borderRatio = mBorderWidth / rect.height();
 
         final int[] colors = new int[6];
-        colors[0] = mTopOuterStrokeColor;
-        colors[1] = mTopInnerStrokeColor;
-        colors[2] = ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0);
-        colors[3] = ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0);
-        colors[4] = mBottomInnerStrokeColor;
-        colors[5] = mBottomOuterStrokeColor;
+        colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mTintColor);
+        colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mTintColor);
+        colors[2] = ColorUtils.compositeColors(
+                ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mTintColor);
+        colors[3] = ColorUtils.compositeColors(
+                ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mTintColor);
+        colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mTintColor);
+        colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mTintColor);
 
         final float[] positions = new float[6];
         positions[0] = 0f;
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index c17aea8..6c154d4 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -66,11 +66,8 @@
                 resources.getColor(R.color.fab_stroke_end_inner_color),
                 resources.getColor(R.color.fab_stroke_end_outer_color));
         borderDrawable.setBorderWidth(borderWidth);
-
-        Drawable d = DrawableCompat.wrap(borderDrawable);
-        DrawableCompat.setTintList(d, backgroundTint);
-        DrawableCompat.setTintMode(d, PorterDuff.Mode.DST_OVER);
-        return d;
+        borderDrawable.setTintColor(backgroundTint.getDefaultColor());
+        return borderDrawable;
     }
 
     CircularBorderDrawable newCircularDrawable() {
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index e4c1bf0..9702497 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -51,6 +51,7 @@
         <attr name="itemIconTint" format="color"/>
         <attr name="itemTextColor" format="color"/>
         <attr name="itemBackground" format="reference"/>
+        <attr name="itemTextAppearance" format="reference"/>
         <!-- Layout resource to inflate as the header -->
         <attr name="headerLayout" format="reference"/>
     </declare-styleable>
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index 4e03029..067846c 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -23,7 +23,7 @@
         <item name="elevation">@dimen/fab_elevation</item>
         <item name="pressedTranslationZ">@dimen/fab_translation_z_pressed</item>
         <item name="rippleColor">?attr/colorControlHighlight</item>
-        <item name="borderWidth">0dp</item>
+        <item name="borderWidth">@dimen/fab_border_width</item>
     </style>
 
     <style name="Widget.Design.ScrimInsetsFrameLayout" parent="">
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index 55a7594..f19b78a 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -26,6 +26,7 @@
 import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
 import android.support.design.R;
 import android.support.v7.internal.view.menu.MenuBuilder;
 import android.support.v7.internal.view.menu.MenuItemImpl;
@@ -63,6 +64,8 @@
     private NavigationMenuAdapter mAdapter;
     private LayoutInflater mLayoutInflater;
 
+    private int mTextAppearance;
+    private boolean mTextAppearanceSet;
     private ColorStateList mTextColor;
     private ColorStateList mIconTintList;
     private Drawable mItemBackground;
@@ -184,10 +187,21 @@
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         int positionInAdapter = position - mMenuView.getHeaderViewsCount();
         if (positionInAdapter >= 0) {
-            mMenu.performItemAction(mAdapter.getItem(positionInAdapter).getMenuItem(), this, 0);
+            setUpdateSuspended(true);
+            MenuItemImpl item = mAdapter.getItem(positionInAdapter).getMenuItem();
+            if (item != null && item.isCheckable()) {
+                setCheckedItem(item);
+            }
+            mMenu.performItemAction(item, this, 0);
+            setUpdateSuspended(false);
+            updateMenuView(false);
         }
     }
 
+    public void setCheckedItem(MenuItemImpl item) {
+        mAdapter.setCheckedItem(item);
+    }
+
     public View inflateHeaderView(@LayoutRes int res) {
         View view = mLayoutInflater.inflate(res, mHeader, false);
         addHeaderView(view);
@@ -214,6 +228,7 @@
 
     public void setItemIconTintList(@Nullable ColorStateList tint) {
         mIconTintList = tint;
+        updateMenuView(false);
     }
 
     @Nullable
@@ -223,6 +238,13 @@
 
     public void setItemTextColor(@Nullable ColorStateList textColor) {
         mTextColor = textColor;
+        updateMenuView(false);
+    }
+
+    public void setItemTextAppearance(@StyleRes int resId) {
+        mTextAppearance = resId;
+        mTextAppearanceSet = true;
+        updateMenuView(false);
     }
 
     public Drawable getItemBackground() {
@@ -233,15 +255,22 @@
         mItemBackground = itemBackground;
     }
 
+    public void setUpdateSuspended(boolean updateSuspended) {
+        if (mAdapter != null) {
+            mAdapter.setUpdateSuspended(updateSuspended);
+        }
+    }
+
     private class NavigationMenuAdapter extends BaseAdapter {
 
-        private static final String STATE_CHECKED_ITEMS = "android:menu:checked";
+        private static final String STATE_CHECKED_ITEM = "android:menu:checked";
 
         private static final int VIEW_TYPE_NORMAL = 0;
         private static final int VIEW_TYPE_SUBHEADER = 1;
         private static final int VIEW_TYPE_SEPARATOR = 2;
 
         private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
+        private MenuItemImpl mCheckedItem;
         private ColorDrawable mTransparentIcon;
         private boolean mUpdateSuspended;
 
@@ -293,7 +322,12 @@
                     }
                     NavigationMenuItemView itemView = (NavigationMenuItemView) convertView;
                     itemView.setIconTintList(mIconTintList);
-                    itemView.setTextColor(mTextColor);
+                    if (mTextAppearanceSet) {
+                        itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
+                    }
+                    if (mTextColor != null) {
+                        itemView.setTextColor(mTextColor);
+                    }
                     itemView.setBackgroundDrawable(mItemBackground);
                     itemView.initialize(item.getMenuItem(), 0);
                     break;
@@ -347,6 +381,12 @@
             boolean currentGroupHasIcon = false;
             for (int i = 0, totalSize = mMenu.getVisibleItems().size(); i < totalSize; i++) {
                 MenuItemImpl item = mMenu.getVisibleItems().get(i);
+                if (item.isChecked()) {
+                    setCheckedItem(item);
+                }
+                if (item.isCheckable()) {
+                    item.setExclusiveCheckable(false);
+                }
                 if (item.hasSubMenu()) {
                     SubMenu subMenu = item.getSubMenu();
                     if (subMenu.hasVisibleItems()) {
@@ -357,12 +397,18 @@
                         boolean subMenuHasIcon = false;
                         int subMenuStart = mItems.size();
                         for (int j = 0, size = subMenu.size(); j < size; j++) {
-                            MenuItem subMenuItem = subMenu.getItem(j);
+                            MenuItemImpl subMenuItem = (MenuItemImpl) subMenu.getItem(j);
                             if (subMenuItem.isVisible()) {
                                 if (!subMenuHasIcon && subMenuItem.getIcon() != null) {
                                     subMenuHasIcon = true;
                                 }
-                                mItems.add(NavigationMenuItem.of((MenuItemImpl) subMenuItem));
+                                if (subMenuItem.isCheckable()) {
+                                    subMenuItem.setExclusiveCheckable(false);
+                                }
+                                if (item.isChecked()) {
+                                    setCheckedItem(item);
+                                }
+                                mItems.add(NavigationMenuItem.of(subMenuItem));
                             }
                         }
                         if (subMenuHasIcon) {
@@ -404,27 +450,32 @@
             }
         }
 
+        public void setCheckedItem(MenuItemImpl checkedItem) {
+            if (mCheckedItem == checkedItem || !checkedItem.isCheckable()) {
+                return;
+            }
+            if (mCheckedItem != null) {
+                mCheckedItem.setChecked(false);
+            }
+            mCheckedItem = checkedItem;
+            checkedItem.setChecked(true);
+        }
+
         public Bundle createInstanceState() {
             Bundle state = new Bundle();
-            ArrayList<Integer> checkedItems = new ArrayList<>();
-            for (NavigationMenuItem item : mItems) {
-                MenuItemImpl menuItem = item.getMenuItem();
-                if (menuItem != null && menuItem.isChecked()) {
-                    checkedItems.add(menuItem.getItemId());
-                }
-            }
-            state.putIntegerArrayList(STATE_CHECKED_ITEMS, checkedItems);
+            state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId());
             return state;
         }
 
         public void restoreInstanceState(Bundle state) {
-            ArrayList<Integer> checkedItems = state.getIntegerArrayList(STATE_CHECKED_ITEMS);
-            if (checkedItems != null) {
+            int checkedItem = state.getInt(STATE_CHECKED_ITEM, 0);
+            if (checkedItem != 0) {
                 mUpdateSuspended = true;
                 for (NavigationMenuItem item : mItems) {
                     MenuItemImpl menuItem = item.getMenuItem();
-                    if (menuItem != null && checkedItems.contains(menuItem.getItemId())) {
-                        menuItem.setChecked(true);
+                    if (menuItem !=  null && menuItem.getItemId() == checkedItem) {
+                        setCheckedItem(menuItem);
+                        break;
                     }
                 }
                 mUpdateSuspended = false;
@@ -432,6 +483,10 @@
             }
         }
 
+        public void setUpdateSuspended(boolean updateSuspended) {
+            mUpdateSuspended = updateSuspended;
+        }
+
     }
 
     /**
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 437e2d1..636770e 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -22,6 +22,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.Typeface;
 import android.os.Build;
 import android.support.design.R;
 import android.support.v4.text.TextDirectionHeuristicsCompat;
@@ -136,12 +137,10 @@
 
     void setExpandedBounds(int left, int top, int right, int bottom) {
         mExpandedBounds.set(left, top, right, bottom);
-        recalculate();
     }
 
     void setCollapsedBounds(int left, int top, int right, int bottom) {
         mCollapsedBounds.set(left, top, right, bottom);
-        recalculate();
     }
 
     void setExpandedTextVerticalGravity(int gravity) {
@@ -190,6 +189,20 @@
         recalculate();
     }
 
+    void setTypeface(Typeface typeface) {
+        if (typeface == null) {
+            typeface = Typeface.DEFAULT;
+        }
+        if (mTextPaint.getTypeface() != typeface) {
+            mTextPaint.setTypeface(typeface);
+            recalculate();
+        }
+    }
+
+    Typeface getTypeface() {
+        return mTextPaint.getTypeface();
+    }
+
     /**
      * Set the value indicating the current scroll value. This decides how much of the
      * background will be displayed, as well as the title metrics/positioning.
@@ -425,8 +438,8 @@
         }
     }
 
-    private void recalculate() {
-        if (ViewCompat.isLaidOut(mView)) {
+    public void recalculate() {
+        if (mView.getHeight() > 0 && mView.getWidth() > 0) {
             // If we've already been laid out, calculate everything now otherwise we'll wait
             // until a layout
             calculateBaselines();
@@ -442,6 +455,7 @@
     void setText(CharSequence text) {
         if (text == null || !text.equals(mText)) {
             mText = text;
+            mTextToDraw = null;
             clearTexture();
             recalculate();
         }
@@ -458,10 +472,6 @@
         }
     }
 
-    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        recalculate();
-    }
-
     /**
      * Returns true if {@code value} is 'close' to it's closest decimal value. Close is currently
      * defined as it's difference being < 0.001.
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 474a0a8..b2b55f7 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -332,9 +332,6 @@
             getViewOffsetHelper(child).onViewLayout();
         }
 
-        // Now let the collapsing text helper update itself
-        mCollapsingTextHelper.onLayout(changed, left, top, right, bottom);
-
         ensureToolbar();
 
         // Update the collapsed bounds by getting it's transformed bounds
@@ -346,6 +343,8 @@
             mCollapsingTextHelper.setExpandedBounds(left + mExpandedMarginLeft,
                     mTmpRect.bottom + mExpandedMarginTop, right - mExpandedMarginRight,
                     bottom - mExpandedMarginBottom);
+
+            mCollapsingTextHelper.recalculate();
         }
 
         // Finally, set our minimum height to enable proper AppBarLayout collapsing
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index e23ba02..e2081b7 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -32,6 +32,7 @@
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.view.GravityCompat;
+import android.support.v4.view.MotionEventCompat;
 import android.support.v4.view.NestedScrollingParent;
 import android.support.v4.view.NestedScrollingParentHelper;
 import android.support.v4.view.ViewCompat;
@@ -314,7 +315,7 @@
 
         MotionEvent cancelEvent = null;
 
-        final int action = ev.getActionMasked();
+        final int action = MotionEventCompat.getActionMasked(ev);
 
         final List<View> topmostChildList = mTempList1;
         getTopSortedChildren(topmostChildList);
@@ -366,7 +367,7 @@
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         MotionEvent cancelEvent = null;
 
-        final int action = ev.getActionMasked();
+        final int action = MotionEventCompat.getActionMasked(ev);
 
         // Make sure we reset in case we had missed a previous important event.
         if (action == MotionEvent.ACTION_DOWN) {
@@ -392,7 +393,7 @@
         boolean cancelSuper = false;
         MotionEvent cancelEvent = null;
 
-        final int action = ev.getActionMasked();
+        final int action = MotionEventCompat.getActionMasked(ev);
 
         if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev))) {
             // Safe since performIntercept guarantees that
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 02dfa3c..3e83863 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -24,9 +24,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.DrawableRes;
+import android.support.annotation.IdRes;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
 import android.support.design.R;
 import android.support.design.internal.NavigationMenuPresenter;
 import android.support.design.internal.ScrimInsetsFrameLayout;
@@ -34,6 +36,7 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v7.internal.view.SupportMenuInflater;
 import android.support.v7.internal.view.menu.MenuBuilder;
+import android.support.v7.internal.view.menu.MenuItemImpl;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Menu;
@@ -117,10 +120,20 @@
             itemIconTint = createDefaultColorStateList(android.R.attr.textColorSecondary);
         }
 
-        final ColorStateList itemTextColor;
+        boolean textAppearanceSet = false;
+        int textAppearance = 0;
+        if (a.hasValue(R.styleable.NavigationView_itemTextAppearance)) {
+            textAppearance = a.getResourceId(R.styleable.NavigationView_itemTextAppearance, 0);
+            textAppearanceSet = true;
+        }
+
+        ColorStateList itemTextColor = null;
         if (a.hasValue(R.styleable.NavigationView_itemTextColor)) {
             itemTextColor = a.getColorStateList(R.styleable.NavigationView_itemTextColor);
-        } else {
+        }
+
+        if (!textAppearanceSet && itemTextColor == null) {
+            // If there isn't a text appearance set, we'll use a default text color
             itemTextColor = createDefaultColorStateList(android.R.attr.textColorPrimary);
         }
 
@@ -143,6 +156,9 @@
         mPresenter.setId(PRESENTER_NAVIGATION_VIEW_ID);
         mPresenter.initForMenu(context, mMenu);
         mPresenter.setItemIconTintList(itemIconTint);
+        if (textAppearanceSet) {
+            mPresenter.setItemTextAppearance(textAppearance);
+        }
         mPresenter.setItemTextColor(itemTextColor);
         mPresenter.setItemBackground(itemBackground);
         mMenu.addMenuPresenter(mPresenter);
@@ -207,7 +223,14 @@
      * @param resId ID of a menu resource to inflate
      */
     public void inflateMenu(int resId) {
+        if (mPresenter != null) {
+            mPresenter.setUpdateSuspended(true);
+        }
         getMenuInflater().inflate(resId, mMenu);
+        if (mPresenter != null) {
+            mPresenter.setUpdateSuspended(false);
+            mPresenter.updateMenuView(false);
+        }
     }
 
     /**
@@ -323,6 +346,27 @@
         mPresenter.setItemBackground(itemBackground);
     }
 
+    /**
+     * Sets the currently checked item in this navigation menu.
+     *
+     * @param id The item ID of the currently checked item.
+     */
+    public void setCheckedItem(@IdRes int id) {
+        MenuItem item = mMenu.findItem(id);
+        if (item != null) {
+            mPresenter.setCheckedItem((MenuItemImpl) item);
+        }
+    }
+
+    /**
+     * Set the text appearance of the menu items to a given resource.
+     *
+     * @attr ref R.styleable#NavigationView_itemTextAppearance
+     */
+    public void setItemTextAppearance(@StyleRes int resId) {
+        mPresenter.setItemTextAppearance(resId);
+    }
+
     private MenuInflater getMenuInflater() {
         if (mMenuInflater == null) {
             mMenuInflater = new SupportMenuInflater(getContext());
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 6282146..884e538 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Typeface;
 import android.os.Handler;
 import android.os.Message;
 import android.support.design.R;
@@ -49,6 +50,24 @@
  *
  * Also supports showing an error via {@link #setErrorEnabled(boolean)} and
  * {@link #setError(CharSequence)}.
+ *
+ * <p>Please note: this class sets a {@link android.view.View.OnFocusChangeListener} on the wrapped
+ * {@link EditText}. If you need to set your own listener, then you should wrap the existing one
+ * and forward the call like so:
+ * <pre>
+ * TextInputLayout inputLayout = ...;
+ * EditText editText = inputLayout.getEditText();
+ * final OnFocusChangeListener existing = editText.getOnFocusChangeListener();
+ *
+ * editText.setOnFocusChangeListener(new OnFocusChangeListener() {
+ *     public void onFocusChange(View view, boolean focused) {
+ *         existing.onFocusChange(view, focused);
+ *
+ *         // Your custom logic
+ *     }
+ * });
+ * </pre>
+ * </p>
  */
 public class TextInputLayout extends LinearLayout {
 
@@ -144,6 +163,15 @@
         }
     }
 
+    /**
+     * Set the typeface to use for the both the expanded and floating hint.
+     *
+     * @param typeface typeface to use, or {@code null} to use the default.
+     */
+    public void setTypeface(Typeface typeface) {
+        mCollapsingTextHelper.setTypeface(typeface);
+    }
+
     private LayoutParams setEditText(EditText editText, ViewGroup.LayoutParams lp) {
         // If we already have an EditText, throw an exception
         if (mEditText != null) {
@@ -151,7 +179,8 @@
         }
         mEditText = editText;
 
-        // Use the EditText's text size for our expanded text
+        // Use the EditText's typeface, and it's text size for our expanded text
+        mCollapsingTextHelper.setTypeface(mEditText.getTypeface());
         mCollapsingTextHelper.setExpandedTextSize(mEditText.getTextSize());
 
         // Add a TextWatcher so that we know when the text input has changed
@@ -199,6 +228,7 @@
         // to the EditText so make room for the label
         LayoutParams newLp = new LayoutParams(lp);
         Paint paint = new Paint();
+        paint.setTypeface(mCollapsingTextHelper.getTypeface());
         paint.setTextSize(mCollapsingTextHelper.getExpandedTextSize());
         newLp.topMargin = (int) -paint.ascent();
 
@@ -323,8 +353,6 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        mCollapsingTextHelper.onLayout(changed, left, top, right, bottom);
-
         if (mEditText != null) {
             final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
             final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
@@ -337,6 +365,8 @@
             // EditText's editable area
             mCollapsingTextHelper.setCollapsedBounds(l, getPaddingTop(),
                     r, bottom - top - getPaddingBottom());
+
+            mCollapsingTextHelper.recalculate();
         }
     }
 
@@ -370,7 +400,6 @@
         } else if (mAnimator.isRunning()) {
             mAnimator.cancel();
         }
-
         mAnimator.setFloatValues(mCollapsingTextHelper.getExpansionFraction(), target);
         mAnimator.start();
     }
diff --git a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
index e5388b9..93990b4 100644
--- a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
+++ b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
@@ -19,6 +19,7 @@
 import android.content.res.ColorStateList;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
 import android.graphics.drawable.GradientDrawable;
 
 /**
@@ -69,9 +70,10 @@
     }
 
     public static Drawable wrapForTinting(Drawable drawable) {
-        if (drawable instanceof GradientDrawable) {
+        if (drawable instanceof GradientDrawable || drawable instanceof DrawableContainer) {
             // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
-            // functionality instead
+            // functionality instead. We also do the same for DrawableContainers since they may
+            // contain GradientDrawable instances.
             return new DrawableWrapperLollipop(drawable);
         }
         return drawable;
diff --git a/v7/appcompat/res/values-v11/styles_base_text.xml b/v7/appcompat/res/values-v11/styles_base_text.xml
index 4cf4966..4227794 100644
--- a/v7/appcompat/res/values-v11/styles_base_text.xml
+++ b/v7/appcompat/res/values-v11/styles_base_text.xml
@@ -25,7 +25,7 @@
     </style>
 
     <style name="Base.TextAppearance.AppCompat.Subhead.Inverse">
-        <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
         <item name="android:textColorHint">?android:attr/textColorHintInverse</item>
         <item name="android:textColorHighlight">?android:attr/textColorHighlightInverse</item>
         <item name="android:textColorLink">?android:attr/textColorLinkInverse</item>
diff --git a/v7/appcompat/res/values/styles_base_text.xml b/v7/appcompat/res/values/styles_base_text.xml
index 78e119c..3a2799a 100644
--- a/v7/appcompat/res/values/styles_base_text.xml
+++ b/v7/appcompat/res/values/styles_base_text.xml
@@ -66,7 +66,7 @@
     </style>
 
     <style name="Base.TextAppearance.AppCompat.Subhead.Inverse">
-        <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
         <item name="android:textColorHint">?android:attr/textColorHintInverse</item>
     </style>
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index f379071..eb58dc5 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -17,14 +17,12 @@
 package android.support.v7.app;
 
 import android.app.Activity;
-import android.app.Dialog;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Bundle;
+import android.support.v4.view.WindowCompat;
 import android.support.v7.appcompat.R;
-import android.support.v7.internal.app.WindowDecorActionBar;
 import android.support.v7.internal.view.SupportMenuInflater;
 import android.support.v7.internal.view.WindowCallbackWrapper;
 import android.support.v7.internal.view.menu.MenuBuilder;
@@ -43,7 +41,7 @@
     final Window.Callback mOriginalWindowCallback;
     final AppCompatCallback mAppCompatCallback;
 
-    private ActionBar mActionBar;
+    ActionBar mActionBar;
     private MenuInflater mMenuInflater;
 
     // true if this activity has an action bar.
@@ -75,7 +73,7 @@
         mWindow.setCallback(wrapWindowCallback(mOriginalWindowCallback));
     }
 
-    abstract ActionBar createSupportActionBar();
+    abstract void initWindowDecorActionBar();
 
     Window.Callback wrapWindowCallback(Window.Callback callback) {
         return new AppCompatWindowCallbackBase(callback);
@@ -85,15 +83,7 @@
     public ActionBar getSupportActionBar() {
         // The Action Bar should be lazily created as hasActionBar
         // could change after onCreate
-        if (mHasActionBar) {
-            if (mActionBar == null) {
-                mActionBar = createSupportActionBar();
-            }
-        } else {
-            if (mActionBar instanceof WindowDecorActionBar) {
-                mActionBar = null;
-            }
-        }
+        initWindowDecorActionBar();
         return mActionBar;
     }
 
@@ -123,17 +113,19 @@
                     "You need to use a Theme.AppCompat theme (or descendant) with this activity.");
         }
 
-        if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) {
-            mHasActionBar = true;
+        if (a.getBoolean(R.styleable.Theme_windowNoTitle, false)) {
+            requestWindowFeature(Window.FEATURE_NO_TITLE);
+        } else if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) {
+            // Don't allow an action bar if there is no title.
+            requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
         }
         if (a.getBoolean(R.styleable.Theme_windowActionBarOverlay, false)) {
-            mOverlayActionBar = true;
+            requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY);
         }
         if (a.getBoolean(R.styleable.Theme_windowActionModeOverlay, false)) {
-            mOverlayActionMode = true;
+            requestWindowFeature(WindowCompat.FEATURE_ACTION_MODE_OVERLAY);
         }
         mIsFloating = a.getBoolean(R.styleable.Theme_android_windowIsFloating, false);
-        mWindowNoTitle = a.getBoolean(R.styleable.Theme_windowNoTitle, false);
         a.recycle();
     }
 
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index 1c08a40..abb665f 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -167,18 +167,22 @@
     }
 
     @Override
-    public ActionBar createSupportActionBar() {
+    public void initWindowDecorActionBar() {
         ensureSubDecor();
-        ActionBar ab = null;
+
+        if (!mHasActionBar || mActionBar != null) {
+            return;
+        }
+
         if (mOriginalWindowCallback instanceof Activity) {
-            ab = new WindowDecorActionBar((Activity) mOriginalWindowCallback, mOverlayActionBar);
+            mActionBar = new WindowDecorActionBar((Activity) mOriginalWindowCallback,
+                    mOverlayActionBar);
         } else if (mOriginalWindowCallback instanceof Dialog) {
-            ab = new WindowDecorActionBar((Dialog) mOriginalWindowCallback);
+            mActionBar = new WindowDecorActionBar((Dialog) mOriginalWindowCallback);
         }
-        if (ab != null) {
-            ab.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
+        if (mActionBar != null) {
+            mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
         }
-        return ab;
     }
 
     @Override
@@ -460,6 +464,14 @@
 
     @Override
     public boolean requestWindowFeature(int featureId) {
+        if (mWindowNoTitle && featureId == FEATURE_ACTION_BAR) {
+            return false; // Ignore. No title dominates.
+        }
+        if (mHasActionBar && featureId == Window.FEATURE_NO_TITLE) {
+            // Remove the action bar feature if we have no title. No title dominates.
+            mHasActionBar = false;
+        }
+
         switch (featureId) {
             case FEATURE_ACTION_BAR:
                 throwFeatureRequestIfSubDecorInstalled();
diff --git a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
index 9653f42..46bebe6 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
@@ -513,6 +513,12 @@
             final Resources.Theme widgetTheme = context.getResources().newTheme();
             widgetTheme.setTo(context.getTheme());
 
+            // First apply the actionBarPopupTheme
+            widgetTheme.resolveAttribute(R.attr.actionBarPopupTheme, outValue, true);
+            if (outValue.resourceId != 0) {
+                widgetTheme.applyStyle(outValue.resourceId, true);
+            }
+
             // Apply the panelMenuListTheme
             widgetTheme.resolveAttribute(R.attr.panelMenuListTheme, outValue, true);
             if (outValue.resourceId != 0) {
diff --git a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
index 9c53920..6aa55d7 100644
--- a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
@@ -140,7 +140,7 @@
     private Layout mOnLayout;
     private Layout mOffLayout;
     private TransformationMethod mSwitchTransformationMethod;
-    private Animation mPositionAnimator;
+    private ThumbAnimation mPositionAnimator;
 
     @SuppressWarnings("hiding")
     private final Rect mTempRect = new Rect();
@@ -748,16 +748,7 @@
     }
 
     private void animateThumbToCheckedState(boolean newCheckedState) {
-        final float startPosition = mThumbPosition;
-        final float targetPosition = newCheckedState ? 1 : 0;
-        final float diff = targetPosition - startPosition;
-
-        mPositionAnimator = new Animation() {
-            @Override
-            protected void applyTransformation(float interpolatedTime, Transformation t) {
-                setThumbPosition(startPosition + (diff * interpolatedTime));
-            }
-        };
+        mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1 : 0);
         mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
         startAnimation(mPositionAnimator);
     }
@@ -1111,6 +1102,8 @@
 
             if (mPositionAnimator != null && !mPositionAnimator.hasEnded()) {
                 clearAnimation();
+                // Manually set our thumb position to the end state
+                setThumbPosition(mPositionAnimator.mEndPosition);
                 mPositionAnimator = null;
             }
         }
@@ -1148,4 +1141,21 @@
     private static float constrain(float amount, float low, float high) {
         return amount < low ? low : (amount > high ? high : amount);
     }
+
+    private class ThumbAnimation extends Animation {
+        final float mStartPosition;
+        final float mEndPosition;
+        final float mDiff;
+
+        private ThumbAnimation(float startPosition, float endPosition) {
+            mStartPosition = startPosition;
+            mEndPosition = endPosition;
+            mDiff = endPosition - startPosition;
+        }
+
+        @Override
+        protected void applyTransformation(float interpolatedTime, Transformation t) {
+            setThumbPosition(mStartPosition + (mDiff * interpolatedTime));
+        }
+    }
 }
\ No newline at end of file