Merge "Jump SwitchCompat to end state in jumpDrawablesToCurrentState()" into lmp-mr1-ub-dev
diff --git a/design/api/current.txt b/design/api/current.txt
index e0e49ea..4e71e40 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -197,6 +197,7 @@
     method public void setItemIconTintList(android.content.res.ColorStateList);
     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 {
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index b89c603..390c9e4 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -184,10 +184,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);
@@ -241,13 +252,14 @@
 
     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;
 
@@ -353,6 +365,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()) {
@@ -363,12 +381,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) {
@@ -410,27 +434,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;
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 563a270..636770e 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -137,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) {
@@ -440,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();
@@ -457,6 +455,7 @@
     void setText(CharSequence text) {
         if (text == null || !text.equals(mText)) {
             mText = text;
+            mTextToDraw = null;
             clearTexture();
             recalculate();
         }
@@ -473,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/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 11afbc9..486ce74 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -24,6 +24,7 @@
 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;
@@ -34,6 +35,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;
@@ -330,6 +332,18 @@
         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);
+        }
+    }
+
     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 392da5f..884e538 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -50,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 {
 
@@ -335,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();
@@ -349,6 +365,8 @@
             // EditText's editable area
             mCollapsingTextHelper.setCollapsedBounds(l, getPaddingTop(),
                     r, bottom - top - getPaddingBottom());
+
+            mCollapsingTextHelper.recalculate();
         }
     }
 
@@ -382,7 +400,6 @@
         } else if (mAnimator.isRunning()) {
             mAnimator.cancel();
         }
-
         mAnimator.setFloatValues(mCollapsingTextHelper.getExpansionFraction(), target);
         mAnimator.start();
     }