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());