Merge changes Ib0f927b5,I90a85ee9 into nyc-mr1-dev

* changes:
  Add a demo for InputConnectionCompat#commitContent
  Fix a type mismatch in COMMIT_CONTENT_FLAGS_KEY
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
index 123333c..02fd3dd 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -233,6 +233,10 @@
      * near the top of the refreshing content. This position is a consistent
      * location, but can be adjusted in either direction based on whether or not
      * there is a toolbar or actionbar present.
+     * <p>
+     * <strong>Note:</strong> Calling this will reset the position of the refresh indicator to
+     * <code>start</code>.
+     * </p>
      *
      * @param scale Set to true if there is no view at a higher z-order than where the progress
      *              spinner is set to appear. Setting it to true will cause indicator to be scaled
@@ -245,11 +249,11 @@
      */
     public void setProgressViewOffset(boolean scale, int start, int end) {
         mScale = scale;
-        mCircleView.setVisibility(View.GONE);
-        mOriginalOffsetTop = mCurrentTargetOffsetTop = start;
+        mOriginalOffsetTop = start;
         mSpinnerFinalOffset = end;
         mUsingCustomStart = true;
-        mCircleView.invalidate();
+        reset();
+        mRefreshing = false;
     }
 
     /**
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 74092a0..35d59ff 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -1135,9 +1135,13 @@
                     setSelectedTabView(newPosition);
                 }
             }
-            dispatchTabUnselected(currentTab);
+            if (currentTab != null) {
+                dispatchTabUnselected(currentTab);
+            }
             mSelectedTab = tab;
-            dispatchTabSelected(tab);
+            if (tab != null) {
+                dispatchTabSelected(tab);
+            }
         }
     }
 
diff --git a/design/tests/src/android/support/design/widget/TabLayoutTest.java b/design/tests/src/android/support/design/widget/TabLayoutTest.java
index 2f3ad60..69bf429 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutTest.java
@@ -20,6 +20,12 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.support.design.test.R;
 import android.support.test.annotation.UiThreadTest;
@@ -82,12 +88,17 @@
     @Test
     @UiThreadTest
     public void testTabWithCustomLayoutSelection1() {
+        final TabLayout.OnTabSelectedListener mockListener =
+                mock(TabLayout.OnTabSelectedListener.class);
         final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
 
         final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
+        tabLayout.addOnTabSelectedListener(mockListener);
         final TabLayout.Tab tab = tabLayout.newTab();
         tab.setCustomView(R.layout.design_tab_item_custom);
         tabLayout.addTab(tab);
+        verify(mockListener, times(1)).onTabSelected(eq(tab));
+        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
 
         assertNotNull("Tab has custom view", tab.getCustomView());
         assertEquals("First tab is selected", 0, tabLayout.getSelectedTabPosition());
@@ -97,11 +108,16 @@
     @Test
     @UiThreadTest
     public void testTabWithCustomLayoutSelection2() {
+        final TabLayout.OnTabSelectedListener mockListener =
+                mock(TabLayout.OnTabSelectedListener.class);
         final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
 
         final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
+        tabLayout.addOnTabSelectedListener(mockListener);
         final TabLayout.Tab tab = tabLayout.newTab();
         tabLayout.addTab(tab);
+        verify(mockListener, times(1)).onTabSelected(eq(tab));
+        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
         tab.setCustomView(R.layout.design_tab_item_custom);
 
         assertNotNull("Tab has custom view", tab.getCustomView());
@@ -112,12 +128,23 @@
     @Test
     @UiThreadTest
     public void testMultipleTabsWithCustomLayoutSelection1() {
+        final TabLayout.OnTabSelectedListener mockListener =
+                mock(TabLayout.OnTabSelectedListener.class);
         final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
         final TabLayout tabs = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
+        tabs.addOnTabSelectedListener(mockListener);
 
-        tabs.addTab(tabs.newTab().setCustomView(R.layout.design_tab_item_custom));
-        tabs.addTab(tabs.newTab().setCustomView(R.layout.design_tab_item_custom), true);
-        tabs.addTab(tabs.newTab().setCustomView(R.layout.design_tab_item_custom));
+        final TabLayout.Tab tab1 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
+        tabs.addTab(tab1);
+        verify(mockListener, times(1)).onTabSelected(eq(tab1));
+        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
+        final TabLayout.Tab tab2 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
+        tabs.addTab(tab2, true);
+        verify(mockListener, times(1)).onTabSelected(eq(tab2));
+        verify(mockListener, times(1)).onTabUnselected(eq(tab1));
+        final TabLayout.Tab tab3 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
+        tabs.addTab(tab3);
+        verifyNoMoreInteractions(mockListener);
 
         assertEquals("Second tab is selected", 1, tabs.getSelectedTabPosition());
         assertTabCustomViewSelected(tabs);
@@ -126,12 +153,23 @@
     @Test
     @UiThreadTest
     public void testMultipleTabsWithCustomLayoutSelection2() {
+        final TabLayout.OnTabSelectedListener mockListener =
+                mock(TabLayout.OnTabSelectedListener.class);
         final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
         final TabLayout tabs = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
+        tabs.addOnTabSelectedListener(mockListener);
 
-        tabs.addTab(tabs.newTab());
-        tabs.addTab(tabs.newTab(), true);
-        tabs.addTab(tabs.newTab());
+        final TabLayout.Tab tab1 = tabs.newTab();
+        tabs.addTab(tab1);
+        verify(mockListener, times(1)).onTabSelected(eq(tab1));
+        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
+        final TabLayout.Tab tab2 = tabs.newTab();
+        tabs.addTab(tab2, true);
+        verify(mockListener, times(1)).onTabSelected(eq(tab2));
+        verify(mockListener, times(1)).onTabUnselected(eq(tab1));
+        final TabLayout.Tab tab3 = tabs.newTab();
+        tabs.addTab(tab3);
+        verifyNoMoreInteractions(mockListener);
 
         tabs.getTabAt(0).setCustomView(R.layout.design_tab_item_custom);
         tabs.getTabAt(1).setCustomView(R.layout.design_tab_item_custom);
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
index 38efc46..9e6df30 100644
--- a/v7/appcompat/res-public/values/public_styles.xml
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -54,8 +54,6 @@
     <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title.Inverse"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.Button"/>
-    <public type="style" name="TextAppearance.AppCompat.Widget.Button.Borderless.Colored"/>
-    <public type="style" name="TextAppearance.AppCompat.Widget.Button.Colored"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.Button.Inverse"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.DropDownItem"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.PopupMenu.Header"/>
diff --git a/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml b/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml
deleted file mode 100644
index 74170d6..0000000
--- a/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Used for the text of a bordered colored button. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?android:attr/disabledAlpha"
-          android:color="?android:attr/textColorPrimary" />
-    <item android:color="?android:attr/textColorPrimaryInverse" />
-</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/color/abc_btn_colored_text_material.xml b/v7/appcompat/res/color/abc_btn_colored_text_material.xml
deleted file mode 100644
index 897a3f7..0000000
--- a/v7/appcompat/res/color/abc_btn_colored_text_material.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Used for the text of a bordered colored button. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:state_enabled="false"
-          app:alpha="?android:attr/disabledAlpha"
-          android:color="?android:attr/textColorPrimary" />
-    <item android:color="?android:attr/textColorPrimaryInverse" />
-</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v24/styles_base_text.xml b/v7/appcompat/res/values-v24/styles_base_text.xml
deleted file mode 100644
index 2e6182d..0000000
--- a/v7/appcompat/res/values-v24/styles_base_text.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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.
--->
-<resources>
-
-    <style name="Base.TextAppearance.AppCompat.Widget.Button.Colored" parent="android:TextAppearance.Material.Widget.Button.Colored" />
-
-    <style name="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="android:TextAppearance.Material.Widget.Button.Borderless.Colored" />
-
-</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index 7595d74..ec8bbe1 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -298,10 +298,6 @@
 
     <style name="TextAppearance.AppCompat.Widget.TextView.SpinnerItem" parent="Base.TextAppearance.AppCompat.Widget.TextView.SpinnerItem" />
 
-    <style name="TextAppearance.AppCompat.Widget.Button.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button.Colored" />
-
-    <style name="TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" />
-
     <!--
          The following themes are deprecated.
     -->
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index b8c1f29..b1d6c95 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -453,7 +453,7 @@
     <!-- Colored bordered ink button -->
     <style name="Base.Widget.AppCompat.Button.Colored">
         <item name="android:background">@drawable/abc_btn_colored_material</item>
-        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Colored</item>
+        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Inverse</item>
     </style>
 
     <!-- Borderless ink button -->
@@ -463,7 +463,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Base.Widget.AppCompat.Button.Borderless.Colored">
-        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Borderless.Colored</item>
+        <item name="android:textColor">@color/abc_btn_colored_borderless_text_material</item>
     </style>
 
     <style name="Base.Widget.AppCompat.Button.ButtonBar.AlertDialog" parent="Widget.AppCompat.Button.Borderless.Colored">
diff --git a/v7/appcompat/res/values/styles_base_text.xml b/v7/appcompat/res/values/styles_base_text.xml
index 6a43144..8597179 100644
--- a/v7/appcompat/res/values/styles_base_text.xml
+++ b/v7/appcompat/res/values/styles_base_text.xml
@@ -139,12 +139,4 @@
         <item name="android:textColorHint">?android:attr/textColorHintInverse</item>
     </style>
 
-    <style name="Base.TextAppearance.AppCompat.Widget.Button.Colored">
-        <item name="android:textColor">@color/abc_btn_colored_text_material</item>
-    </style>
-
-    <style name="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button">
-        <item name="android:textColor">@color/abc_btn_colored_borderless_text_material</item>
-    </style>
-
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
index 09590bd..ba27a88 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
@@ -278,7 +278,8 @@
         // Allow for off-by-one mismatch in anchoring
         assertEquals("Anchoring X", anchorOnScreenXY[0] + popupInWindowXY[0],
                 popupOnScreenXY[0], 1);
-        assertEquals("Anchoring Y", anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight(),
+        assertEquals("Anchoring Y",
+                anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight() - popupPadding.top,
                 popupOnScreenXY[1], 1);
     }
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 848d910..5ee2537 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -137,6 +137,11 @@
     final AnchorInfo mAnchorInfo = new AnchorInfo();
 
     /**
+     * Stashed to avoid allocation, currently only used in #fill()
+     */
+    private final LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();
+
+    /**
      * Creates a vertical LinearLayoutManager
      *
      * @param context Current context, will be used to access resources.
@@ -1366,7 +1371,7 @@
             recycleByLayoutState(recycler, layoutState);
         }
         int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
-        LayoutChunkResult layoutChunkResult = new LayoutChunkResult();
+        LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
         while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
             layoutChunkResult.resetInternal();
             layoutChunk(recycler, state, layoutState, layoutChunkResult);
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index b1d1dfd..a90cf7c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -4277,6 +4277,10 @@
             return lp.mDecorInsets;
         }
 
+        if (mState.isPreLayout() && (lp.isItemChanged() || lp.isViewInvalid())) {
+            // changed/invalid items should not be updated until they are rebound.
+            return lp.mDecorInsets;
+        }
         final Rect insets = lp.mDecorInsets;
         insets.set(0, 0, 0, 0);
         final int decorCount = mItemDecorations.size();
@@ -5886,6 +5890,10 @@
             TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);
             onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
             holder.clearPayload();
+            final ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
+            if (layoutParams instanceof RecyclerView.LayoutParams) {
+                ((LayoutParams) layoutParams).mInsetsDirty = true;
+            }
             TraceCompat.endSection();
         }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 8377874..5f7f244 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -527,6 +527,7 @@
     public class TestViewHolder extends RecyclerView.ViewHolder {
 
         Item mBoundItem;
+        Object mData;
 
         public TestViewHolder(View itemView) {
             super(itemView);
@@ -535,7 +536,15 @@
 
         @Override
         public String toString() {
-            return super.toString() + " item:" + mBoundItem;
+            return super.toString() + " item:" + mBoundItem + ", data:" + mData;
+        }
+
+        public Object getData() {
+            return mData;
+        }
+
+        public void setData(Object data) {
+            mData = data;
         }
     }
     class DumbLayoutManager extends TestLayoutManager {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index e9e92a1..770ab71 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -24,6 +24,7 @@
 import static android.support.v7.widget.RecyclerView.getChildViewHolderInt;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -2596,6 +2597,67 @@
     }
 
     @Test
+    public void itemDecorsWithPredictive() throws Throwable {
+        LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        lm.setSupportsPredictive(true);
+        final Object changePayload = new Object();
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(TestViewHolder holder,
+                    int position, List<Object> payloads) {
+                super.onBindViewHolder(holder, position);
+                holder.setData(payloads.isEmpty() ? null : payloads.get(0));
+            }
+        };
+        final Map<Integer, Object> preLayoutData = new HashMap<>();
+        final Map<Integer, Object> postLayoutData = new HashMap<>();
+
+        final RecyclerView.ItemDecoration decoration = new RecyclerView.ItemDecoration() {
+            @Override
+            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                    RecyclerView.State state) {
+                try {
+                    TestViewHolder tvh = (TestViewHolder) parent.getChildViewHolder(view);
+                    Object data = tvh.getData();
+                    int adapterPos = tvh.getAdapterPosition();
+                    assertThat(adapterPos, is(not(NO_POSITION)));
+                    if (state.isPreLayout()) {
+                        preLayoutData.put(adapterPos, data);
+                    } else {
+                        postLayoutData.put(adapterPos, data);
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+
+            }
+        };
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.addItemDecoration(decoration);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(2);
+
+        preLayoutData.clear();
+        postLayoutData.clear();
+        lm.expectLayouts(2);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyItemChanged(3, changePayload);
+            }
+        });
+        lm.waitForLayout(2);
+        assertThat(preLayoutData.containsKey(3), is(false));
+        assertThat(postLayoutData.get(3), is(changePayload));
+        assertThat(preLayoutData.size(), is(0));
+        assertThat(postLayoutData.size(), is(1));
+        checkForMainThreadException();
+    }
+
+    @Test
     public void invalidateAllDecorOffsets() throws Throwable {
         final TestAdapter adapter = new TestAdapter(10);
         final RecyclerView recyclerView = new RecyclerView(getActivity());