Merge "Support library gradle improvements" into mnc-ub-dev
diff --git a/annotations/src/android/support/annotation/VisibleForTesting.java b/annotations/src/android/support/annotation/VisibleForTesting.java
index bb02ab4..0c893ff 100644
--- a/annotations/src/android/support/annotation/VisibleForTesting.java
+++ b/annotations/src/android/support/annotation/VisibleForTesting.java
@@ -17,12 +17,12 @@
import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
/**
* Denotes that the class, method or field has its visibility relaxed, so that it is more widely
* visible than otherwise necessary to make code testable.
*/
-@Retention(SOURCE)
+@Retention(CLASS)
public @interface VisibleForTesting {
}
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 7ff70c2..7a9e3c1 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -109,7 +109,7 @@
<attr name="android:text" />
<!-- Icon to display in the tab. -->
<attr name="android:icon" />
- <!-- A reference to a layout to be displayed in the tab. -->
+ <!-- A reference to a layout resource to be displayed in the tab. -->
<attr name="android:layout" />
</declare-styleable>
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index cb95f4f..609795f 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -238,12 +238,14 @@
updateMenuView(false);
}
+ @Nullable
public Drawable getItemBackground() {
return mItemBackground;
}
- public void setItemBackground(Drawable itemBackground) {
+ public void setItemBackground(@Nullable Drawable itemBackground) {
mItemBackground = itemBackground;
+ updateMenuView(false);
}
public void setUpdateSuspended(boolean updateSuspended) {
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 9a38c7d..8768826 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -105,8 +105,7 @@
public CollapsingTextHelper(View view) {
mView = view;
- mTextPaint = new TextPaint();
- mTextPaint.setAntiAlias(true);
+ mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
mCollapsedBounds = new Rect();
mExpandedBounds = new Rect();
@@ -436,10 +435,6 @@
final float ascent;
final float descent;
-
- // Update the TextPaint to the current text size
- mTextPaint.setTextSize(mCurrentTextSize);
-
if (drawTexture) {
ascent = mTextureAscent * mScale;
descent = mTextureDescent * mScale;
@@ -536,6 +531,8 @@
if (mTextToDraw == null || updateDrawText) {
mTextPaint.setTextSize(mCurrentTextSize);
mTextPaint.setTypeface(mCurrentTypeface);
+ // Use linear text scaling if we're scaling the canvas
+ mTextPaint.setLinearText(mScale != 1f);
// If we don't currently have text to draw, or the text size has changed, ellipsize...
final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index a73dc65..42f4eed 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -297,7 +297,7 @@
}
/**
- * Returns the tint which is applied to our item's icons.
+ * Returns the tint which is applied to our menu items' icons.
*
* @see #setItemIconTintList(ColorStateList)
*
@@ -309,7 +309,7 @@
}
/**
- * Set the tint which is applied to our item's icons.
+ * Set the tint which is applied to our menu items' icons.
*
* @param tint the tint to apply.
*
@@ -320,7 +320,7 @@
}
/**
- * Returns the tint which is applied to our item's icons.
+ * Returns the tint which is applied to our menu items' icons.
*
* @see #setItemTextColor(ColorStateList)
*
@@ -332,7 +332,7 @@
}
/**
- * Set the text color which is text to our items.
+ * Set the text color to be used on our menu items.
*
* @see #getItemTextColor()
*
@@ -343,18 +343,19 @@
}
/**
- * Returns the background drawable for the menu items.
+ * Returns the background drawable for our menu items.
*
* @see #setItemBackgroundResource(int)
*
* @attr ref R.styleable#NavigationView_itemBackground
*/
+ @Nullable
public Drawable getItemBackground() {
return mPresenter.getItemBackground();
}
/**
- * Set the background of the menu items to the given resource.
+ * Set the background of our menu items to the given resource.
*
* @param resId The identifier of the resource.
*
@@ -365,12 +366,12 @@
}
/**
- * Set the background of the menu items to a given resource. The resource should refer to
- * a Drawable object or 0 to use the background background.
+ * Set the background of our menu items to a given resource. The resource should refer to
+ * a Drawable object or null to use the default background set on this navigation menu.
*
* @attr ref R.styleable#NavigationView_itemBackground
*/
- public void setItemBackground(Drawable itemBackground) {
+ public void setItemBackground(@Nullable Drawable itemBackground) {
mPresenter.setItemBackground(itemBackground);
}
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index af26af3..4f65f92 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -39,6 +39,10 @@
android:name="android.support.design.widget.BottomSheetBehaviorActivity"/>
<activity
+ android:theme="@style/Theme.AppCompat.NoActionBar"
+ android:name="android.support.design.widget.NavigationViewActivity"/>
+
+ <activity
android:name="android.support.v7.app.AppCompatActivity"/>
</application>
diff --git a/design/tests/res/color/color_state_list_lilac.xml b/design/tests/res/color/color_state_list_lilac.xml
new file mode 100644
index 0000000..f0b2791
--- /dev/null
+++ b/design/tests/res/color/color_state_list_lilac.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/lilac_disabled" />
+ <item android:color="@color/lilac_default"/>
+</selector>
+
diff --git a/design/tests/res/color/color_state_list_red_translucent.xml b/design/tests/res/color/color_state_list_red_translucent.xml
new file mode 100644
index 0000000..fdf8b2b
--- /dev/null
+++ b/design/tests/res/color/color_state_list_red_translucent.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/red_translucent"/>
+</selector>
+
diff --git a/design/tests/res/color/color_state_list_sand.xml b/design/tests/res/color/color_state_list_sand.xml
new file mode 100644
index 0000000..eb472c2
--- /dev/null
+++ b/design/tests/res/color/color_state_list_sand.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/sand_disabled" />
+ <item android:state_checked="true" android:color="@color/sand_checked" />
+ <item android:color="@color/sand_default" />
+</selector>
+
diff --git a/design/tests/res/drawable/test_background_blue.xml b/design/tests/res/drawable/test_background_blue.xml
new file mode 100644
index 0000000..fe4bca2
--- /dev/null
+++ b/design/tests/res/drawable/test_background_blue.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="@color/test_blue" />
+</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_background_green.xml b/design/tests/res/drawable/test_background_green.xml
new file mode 100644
index 0000000..b90d9bc
--- /dev/null
+++ b/design/tests/res/drawable/test_background_green.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="@color/test_green" />
+</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_drawable_blue.xml b/design/tests/res/drawable/test_drawable_blue.xml
new file mode 100644
index 0000000..f228e34
--- /dev/null
+++ b/design/tests/res/drawable/test_drawable_blue.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size
+ android:width="@dimen/drawable_large_size"
+ android:height="@dimen/drawable_small_size" />
+ <solid
+ android:color="@color/test_blue" />
+</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_drawable_green.xml b/design/tests/res/drawable/test_drawable_green.xml
new file mode 100644
index 0000000..1d83f0f
--- /dev/null
+++ b/design/tests/res/drawable/test_drawable_green.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size
+ android:width="@dimen/drawable_medium_size"
+ android:height="@dimen/drawable_large_size" />
+ <solid
+ android:color="@color/test_green" />
+</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_drawable_red.xml b/design/tests/res/drawable/test_drawable_red.xml
new file mode 100644
index 0000000..58dbe73
--- /dev/null
+++ b/design/tests/res/drawable/test_drawable_red.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size
+ android:width="@dimen/drawable_small_size"
+ android:height="@dimen/drawable_medium_size" />
+ <solid
+ android:color="@color/test_red" />
+</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_drawable_state_list.xml b/design/tests/res/drawable/test_drawable_state_list.xml
new file mode 100644
index 0000000..f125913
--- /dev/null
+++ b/design/tests/res/drawable/test_drawable_state_list.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:drawable="@drawable/test_background_blue" />
+ <item android:drawable="@drawable/test_background_green" />
+</selector>
+
diff --git a/design/tests/res/layout/design_navigation_view.xml b/design/tests/res/layout/design_navigation_view.xml
new file mode 100644
index 0000000..1789843
--- /dev/null
+++ b/design/tests/res/layout/design_navigation_view.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+ <!-- As the main content view, the view below consumes the entire
+ space available using match_parent in both dimensions. Note that
+ this child does not specify android:layout_gravity attribute. -->
+ <FrameLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- android:layout_gravity="start" tells DrawerLayout to treat
+ this as a sliding drawer on the starting side, which is
+ left for left-to-right locales. The navigation view extends
+ the full height of the container. A
+ solid background is used for contrast with the content view.
+ android:fitsSystemWindows="true" tells the system to have
+ DrawerLayout span the full height of the screen, including the
+ system status bar on Lollipop+ versions of the plaform. -->
+ <android.support.design.widget.NavigationView
+ android:id="@+id/start_drawer"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:background="#333"
+ android:fitsSystemWindows="true"
+ app:menu="@menu/navigation_view_content"
+ app:itemIconTint="@color/emerald_translucent"
+ app:itemTextColor="@color/emerald_text"
+ app:itemBackground="@color/sand_default"
+ app:itemTextAppearance="@style/TextMediumStyle" />
+
+</android.support.v4.widget.DrawerLayout>
+
diff --git a/design/tests/res/layout/design_navigation_view_header1.xml b/design/tests/res/layout/design_navigation_view_header1.xml
new file mode 100644
index 0000000..2fd6f20
--- /dev/null
+++ b/design/tests/res/layout/design_navigation_view_header1.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header1"
+ android:layout_width="match_parent"
+ android:layout_height="120dip"
+ android:background="@color/test_red" />
+
diff --git a/design/tests/res/layout/design_navigation_view_header2.xml b/design/tests/res/layout/design_navigation_view_header2.xml
new file mode 100644
index 0000000..77ad32a
--- /dev/null
+++ b/design/tests/res/layout/design_navigation_view_header2.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header2"
+ android:layout_width="match_parent"
+ android:layout_height="100dip"
+ android:background="@color/test_blue" />
+
diff --git a/design/tests/res/layout/design_navigation_view_header3.xml b/design/tests/res/layout/design_navigation_view_header3.xml
new file mode 100644
index 0000000..b1fd676
--- /dev/null
+++ b/design/tests/res/layout/design_navigation_view_header3.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header3"
+ android:layout_width="match_parent"
+ android:layout_height="80dip"
+ android:background="@color/test_green" />
+
diff --git a/design/tests/res/menu/navigation_view_content.xml b/design/tests/res/menu/navigation_view_content.xml
new file mode 100644
index 0000000..ee396f0
--- /dev/null
+++ b/design/tests/res/menu/navigation_view_content.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+ 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <group android:checkableBehavior="single">
+ <item android:id="@+id/destination_home"
+ android:title="@string/navigate_home"
+ android:icon="@drawable/test_drawable_red" />
+ <item android:id="@+id/destination_profile"
+ android:title="@string/navigate_profile"
+ android:icon="@drawable/test_drawable_green" />
+ <item android:id="@+id/destination_people"
+ android:title="@string/navigate_people"
+ android:icon="@drawable/test_drawable_blue" />
+ <item android:id="@+id/destination_settings"
+ android:title="@string/navigate_settings" />
+ </group>
+</menu>
diff --git a/design/tests/res/values/colors.xml b/design/tests/res/values/colors.xml
new file mode 100644
index 0000000..ea8da2a
--- /dev/null
+++ b/design/tests/res/values/colors.xml
@@ -0,0 +1,31 @@
+<?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>
+ <color name="emerald_translucent">#8020A060</color>
+ <color name="emerald_text">#30B050</color>
+ <color name="red_translucent">#90FF2040</color>
+
+ <color name="lilac_default">#F080F0</color>
+ <color name="lilac_disabled">#F0A0FF</color>
+ <color name="sand_default">#F0B000</color>
+ <color name="sand_disabled">#FFC080</color>
+ <color name="sand_checked">#FFD0A0</color>
+
+ <color name="test_red">#FF6030</color>
+ <color name="test_green">#50E080</color>
+ <color name="test_blue">#3050CF</color>
+</resources>
diff --git a/design/tests/res/values/dimens.xml b/design/tests/res/values/dimens.xml
index c20e4f8..94c2734 100644
--- a/design/tests/res/values/dimens.xml
+++ b/design/tests/res/values/dimens.xml
@@ -18,4 +18,11 @@
<dimen name="tab_width_limit_medium">100dip</dimen>
<dimen name="tab_width_limit_large">120dip</dimen>
<dimen name="bottom_sheet_peek_height">128dp</dimen>
+
+ <dimen name="text_small_size">16sp</dimen>
+ <dimen name="text_medium_size">20sp</dimen>
+
+ <dimen name="drawable_small_size">12dip</dimen>
+ <dimen name="drawable_medium_size">16dip</dimen>
+ <dimen name="drawable_large_size">20dip</dimen>
</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/strings.xml b/design/tests/res/values/strings.xml
index 854e711..05dd55e 100644
--- a/design/tests/res/values/strings.xml
+++ b/design/tests/res/values/strings.xml
@@ -15,4 +15,9 @@
-->
<resources>
<string name="tab_layout_text">Tab text!</string>
+
+ <string name="navigate_home">Home</string>
+ <string name="navigate_profile">Profile</string>
+ <string name="navigate_people">People</string>
+ <string name="navigate_settings">Settings</string>
</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/styles.xml b/design/tests/res/values/styles.xml
new file mode 100644
index 0000000..4fc946b
--- /dev/null
+++ b/design/tests/res/values/styles.xml
@@ -0,0 +1,24 @@
+<?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="TextSmallStyle" parent="@android:style/TextAppearance">
+ <item name="android:textSize">@dimen/text_small_size</item>
+ </style>
+
+ <style name="TextMediumStyle" parent="@android:style/TextAppearance.Medium">
+ <item name="android:textSize">@dimen/text_medium_size</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java b/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java
new file mode 100755
index 0000000..e4ea867
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+package android.support.design.testutils;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.v4.widget.DrawerLayout;
+import android.view.View;
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+
+public class DrawerLayoutActions {
+ /**
+ * Opens the drawer at the specified edge gravity.
+ */
+ public static ViewAction openDrawer(final int drawerEdgeGravity) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(DrawerLayout.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Opens the drawer";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ DrawerLayout drawerLayout = (DrawerLayout) view;
+ drawerLayout.openDrawer(drawerEdgeGravity);
+
+ // Wait for a full second to let the inner ViewDragHelper complete the operation
+ uiController.loopMainThreadForAtLeast(1000);
+ }
+ };
+ }
+
+ /**
+ * Closes the drawer at the specified edge gravity.
+ */
+ public static ViewAction closeDrawer(final int drawerEdgeGravity) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(DrawerLayout.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Closes the drawer";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ DrawerLayout drawerLayout = (DrawerLayout) view;
+ drawerLayout.closeDrawer(drawerEdgeGravity);
+
+ // Wait for a full second to let the inner ViewDragHelper complete the operation
+ uiController.loopMainThreadForAtLeast(1000);
+ }
+ };
+ }
+}
diff --git a/design/tests/src/android/support/design/testutils/NavigationViewActions.java b/design/tests/src/android/support/design/testutils/NavigationViewActions.java
new file mode 100644
index 0000000..66e4630
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/NavigationViewActions.java
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+package android.support.design.testutils;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+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.widget.NavigationView;
+import android.support.design.widget.TabLayout;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.view.LayoutInflater;
+import android.view.View;
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
+
+public class NavigationViewActions {
+ /**
+ * Sets item text appearance on the content of the navigation view.
+ */
+ public static ViewAction setItemTextAppearance(final @StyleRes int resId) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item text appearance";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setItemTextAppearance(resId);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets item text color on the content of the navigation view.
+ */
+ public static ViewAction setItemTextColor(final ColorStateList textColor) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item text color";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setItemTextColor(textColor);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets item background on the content of the navigation view.
+ */
+ public static ViewAction setItemBackground(final @Nullable Drawable itemBackground) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item background";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setItemBackground(itemBackground);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets item background on the content of the navigation view.
+ */
+ public static ViewAction setItemBackgroundResource(final @DrawableRes int resId) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item background";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setItemBackgroundResource(resId);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets item icon tint list on the content of the navigation view.
+ */
+ public static ViewAction setItemIconTintList(final @Nullable ColorStateList tint) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item icon tint list";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setItemIconTintList(tint);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Add the specified view as a header to the navigation view.
+ */
+ public static ViewAction addHeaderView(final @NonNull LayoutInflater inflater,
+ final @LayoutRes int res) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Add header view";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.addHeaderView(inflater.inflate(res, null, false));
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Inflates a view from the specified layout ID and adds it as a header to the navigation view.
+ */
+ public static ViewAction inflateHeaderView(final @LayoutRes int res) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Inflate and add header view";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.inflateHeaderView(res);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Removes a previously added header view from the navigation view.
+ */
+ public static ViewAction removeHeaderView(final @Nullable View headerView) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Remove header view";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.removeHeaderView(headerView);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets checked item on the navigation view.
+ */
+ public static ViewAction setCheckedItem(final @IdRes int id) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set checked item";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ NavigationView navigationView = (NavigationView) view;
+ navigationView.setCheckedItem(id);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+}
diff --git a/design/tests/src/android/support/design/testutils/TestUtils.java b/design/tests/src/android/support/design/testutils/TestUtils.java
new file mode 100644
index 0000000..3255fb1
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/TestUtils.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package android.support.design.testutils;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import junit.framework.Assert;
+
+public class TestUtils {
+ /**
+ * Checks whether all the pixels in the specified drawable are of the same specified color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
+ int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
+ int allowedComponentVariance, boolean throwExceptionIfFails) {
+ // Create a bitmap
+ Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
+ // Create a canvas that wraps the bitmap
+ Canvas canvas = new Canvas(bitmap);
+ if (callSetBounds) {
+ // Configure the drawable to have bounds that match the passed size
+ drawable.setBounds(0, 0, drawableWidth, drawableHeight);
+ }
+ // And ask the drawable to draw itself to the canvas / bitmap
+ drawable.draw(canvas);
+
+ try {
+ int[] rowPixels = new int[drawableWidth];
+ for (int row = 0; row < drawableHeight; row++) {
+ bitmap.getPixels(rowPixels, 0, drawableWidth, 0, row, drawableWidth, 1);
+ for (int column = 0; column < drawableWidth; column++) {
+ int sourceAlpha = Color.alpha(rowPixels[column]);
+ int sourceRed = Color.red(rowPixels[column]);
+ int sourceGreen = Color.green(rowPixels[column]);
+ int sourceBlue = Color.blue(rowPixels[column]);
+
+ int expectedAlpha = Color.alpha(color);
+ int expectedRed = Color.red(color);
+ int expectedGreen = Color.green(color);
+ int expectedBlue = Color.blue(color);
+
+ int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
+ int varianceRed = Math.abs(sourceRed - expectedRed);
+ int varianceGreen = Math.abs(sourceGreen - expectedGreen);
+ int varianceBlue = Math.abs(sourceBlue - expectedBlue);
+
+ boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
+ && (varianceRed <= allowedComponentVariance)
+ && (varianceGreen <= allowedComponentVariance)
+ && (varianceBlue <= allowedComponentVariance);
+
+ if (!isColorMatch) {
+ String mismatchDescription = failMessagePrefix
+ + ": expected all drawable colors to be ["
+ + expectedAlpha + "," + expectedRed + ","
+ + expectedGreen + "," + expectedBlue
+ + "] but at position (" + row + "," + column + ") found ["
+ + sourceAlpha + "," + sourceRed + ","
+ + sourceGreen + "," + sourceBlue + "]";
+ if (throwExceptionIfFails) {
+ throw new RuntimeException(mismatchDescription);
+ } else {
+ Assert.fail(mismatchDescription);
+ }
+ }
+ }
+ }
+ } finally {
+ bitmap.recycle();
+ }
+ }
+}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
index 049e7a5..7d4b75d 100644
--- a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
+++ b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
@@ -16,10 +16,18 @@
package android.support.design.testutils;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
import android.support.test.espresso.matcher.BoundedMatcher;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.TextViewCompat;
import android.view.View;
+import android.view.ViewParent;
+import android.widget.TextView;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
public class TestUtilsMatchers {
/**
@@ -71,4 +79,163 @@
}
};
}
+
+ /**
+ * Returns a matcher that matches TextViews with the specified text size.
+ */
+ public static Matcher withTextSize(final float textSize) {
+ return new BoundedMatcher<View, TextView>(TextView.class) {
+ private String failedCheckDescription;
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(failedCheckDescription);
+ }
+
+ @Override
+ public boolean matchesSafely(final TextView view) {
+ final float ourTextSize = view.getTextSize();
+ if (Math.abs(textSize - ourTextSize) > 1.0f) {
+ failedCheckDescription =
+ "text size " + ourTextSize + " is different than expected " + textSize;
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Returns a matcher that matches TextViews with the specified text color.
+ */
+ public static Matcher withTextColor(final @ColorInt int textColor) {
+ return new BoundedMatcher<View, TextView>(TextView.class) {
+ private String failedCheckDescription;
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(failedCheckDescription);
+ }
+
+ @Override
+ public boolean matchesSafely(final TextView view) {
+ final @ColorInt int ourTextColor = view.getCurrentTextColor();
+ if (ourTextColor != textColor) {
+ int ourAlpha = Color.alpha(ourTextColor);
+ int ourRed = Color.red(ourTextColor);
+ int ourGreen = Color.green(ourTextColor);
+ int ourBlue = Color.blue(ourTextColor);
+
+ int expectedAlpha = Color.alpha(textColor);
+ int expectedRed = Color.red(textColor);
+ int expectedGreen = Color.green(textColor);
+ int expectedBlue = Color.blue(textColor);
+
+ failedCheckDescription =
+ "expected color to be ["
+ + expectedAlpha + "," + expectedRed + ","
+ + expectedGreen + "," + expectedBlue
+ + "] but found ["
+ + ourAlpha + "," + ourRed + ","
+ + ourGreen + "," + ourBlue + "]";
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Returns a matcher that matches TextViews whose start drawable is filled with the specified
+ * fill color.
+ */
+ public static Matcher withStartDrawableFilledWith(final @ColorInt int fillColor,
+ final int allowedComponentVariance) {
+ return new BoundedMatcher<View, TextView>(TextView.class) {
+ private String failedCheckDescription;
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(failedCheckDescription);
+ }
+
+ @Override
+ public boolean matchesSafely(final TextView view) {
+ Drawable[] compoundDrawables = view.getCompoundDrawables();
+ boolean isRtl =
+ (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL);
+ Drawable startDrawable = isRtl ? compoundDrawables[2] : compoundDrawables[0];
+ if (startDrawable == null) {
+ failedCheckDescription = "no start drawable";
+ return false;
+ }
+ try {
+ TestUtils.assertAllPixelsOfColor("",
+ startDrawable, startDrawable.getIntrinsicWidth(),
+ startDrawable.getIntrinsicHeight(), true,
+ fillColor, allowedComponentVariance, true);
+ } catch (Throwable t) {
+ failedCheckDescription = t.getMessage();
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Returns a matcher that matches Views with the specified background fill color.
+ */
+ public static Matcher withBackgroundFill(final @ColorInt int fillColor) {
+ return new BoundedMatcher<View, View>(View.class) {
+ private String failedCheckDescription;
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(failedCheckDescription);
+ }
+
+ @Override
+ public boolean matchesSafely(final View view) {
+ Drawable background = view.getBackground();
+ try {
+ TestUtils.assertAllPixelsOfColor("",
+ background, view.getWidth(), view.getHeight(), true,
+ fillColor, 0, true);
+ } catch (Throwable t) {
+ failedCheckDescription = t.getMessage();
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Returns a matcher that matches {@link View}s based on the given parent type.
+ *
+ * @param parentMatcher the type of the parent to match on
+ */
+ public static Matcher<View> isChildOfA(final Matcher<View> parentMatcher) {
+ return new TypeSafeMatcher<View>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is child of a: ");
+ parentMatcher.describeTo(description);
+ }
+
+ @Override
+ public boolean matchesSafely(View view) {
+ final ViewParent viewParent = view.getParent();
+ if (!(viewParent instanceof View)) {
+ return false;
+ }
+ if (parentMatcher.matches(viewParent)) {
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
}
diff --git a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java b/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
index bda213c..0c09e7b 100644
--- a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
+++ b/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
@@ -17,26 +17,17 @@
package android.support.design.widget;
import android.app.Activity;
-import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.test.ActivityInstrumentationTestCase2;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-public abstract class BaseInstrumentationTestCase<A extends Activity>
- extends ActivityInstrumentationTestCase2<A> {
+public abstract class BaseInstrumentationTestCase<A extends Activity> {
+ @Rule
+ public final ActivityTestRule<A> mActivityTestRule;
protected BaseInstrumentationTestCase(Class<A> activityClass) {
- super(activityClass);
+ mActivityTestRule = new ActivityTestRule<A>(activityClass);
}
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- injectInstrumentation(InstrumentationRegistry.getInstrumentation());
- getActivity();
- }
-
}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
index 9634a58..3d21033 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
@@ -16,11 +16,9 @@
package android.support.design.widget;
-import org.hamcrest.Matcher;
-import org.junit.Test;
-
import android.support.annotation.NonNull;
import android.support.design.test.R;
+import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingResource;
import android.support.test.espresso.action.CoordinatesProvider;
@@ -35,6 +33,8 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.view.ViewGroup;
+import org.hamcrest.Matcher;
+import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
@@ -196,9 +196,9 @@
@Test
@MediumTest
- public void testInvisible() throws Throwable {
+ public void testInvisible() {
// Make the bottomsheet invisible
- runTestOnUiThread(new Runnable() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
getBottomSheet().setVisibility(View.INVISIBLE);
@@ -217,7 +217,7 @@
}, Press.FINGER),
not(ViewMatchers.isDisplayed())));
// Check that the bottom sheet stays the same collapsed state
- runTestOnUiThread(new Runnable() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
@@ -225,10 +225,15 @@
});
}
- private void checkSetState(int state, Matcher<View> matcher) {
+ private void checkSetState(final int state, Matcher<View> matcher) {
registerIdlingResourceCallback();
try {
- getBehavior().setState(state);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ getBehavior().setState(state);
+ }
+ });
Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
.check(ViewAssertions.matches(matcher));
assertThat(getBehavior().getState(), is(state));
@@ -251,15 +256,15 @@
}
private ViewGroup getBottomSheet() {
- return getActivity().mBottomSheet;
+ return mActivityTestRule.getActivity().mBottomSheet;
}
private BottomSheetBehavior getBehavior() {
- return getActivity().mBehavior;
+ return mActivityTestRule.getActivity().mBehavior;
}
private CoordinatorLayout getCoordinatorLayout() {
- return getActivity().mCoordinatorLayout;
+ return mActivityTestRule.getActivity().mCoordinatorLayout;
}
}
diff --git a/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java b/design/tests/src/android/support/design/widget/NavigationViewActivity.java
similarity index 64%
copy from v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
copy to design/tests/src/android/support/design/widget/NavigationViewActivity.java
index 7366127..c3e810c 100644
--- a/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
+++ b/design/tests/src/android/support/design/widget/NavigationViewActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.support.design.widget;
-package android.support.v4.widget.test;
+import android.support.design.test.R;
-
-import android.app.Activity;
-
-public class TextViewTestActivity extends Activity {
-
+public class NavigationViewActivity extends BaseTestActivity {
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.design_navigation_view;
+ }
}
diff --git a/design/tests/src/android/support/design/widget/NavigationViewTest.java b/design/tests/src/android/support/design/widget/NavigationViewTest.java
new file mode 100755
index 0000000..fd913dc
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/NavigationViewTest.java
@@ -0,0 +1,491 @@
+/*
+ * 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.
+ */
+package android.support.design.widget;
+
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IdRes;
+import android.support.design.test.R;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.widget.RecyclerView;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static android.support.design.testutils.DrawerLayoutActions.closeDrawer;
+import static android.support.design.testutils.DrawerLayoutActions.openDrawer;
+import static android.support.design.testutils.NavigationViewActions.*;
+import static android.support.design.testutils.TestUtilsMatchers.*;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.*;
+import static org.hamcrest.core.AllOf.allOf;
+import static org.junit.Assert.*;
+
+public class NavigationViewTest
+ extends BaseInstrumentationTestCase<NavigationViewActivity> {
+ private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
+ R.id.destination_profile, R.id.destination_people, R.id.destination_settings };
+ private Map<Integer, String> mMenuStringContent;
+
+ private DrawerLayout mDrawerLayout;
+
+ private NavigationView mNavigationView;
+
+ private int mLastSelectedNavigationItemId;
+
+ public NavigationViewTest() {
+ super(NavigationViewActivity.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ final NavigationViewActivity activity = mActivityTestRule.getActivity();
+ mDrawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
+ mNavigationView = (NavigationView) mDrawerLayout.findViewById(R.id.start_drawer);
+
+ // Close the drawer to reset the state for the next test
+ onView(withId(R.id.drawer_layout)).perform(closeDrawer(GravityCompat.START));
+
+ final Resources res = activity.getResources();
+ mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
+ mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
+ mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
+ mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
+ mMenuStringContent.put(R.id.destination_settings,
+ res.getString(R.string.navigate_settings));
+ }
+
+ @Test
+ @SmallTest
+ public void testBasics() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ // Check the contents of the Menu object
+ final Menu menu = mNavigationView.getMenu();
+ assertNotNull("Menu should not be null", menu);
+ assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length,
+ menu.size());
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ final MenuItem currItem = menu.getItem(i);
+ assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
+ }
+
+ // Check that we have the expected menu items in our NavigationView
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(isDisplayed()));
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testTextAppearance() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ final int defaultTextSize = res.getDimensionPixelSize(R.dimen.text_medium_size);
+
+ // Check the default style of the menu items in our NavigationView
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(
+ matches(withTextSize(defaultTextSize)));
+ }
+
+ // Set a new text appearance on our NavigationView
+ onView(withId(R.id.start_drawer)).perform(setItemTextAppearance(R.style.TextSmallStyle));
+
+ // And check that all the menu items have the new style
+ final int newTextSize = res.getDimensionPixelSize(R.dimen.text_small_size);
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(
+ matches(withTextSize(newTextSize)));
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testTextColor() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ final @ColorInt int defaultTextColor = ResourcesCompat.getColor(res,
+ R.color.emerald_text, null);
+
+ // Check the default text color of the menu items in our NavigationView
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(
+ matches(withTextColor(defaultTextColor)));
+ }
+
+ // Set a new text color on our NavigationView
+ onView(withId(R.id.start_drawer)).perform(setItemTextColor(
+ ResourcesCompat.getColorStateList(res, R.color.color_state_list_lilac, null)));
+
+ // And check that all the menu items have the new color
+ final @ColorInt int newTextColor = ResourcesCompat.getColor(res,
+ R.color.lilac_default, null);
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(
+ matches(withTextColor(newTextColor)));
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testBackground() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ final @ColorInt int defaultFillColor = ResourcesCompat.getColor(res,
+ R.color.sand_default, null);
+
+ // Check the default fill color of the menu items in our NavigationView
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ // Note that here we're tying ourselves to the implementation details of the
+ // internal structure of the NavigationView. Specifically, we're looking at the
+ // direct child of RecyclerView which is expected to have the background set
+ // on it. If the internal implementation of NavigationView changes, the second
+ // Matcher below will need to be tweaked.
+ Matcher menuItemMatcher = allOf(
+ hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
+ isChildOfA(isAssignableFrom(RecyclerView.class)),
+ isDescendantOfA(withId(R.id.start_drawer)));
+
+ onView(menuItemMatcher).check(matches(withBackgroundFill(defaultFillColor)));
+ }
+
+ // Set a new background (flat fill color) on our NavigationView
+ onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
+ R.drawable.test_background_blue));
+
+ // And check that all the menu items have the new fill
+ final @ColorInt int newFillColorBlue = ResourcesCompat.getColor(res,
+ R.color.test_blue, null);
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ Matcher menuItemMatcher = allOf(
+ hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
+ isChildOfA(isAssignableFrom(RecyclerView.class)),
+ isDescendantOfA(withId(R.id.start_drawer)));
+
+ onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorBlue)));
+ }
+
+ // Set another new background on our NavigationView
+ onView(withId(R.id.start_drawer)).perform(setItemBackground(
+ ResourcesCompat.getDrawable(res, R.drawable.test_background_green, null)));
+
+ // And check that all the menu items have the new fill
+ final @ColorInt int newFillColorGreen = ResourcesCompat.getColor(res,
+ R.color.test_green, null);
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ Matcher menuItemMatcher = allOf(
+ hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
+ isChildOfA(isAssignableFrom(RecyclerView.class)),
+ isDescendantOfA(withId(R.id.start_drawer)));
+
+ onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorGreen)));
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testIconTinting() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ final @ColorInt int defaultTintColor = ResourcesCompat.getColor(res,
+ R.color.emerald_translucent, null);
+
+ // We're allowing a margin of error in checking the color of the items' icons.
+ // This is due to the translucent color being used in the icon tinting
+ // and off-by-one discrepancies of SRC_IN when it's compositing
+ // translucent color. Note that all the checks below are written for the current
+ // logic on NavigationView that uses the default SRC_IN tint mode - effectively
+ // replacing all non-transparent pixels in the destination (original icon) with
+ // our translucent tint color.
+ final int allowedComponentVariance = 1;
+
+ // Note that here we're tying ourselves to the implementation details of the
+ // internal structure of the NavigationView. Specifically, we're checking the
+ // start drawable of the text view with the specific text. If the internal
+ // implementation of NavigationView changes, the second Matcher in the lookups
+ // below will need to be tweaked.
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
+
+ final @ColorInt int newTintColor = ResourcesCompat.getColor(res,
+ R.color.red_translucent, null);
+
+ onView(withId(R.id.start_drawer)).perform(setItemIconTintList(
+ ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
+ null)));
+ // Check that all menu items with icons now have icons tinted with the newly set color
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
+
+ // And now remove all icon tinting
+ onView(withId(R.id.start_drawer)).perform(setItemIconTintList(null));
+ // And verify that all menu items with icons now have the original colors for their icons.
+ // Note that since there is no tinting at this point, we don't allow any color variance
+ // in these checks.
+ final @ColorInt int redIconColor = ResourcesCompat.getColor(res, R.color.test_red, null);
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(redIconColor, 0)));
+ final @ColorInt int greenIconColor = ResourcesCompat.getColor(res, R.color.test_green,
+ null);
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(greenIconColor, 0)));
+ final @ColorInt int blueIconColor = ResourcesCompat.getColor(res, R.color.test_blue, null);
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
+ withStartDrawableFilledWith(blueIconColor, 0)));
+ }
+
+ /**
+ * Gets the list of header IDs (which can be empty) and verifies that the actual header content
+ * of our navigation view matches the expected header content.
+ */
+ private void verifyHeaders(@IdRes int ... expectedHeaderIds) {
+ final int expectedHeaderCount = (expectedHeaderIds != null) ? expectedHeaderIds.length : 0;
+ final int actualHeaderCount = mNavigationView.getHeaderCount();
+ assertEquals("Header count", expectedHeaderCount, actualHeaderCount);
+
+ if (expectedHeaderCount > 0) {
+ for (int i = 0; i < expectedHeaderCount; i++) {
+ final View currentHeader = mNavigationView.getHeaderView(i);
+ assertEquals("Header at #" + i, expectedHeaderIds[i], currentHeader.getId());
+ }
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testHeaders() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ // We should have no headers at the start
+ verifyHeaders();
+
+ // Inflate one header and check that it's there in the navigation view
+ onView(withId(R.id.start_drawer)).perform(
+ inflateHeaderView(R.layout.design_navigation_view_header1));
+ verifyHeaders(R.id.header1);
+
+ final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+
+ // Add one more header and check that it's there in the navigation view
+ onView(withId(R.id.start_drawer)).perform(
+ addHeaderView(inflater, R.layout.design_navigation_view_header2));
+ verifyHeaders(R.id.header1, R.id.header2);
+
+ final View header1 = mNavigationView.findViewById(R.id.header1);
+ // Remove the first header and check that we still have the second header
+ onView(withId(R.id.start_drawer)).perform(removeHeaderView(header1));
+ verifyHeaders(R.id.header2);
+
+ // Add one more header and check that we now have two headers
+ onView(withId(R.id.start_drawer)).perform(
+ inflateHeaderView(R.layout.design_navigation_view_header3));
+ verifyHeaders(R.id.header2, R.id.header3);
+
+ // Add another "copy" of the header from the just-added layout and check that we now
+ // have three headers
+ onView(withId(R.id.start_drawer)).perform(
+ addHeaderView(inflater, R.layout.design_navigation_view_header3));
+ verifyHeaders(R.id.header2, R.id.header3, R.id.header3);
+ }
+
+ @Test
+ @SmallTest
+ public void testNavigationSelectionListener() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
+ // Check that the drawer is still open
+ assertTrue("Drawer is still open after click",
+ mDrawerLayout.isDrawerOpen(GravityCompat.START));
+
+ // Register a listener
+ mNavigationView.setNavigationItemSelectedListener(
+ new NavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(MenuItem item) {
+ mLastSelectedNavigationItemId = item.getItemId();
+ return false;
+ }
+ });
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+ isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
+ // Check that the drawer is still open
+ assertTrue("Drawer is still open after click",
+ mDrawerLayout.isDrawerOpen(GravityCompat.START));
+ // And that our listener has been notified of the click
+ assertEquals("Selected item ID", R.id.destination_profile, mLastSelectedNavigationItemId);
+
+ // Reset the tracker field and set null listener
+ mLastSelectedNavigationItemId = -1;
+ mNavigationView.setNavigationItemSelectedListener(null);
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
+ isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
+ // Check that the drawer is still open
+ assertTrue("Drawer is still open after click",
+ mDrawerLayout.isDrawerOpen(GravityCompat.START));
+ // And that our previous listener has not been notified of the click
+ assertEquals("Selected item ID", -1, mLastSelectedNavigationItemId);
+ }
+
+ private void verifyCheckedAppearance(@IdRes int checkedItemId,
+ @ColorInt int uncheckedItemForeground, @ColorInt int checkedItemForeground,
+ @ColorInt int uncheckedItemBackground, @ColorInt int checkedItemBackground) {
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ final boolean expectedToBeChecked = (MENU_CONTENT_ITEM_IDS[i] == checkedItemId);
+ final @ColorInt int expectedItemForeground =
+ expectedToBeChecked ? checkedItemForeground : uncheckedItemForeground;
+ final @ColorInt int expectedItemBackground =
+ expectedToBeChecked ? checkedItemBackground : uncheckedItemBackground;
+
+ // For the background fill check we need to select a view that has its background
+ // set by the current implementation (see disclaimer in testBackground)
+ Matcher menuItemMatcher = allOf(
+ hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
+ isChildOfA(isAssignableFrom(RecyclerView.class)),
+ isDescendantOfA(withId(R.id.start_drawer)));
+ onView(menuItemMatcher).check(matches(withBackgroundFill(expectedItemBackground)));
+
+ // And for the foreground color check we need to select a view with the text content
+ Matcher menuItemTextMatcher = allOf(
+ withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
+ isDescendantOfA(withId(R.id.start_drawer)));
+ onView(menuItemTextMatcher).check(matches(withTextColor(expectedItemForeground)));
+ }
+ }
+
+ @Test
+ @SmallTest
+ public void testCheckedAppearance() {
+ // Open our drawer
+ onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
+
+ // Reconfigure our navigation view to use foreground (text) and background visuals
+ // with explicitly different colors for the checked state
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ onView(withId(R.id.start_drawer)).perform(setItemTextColor(
+ ResourcesCompat.getColorStateList(res, R.color.color_state_list_sand, null)));
+ onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
+ R.drawable.test_drawable_state_list));
+
+ final @ColorInt int uncheckedItemForeground = ResourcesCompat.getColor(res,
+ R.color.sand_default, null);
+ final @ColorInt int checkedItemForeground = ResourcesCompat.getColor(res,
+ R.color.sand_checked, null);
+ final @ColorInt int uncheckedItemBackground = ResourcesCompat.getColor(res,
+ R.color.test_green, null);
+ final @ColorInt int checkedItemBackground = ResourcesCompat.getColor(res,
+ R.color.test_blue, null);
+
+ // Verify that all items are rendered with unchecked visuals
+ verifyCheckedAppearance(0, uncheckedItemForeground, checkedItemForeground,
+ uncheckedItemBackground, checkedItemBackground);
+
+ // Mark one of the items as checked
+ onView(withId(R.id.start_drawer)).perform(setCheckedItem(R.id.destination_profile));
+ // And verify that it's now rendered with checked visuals
+ verifyCheckedAppearance(R.id.destination_profile,
+ uncheckedItemForeground, checkedItemForeground,
+ uncheckedItemBackground, checkedItemBackground);
+
+ // Register a navigation listener that "marks" the selected item
+ mNavigationView.setNavigationItemSelectedListener(
+ new NavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(MenuItem item) {
+ return true;
+ }
+ });
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
+ // and verify that it's now checked
+ verifyCheckedAppearance(R.id.destination_people,
+ uncheckedItemForeground, checkedItemForeground,
+ uncheckedItemBackground, checkedItemBackground);
+
+ // Register a navigation listener that doesn't "mark" the selected item
+ mNavigationView.setNavigationItemSelectedListener(
+ new NavigationView.OnNavigationItemSelectedListener() {
+ @Override
+ public boolean onNavigationItemSelected(MenuItem item) {
+ return false;
+ }
+ });
+
+ // Click another items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
+ isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
+ // and verify that the checked state remains on the previously clicked item
+ // since the current navigation listener returns false from its callback
+ // implementation
+ verifyCheckedAppearance(R.id.destination_people,
+ uncheckedItemForeground, checkedItemForeground,
+ uncheckedItemBackground, checkedItemBackground);
+ }
+}
diff --git a/design/tests/src/android/support/design/widget/SnackbarBucketTests.java b/design/tests/src/android/support/design/widget/SnackbarBucketTests.java
index e4b1b68..db8d33a 100644
--- a/design/tests/src/android/support/design/widget/SnackbarBucketTests.java
+++ b/design/tests/src/android/support/design/widget/SnackbarBucketTests.java
@@ -16,9 +16,6 @@
package android.support.design.widget;
-import org.junit.Test;
-
-import android.content.Intent;
import android.os.SystemClock;
import android.support.design.test.R;
import android.support.test.espresso.ViewAction;
@@ -26,6 +23,7 @@
import android.support.test.espresso.action.ViewActions;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import org.junit.Test;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -33,6 +31,8 @@
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
public class SnackbarBucketTests extends BaseInstrumentationTestCase<SnackbarBucketTestsActivity> {
@@ -121,6 +121,6 @@
}
private CoordinatorLayout getCoordinatorLayout() {
- return getActivity().mCoordinatorLayout;
+ return mActivityTestRule.getActivity().mCoordinatorLayout;
}
}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithLayoutItems.java b/design/tests/src/android/support/design/widget/TabLayoutWithLayoutItems.java
index 61e5768..603c2d4 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutWithLayoutItems.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutWithLayoutItems.java
@@ -16,12 +16,14 @@
package android.support.design.widget;
-import org.junit.Test;
-
import android.support.design.test.R;
+import android.support.test.InstrumentationRegistry;
import android.support.v7.app.AppCompatActivity;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.LayoutInflater;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
public class TabLayoutWithLayoutItems extends BaseInstrumentationTestCase<AppCompatActivity> {
@@ -31,11 +33,12 @@
@Test
@SmallTest
- public void testInflateTabLayoutWithTabItems() throws Throwable {
- runTestOnUiThread(new Runnable() {
+ public void testInflateTabLayoutWithTabItems() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- final LayoutInflater inflater = LayoutInflater.from(getActivity());
+ final LayoutInflater inflater =
+ LayoutInflater.from(mActivityTestRule.getActivity());
final TabLayout tabLayout = (TabLayout) inflater.inflate(
R.layout.design_tabs_items, null);
@@ -43,7 +46,8 @@
// Tab 0 has text, but no icon or custom view
TabLayout.Tab tab = tabLayout.getTabAt(0);
- assertEquals(getActivity().getString(R.string.tab_layout_text), tab.getText());
+ assertEquals(mActivityTestRule.getActivity().getString(R.string.tab_layout_text),
+ tab.getText());
assertNull(tab.getIcon());
assertNull(tab.getCustomView());
@@ -66,12 +70,20 @@
@Test(expected = IllegalArgumentException.class)
@SmallTest
public void testInflateTabLayoutWithNonTabItem() throws Throwable {
- runTestOnUiThread(new Runnable() {
- @Override
+ final Throwable[] exceptions = new Throwable[1];
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
- final LayoutInflater inflater = LayoutInflater.from(getActivity());
- inflater.inflate(R.layout.design_tabs_with_non_tabitems, null);
+ try {
+ final LayoutInflater inflater =
+ LayoutInflater.from(mActivityTestRule.getActivity());
+ inflater.inflate(R.layout.design_tabs_with_non_tabitems, null);
+ } catch (Throwable throwable) {
+ exceptions[0] = throwable;
+ }
}
});
+ if (exceptions[0] != null) {
+ throw exceptions[0];
+ }
}
}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java
index 6fe99a5..ff92b36 100644
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
package android.support.design.widget;
import android.support.design.test.R;
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
index 0a86bce..15d3780 100755
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
+++ b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
@@ -34,6 +34,7 @@
import android.widget.HorizontalScrollView;
import android.widget.TextView;
import org.hamcrest.Matcher;
+import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
@@ -43,6 +44,7 @@
import static android.support.test.espresso.matcher.ViewMatchers.*;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
public class TabLayoutWithViewPagerTest
extends BaseInstrumentationTestCase<TabLayoutWithViewPagerActivity> {
@@ -165,10 +167,9 @@
super(TabLayoutWithViewPagerActivity.class);
}
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
- final TabLayoutWithViewPagerActivity activity = getActivity();
+ final TabLayoutWithViewPagerActivity activity = mActivityTestRule.getActivity();
mTabLayout = (TabLayout) activity.findViewById(R.id.tabs);
mViewPager = (ViewPager) activity.findViewById(R.id.tabs_viewpager);
@@ -395,7 +396,7 @@
@DimenRes int tabMaxWidthResId) {
assertEquals("Scrollable tab mode", TabLayout.MODE_SCROLLABLE, mTabLayout.getTabMode());
- final Resources res = getActivity().getResources();
+ final Resources res = mActivityTestRule.getActivity().getResources();
final int minTabWidth = (tabMinWidthResId == 0) ? -1 :
res.getDimensionPixelSize(tabMinWidthResId);
final int maxTabWidth = (tabMaxWidthResId == 0) ? -1 :
diff --git a/v17/leanback/res/layout/lb_guidedstep_fragment.xml b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
index d4983e5..2ffae70 100644
--- a/v17/leanback/res/layout/lb_guidedstep_fragment.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
@@ -18,55 +18,66 @@
<android.support.v17.leanback.app.GuidedStepRootLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/guidedstep_root"
- android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <LinearLayout
- android:id="@+id/content_frame"
- android:orientation="horizontal"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="bottom"
+ android:weightSum="2">
+
+ <FrameLayout
+ android:id="@+id/guidedstep_background_view_root"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="0dp"
+ android:layout_weight="?attr/guidedStepHeightWeight">
- <android.support.v17.leanback.widget.NonOverlappingFrameLayout
- android:id="@+id/content_fragment"
- android:layout_toStartOf="@+id/action_fragment"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true" />
-
- <android.support.v17.leanback.widget.NonOverlappingFrameLayout
- android:id="@+id/action_fragment_root"
- android:transitionName="action_fragment_root"
- android:transitionGroup="false"
+ <LinearLayout
+ android:id="@+id/content_frame"
android:orientation="horizontal"
- android:clipToPadding="false"
- android:clipChildren="false"
- android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
- android:layout_width="0dp"
- android:layout_weight="?attr/guidedActionContentWidthWeight"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <android.support.v17.leanback.widget.NonOverlappingView
- android:id="@+id/action_fragment_background"
- android:transitionName="action_fragment_background"
- android:orientation="horizontal"
- android:outlineProvider="paddedBounds"
- android:layout_width="match_parent"
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/content_fragment"
+ android:layout_width="0dp"
+ android:layout_weight="1"
android:layout_height="match_parent"
- android:background="?attr/guidedActionsBackground"
- android:elevation="?attr/guidedActionsElevation" />
+ android:layout_alignParentStart="true" />
- <android.support.v17.leanback.widget.NonOverlappingLinearLayout
- android:id="@+id/action_fragment"
- android:transitionName="action_fragment"
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/action_fragment_root"
+ android:transitionName="action_fragment_root"
android:transitionGroup="false"
android:orientation="horizontal"
- android:layout_width="match_parent"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
+ android:layout_width="0dp"
+ android:layout_weight="?attr/guidedActionContentWidthWeight"
android:layout_height="match_parent"
- android:elevation="?attr/guidedActionsElevation" />
- </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+ android:layout_alignParentEnd="true">
- </LinearLayout>
-</android.support.v17.leanback.app.GuidedStepRootLayout>
\ No newline at end of file
+ <android.support.v17.leanback.widget.NonOverlappingView
+ android:id="@+id/action_fragment_background"
+ android:transitionName="action_fragment_background"
+ android:orientation="horizontal"
+ android:outlineProvider="paddedBounds"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/guidedActionsBackground"
+ android:elevation="?attr/guidedActionsElevation" />
+
+ <android.support.v17.leanback.widget.NonOverlappingLinearLayout
+ android:id="@+id/action_fragment"
+ android:transitionName="action_fragment"
+ android:transitionGroup="false"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="?attr/guidedActionsElevation" />
+ </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+</android.support.v17.leanback.app.GuidedStepRootLayout>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index ebffa93..cde7a2d 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -318,6 +318,11 @@
can set this to <code>@style/Theme.Leanback.GuidedStep</code> in order to specify the
default GuidedStepFragment styles. -->
<attr name="guidedStepTheme" format="reference" />
+ <!-- Used to control the height of the fragment. By default this fragment will take
+ up the full height of it's parent. The height of this fragment is governed by
+ this property. Default weight is set to 2.0, so inorder to render the fragment
+ in half screen mode, this attribute should be set to 1.0 -->
+ <attr name="guidedStepHeightWeight" format="float" />
<!-- @hide
Theme attribute used to inspect theme inheritance. -->
@@ -475,7 +480,6 @@
<attr name="guidedActionContentWidth" format="reference" />
<!-- Deprecated theme attribute, do not use -->
<attr name="guidedActionContentWidthNoIcon" format="reference" />
-
</declare-styleable>
<declare-styleable name="lbDatePicker">
@@ -485,4 +489,4 @@
<attr name="datePickerFormat" format="string"/>
</declare-styleable>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index 87b3549..5823d2b 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -237,6 +237,8 @@
<dimen name="lb_guidedactions_elevation">12dp</dimen>
<dimen name="lb_guidedactions_vertical_padding">12dp</dimen>
+ <item name="lb_guidedstep_height_weight" format="float" type="string">2.0</item>
+ <item name="lb_guidedstep_height_weight_translucent" format="float" type="string">1.0</item>
<item name="lb_guidedactions_item_disabled_text_alpha" format="float" type="string">0.25</item>
<item name="lb_guidedactions_item_disabled_description_text_alpha" format="float" type="string">0.25</item>
<item name="lb_guidedactions_item_unselected_text_alpha" format="float" type="string">1.00</item>
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index 42b49bc..1c52769 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -121,6 +121,7 @@
<style name="Theme.Leanback.GuidedStep" parent="Theme.LeanbackBase">
<item name="guidedStepThemeFlag">true</item>
+ <item name="guidedStepHeightWeight">@string/lb_guidedstep_height_weight</item>
<item name="android:windowEnterTransition">@transition/lb_guidedstep_activity_enter</item>
@@ -169,4 +170,9 @@
<item name="guidedActionVerticalPadding">@dimen/lb_guidedactions_vertical_padding</item>
</style>
+ <style name="Theme.Leanback.GuidedStep.Half" parent="Theme.Leanback.GuidedStep">
+ <item name="guidedStepHeightWeight">@string/lb_guidedstep_height_weight_translucent</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
</resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index 8042242..515946c 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -25,8 +25,8 @@
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.GuidanceStylist;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
@@ -46,8 +46,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -582,7 +582,6 @@
public static int addAsRoot(Activity activity, GuidedStepFragment fragment, int id) {
// Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
activity.getWindow().getDecorView();
-
FragmentManager fragmentManager = activity.getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
@@ -965,8 +964,10 @@
GuidedStepRootLayout root = (GuidedStepRootLayout) inflater.inflate(
R.layout.lb_guidedstep_fragment, container, false);
+
root.setFocusOutStart(isFocusOutStartAllowed());
root.setFocusOutEnd(isFocusOutEndAllowed());
+
ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
@@ -1067,9 +1068,12 @@
setSelectedButtonActionPosition(0);
+ // Add the background view.
View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
if (backgroundView != null) {
- root.addView(backgroundView, 0);
+ FrameLayout backgroundViewRoot = (FrameLayout)root.findViewById(
+ R.id.guidedstep_background_view_root);
+ backgroundViewRoot.addView(backgroundView, 0);
}
return root;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
index 9fc3720..e644636 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
@@ -18,13 +18,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
/**
* Utility class used by GuidedStepFragment to disable focus out left/right.
* @hide
*/
-class GuidedStepRootLayout extends FrameLayout {
+class GuidedStepRootLayout extends LinearLayout {
private boolean mFocusOutStart = false;
private boolean mFocusOutEnd = false;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
index b76c990..bedd570 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -27,8 +27,8 @@
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.GuidanceStylist;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
@@ -48,8 +48,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -584,7 +584,6 @@
public static int addAsRoot(FragmentActivity activity, GuidedStepSupportFragment fragment, int id) {
// Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
activity.getWindow().getDecorView();
-
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
@@ -967,8 +966,10 @@
GuidedStepRootLayout root = (GuidedStepRootLayout) inflater.inflate(
R.layout.lb_guidedstep_fragment, container, false);
+
root.setFocusOutStart(isFocusOutStartAllowed());
root.setFocusOutEnd(isFocusOutEndAllowed());
+
ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
@@ -1069,9 +1070,12 @@
setSelectedButtonActionPosition(0);
+ // Add the background view.
View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
if (backgroundView != null) {
- root.addView(backgroundView, 0);
+ FrameLayout backgroundViewRoot = (FrameLayout)root.findViewById(
+ R.id.guidedstep_background_view_root);
+ backgroundViewRoot.addView(backgroundView, 0);
}
return root;
}
diff --git a/v4/api23/android/support/v4/widget/TextViewCompatApi23.java b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
index 8370bfc..ad21409 100644
--- a/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
+++ b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
@@ -18,10 +18,11 @@
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
+import android.support.annotation.StyleRes;
import android.widget.TextView;
class TextViewCompatApi23 {
- public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ public static void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
textView.setTextAppearance(resId);
}
}
diff --git a/v4/build.gradle b/v4/build.gradle
index 993eb5a..1bb53ca 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -65,8 +65,12 @@
// when manipulating the libraryVariants.
compile files(internalJar.archivePath)
- androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
- androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+ androidTestCompile ('com.android.support.test:runner:0.4.1') {
+ exclude module: 'support-annotations'
+ }
+ androidTestCompile ('com.android.support.test.espresso:espresso-core:2.2.1') {
+ exclude module: 'support-annotations'
+ }
testCompile 'junit:junit:4.12'
}
diff --git a/v4/java/android/support/v4/app/FragmentActivity.java b/v4/java/android/support/v4/app/FragmentActivity.java
index 4d6585a..0fbe357 100644
--- a/v4/java/android/support/v4/app/FragmentActivity.java
+++ b/v4/java/android/support/v4/app/FragmentActivity.java
@@ -784,7 +784,9 @@
*/
@Override
public void startActivityForResult(Intent intent, int requestCode) {
- if (mStartedActivityFromFragment) {
+ // If this was started from a Fragment we've already checked the upper 16 bits were not in
+ // use, and then repurposed them for the Fragment's index.
+ if (!mStartedActivityFromFragment) {
if (requestCode != -1 && (requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
diff --git a/v4/java/android/support/v4/widget/TextViewCompat.java b/v4/java/android/support/v4/widget/TextViewCompat.java
index 5df1ae6..7af3087 100644
--- a/v4/java/android/support/v4/widget/TextViewCompat.java
+++ b/v4/java/android/support/v4/widget/TextViewCompat.java
@@ -18,9 +18,11 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
import android.widget.TextView;
/**
@@ -40,10 +42,11 @@
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom);
void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom);
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom);
int getMaxLines(TextView textView);
int getMinLines(TextView textView);
- void setTextAppearance(@NonNull TextView textView, @IdRes int resId);
+ void setTextAppearance(@NonNull TextView textView, @StyleRes int resId);
}
static class BaseTextViewCompatImpl implements TextViewCompatImpl {
@@ -63,7 +66,8 @@
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom) {
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom) {
textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
}
@@ -78,7 +82,7 @@
}
@Override
- public void setTextAppearance(TextView textView, int resId) {
+ public void setTextAppearance(TextView textView, @StyleRes int resId) {
TextViewCompatDonut.setTextAppearance(textView, resId);
}
}
@@ -113,7 +117,8 @@
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom) {
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom) {
TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
start, top, end, bottom);
}
@@ -138,7 +143,8 @@
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom) {
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom) {
TextViewCompatJbMr2.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
start, top, end, bottom);
}
@@ -146,7 +152,7 @@
static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
@Override
- public void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ public void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
TextViewCompatApi23.setTextAppearance(textView, resId);
}
}
@@ -228,7 +234,8 @@
* @attr ref android.R.styleable#TextView_drawableBottom
*/
public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom) {
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom) {
IMPL.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end, bottom);
}
@@ -259,7 +266,7 @@
* @param textView The TextView against which to invoke the method.
* @param resId The resource identifier of the style to apply.
*/
- public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ public static void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
IMPL.setTextAppearance(textView, resId);
}
}
diff --git a/v4/jellybean-mr1/android/support/v4/media/routing/MediaRouterJellybeanMr1.java b/v4/jellybean-mr1/android/support/v4/media/routing/MediaRouterJellybeanMr1.java
deleted file mode 100644
index 6e5cfd5..0000000
--- a/v4/jellybean-mr1/android/support/v4/media/routing/MediaRouterJellybeanMr1.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.support.v4.media.routing;
-
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.os.Build;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Display;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-class MediaRouterJellybeanMr1 extends MediaRouterJellybean {
- private static final String TAG = "MediaRouterJellybeanMr1";
-
- public static Object createCallback(Callback callback) {
- return new CallbackProxy<Callback>(callback);
- }
-
- public static final class RouteInfo {
- public static boolean isEnabled(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).isEnabled();
- }
-
- public static Display getPresentationDisplay(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getPresentationDisplay();
- }
- }
-
- public static interface Callback extends MediaRouterJellybean.Callback {
- public void onRoutePresentationDisplayChanged(Object routeObj);
- }
-
- /**
- * Workaround the fact that the version of MediaRouter.addCallback() that accepts a
- * flag to perform an active scan does not exist in JB MR1 so we need to force
- * wifi display scans directly through the DisplayManager.
- * Do not use on JB MR2 and above.
- */
- public static final class ActiveScanWorkaround implements Runnable {
- // Time between wifi display scans when actively scanning in milliseconds.
- private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;
-
- private final DisplayManager mDisplayManager;
- private final Handler mHandler;
- private Method mScanWifiDisplaysMethod;
-
- private boolean mActivelyScanningWifiDisplays;
-
- public ActiveScanWorkaround(Context context, Handler handler) {
- if (Build.VERSION.SDK_INT != 17) {
- throw new UnsupportedOperationException();
- }
-
- mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
- mHandler = handler;
- try {
- mScanWifiDisplaysMethod = DisplayManager.class.getMethod("scanWifiDisplays");
- } catch (NoSuchMethodException ex) {
- }
- }
-
- public void setActiveScanRouteTypes(int routeTypes) {
- // On JB MR1, there is no API to scan wifi display routes.
- // Instead we must make a direct call into the DisplayManager to scan
- // wifi displays on this version but only when live video routes are requested.
- // See also the JellybeanMr2Impl implementation of this method.
- // This was fixed in JB MR2 by adding a new overload of addCallback() to
- // enable active scanning on request.
- if ((routeTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO) != 0) {
- if (!mActivelyScanningWifiDisplays) {
- if (mScanWifiDisplaysMethod != null) {
- mActivelyScanningWifiDisplays = true;
- mHandler.post(this);
- } else {
- Log.w(TAG, "Cannot scan for wifi displays because the "
- + "DisplayManager.scanWifiDisplays() method is "
- + "not available on this device.");
- }
- }
- } else {
- if (mActivelyScanningWifiDisplays) {
- mActivelyScanningWifiDisplays = false;
- mHandler.removeCallbacks(this);
- }
- }
- }
-
- @Override
- public void run() {
- if (mActivelyScanningWifiDisplays) {
- try {
- mScanWifiDisplaysMethod.invoke(mDisplayManager);
- } catch (IllegalAccessException ex) {
- Log.w(TAG, "Cannot scan for wifi displays.", ex);
- } catch (InvocationTargetException ex) {
- Log.w(TAG, "Cannot scan for wifi displays.", ex);
- }
- mHandler.postDelayed(this, WIFI_DISPLAY_SCAN_INTERVAL);
- }
- }
- }
-
- /**
- * Workaround the fact that the isConnecting() method does not exist in JB MR1.
- * Do not use on JB MR2 and above.
- */
- public static final class IsConnectingWorkaround {
- private Method mGetStatusCodeMethod;
- private int mStatusConnecting;
-
- public IsConnectingWorkaround() {
- if (Build.VERSION.SDK_INT != 17) {
- throw new UnsupportedOperationException();
- }
-
- try {
- Field statusConnectingField =
- android.media.MediaRouter.RouteInfo.class.getField("STATUS_CONNECTING");
- mStatusConnecting = statusConnectingField.getInt(null);
- mGetStatusCodeMethod =
- android.media.MediaRouter.RouteInfo.class.getMethod("getStatusCode");
- } catch (NoSuchFieldException ex) {
- } catch (NoSuchMethodException ex) {
- } catch (IllegalAccessException ex) {
- }
- }
-
- public boolean isConnecting(Object routeObj) {
- android.media.MediaRouter.RouteInfo route =
- (android.media.MediaRouter.RouteInfo)routeObj;
-
- if (mGetStatusCodeMethod != null) {
- try {
- int statusCode = (Integer)mGetStatusCodeMethod.invoke(route);
- return statusCode == mStatusConnecting;
- } catch (IllegalAccessException ex) {
- } catch (InvocationTargetException ex) {
- }
- }
-
- // Assume not connecting.
- return false;
- }
- }
-
- static class CallbackProxy<T extends Callback>
- extends MediaRouterJellybean.CallbackProxy<T> {
- public CallbackProxy(T callback) {
- super(callback);
- }
-
- @Override
- public void onRoutePresentationDisplayChanged(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route) {
- mCallback.onRoutePresentationDisplayChanged(route);
- }
- }
-}
diff --git a/v4/jellybean-mr2/android/support/v4/media/routing/MediaRouterJellybeanMr2.java b/v4/jellybean-mr2/android/support/v4/media/routing/MediaRouterJellybeanMr2.java
deleted file mode 100644
index 92a1607..0000000
--- a/v4/jellybean-mr2/android/support/v4/media/routing/MediaRouterJellybeanMr2.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.support.v4.media.routing;
-
-class MediaRouterJellybeanMr2 extends MediaRouterJellybeanMr1 {
- public static Object getDefaultRoute(Object routerObj) {
- return ((android.media.MediaRouter)routerObj).getDefaultRoute();
- }
-
- public static void addCallback(Object routerObj, int types, Object callbackObj, int flags) {
- ((android.media.MediaRouter)routerObj).addCallback(types,
- (android.media.MediaRouter.Callback)callbackObj, flags);
- }
-
- public static final class RouteInfo {
- public static CharSequence getDescription(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getDescription();
- }
-
- public static boolean isConnecting(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).isConnecting();
- }
- }
-
- public static final class UserRouteInfo {
- public static void setDescription(Object routeObj, CharSequence description) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setDescription(description);
- }
- }
-}
diff --git a/v4/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java b/v4/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
index ec9fe61..73f9666 100644
--- a/v4/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
+++ b/v4/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
@@ -17,6 +17,7 @@
package android.support.v4.widget;
import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.TextView;
@@ -36,7 +37,8 @@
}
public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
- int start, int top, int end, int bottom) {
+ @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
+ @DrawableRes int bottom) {
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
diff --git a/v4/jellybean/android/support/v4/media/routing/MediaRouterJellybean.java b/v4/jellybean/android/support/v4/media/routing/MediaRouterJellybean.java
deleted file mode 100644
index 3cf6727..0000000
--- a/v4/jellybean/android/support/v4/media/routing/MediaRouterJellybean.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.support.v4.media.routing;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
-class MediaRouterJellybean {
- private static final String TAG = "MediaRouterJellybean";
-
- public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1;
- public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
- public static final int ROUTE_TYPE_USER = 0x00800000;
-
- public static final int ALL_ROUTE_TYPES =
- MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO
- | MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO
- | MediaRouterJellybean.ROUTE_TYPE_USER;
-
- public static Object getMediaRouter(Context context) {
- return context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static List getRoutes(Object routerObj) {
- final android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
- final int count = router.getRouteCount();
- List out = new ArrayList(count);
- for (int i = 0; i < count; i++) {
- out.add(router.getRouteAt(i));
- }
- return out;
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static List getCategories(Object routerObj) {
- final android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
- final int count = router.getCategoryCount();
- List out = new ArrayList(count);
- for (int i = 0; i < count; i++) {
- out.add(router.getCategoryAt(i));
- }
- return out;
- }
-
- public static Object getSelectedRoute(Object routerObj, int type) {
- return ((android.media.MediaRouter)routerObj).getSelectedRoute(type);
- }
-
- public static void selectRoute(Object routerObj, int types, Object routeObj) {
- ((android.media.MediaRouter)routerObj).selectRoute(types,
- (android.media.MediaRouter.RouteInfo)routeObj);
- }
-
- public static void addCallback(Object routerObj, int types, Object callbackObj) {
- ((android.media.MediaRouter)routerObj).addCallback(types,
- (android.media.MediaRouter.Callback)callbackObj);
- }
-
- public static void removeCallback(Object routerObj, Object callbackObj) {
- ((android.media.MediaRouter)routerObj).removeCallback(
- (android.media.MediaRouter.Callback)callbackObj);
- }
-
- public static Object createRouteCategory(Object routerObj,
- String name, boolean isGroupable) {
- return ((android.media.MediaRouter)routerObj).createRouteCategory(name, isGroupable);
- }
-
- public static Object createUserRoute(Object routerObj, Object categoryObj) {
- return ((android.media.MediaRouter)routerObj).createUserRoute(
- (android.media.MediaRouter.RouteCategory)categoryObj);
- }
-
- public static void addUserRoute(Object routerObj, Object routeObj) {
- ((android.media.MediaRouter)routerObj).addUserRoute(
- (android.media.MediaRouter.UserRouteInfo)routeObj);
- }
-
- public static void removeUserRoute(Object routerObj, Object routeObj) {
- ((android.media.MediaRouter)routerObj).removeUserRoute(
- (android.media.MediaRouter.UserRouteInfo)routeObj);
- }
-
- public static Object createCallback(Callback callback) {
- return new CallbackProxy<Callback>(callback);
- }
-
- public static Object createVolumeCallback(VolumeCallback callback) {
- return new VolumeCallbackProxy<VolumeCallback>(callback);
- }
-
- public static final class RouteInfo {
- public static CharSequence getName(Object routeObj, Context context) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getName(context);
- }
-
- public static CharSequence getStatus(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getStatus();
- }
-
- public static int getSupportedTypes(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getSupportedTypes();
- }
-
- public static Object getCategory(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getCategory();
- }
-
- public static Drawable getIconDrawable(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getIconDrawable();
- }
-
- public static int getPlaybackType(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getPlaybackType();
- }
-
- public static int getPlaybackStream(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getPlaybackStream();
- }
-
- public static int getVolume(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getVolume();
- }
-
- public static int getVolumeMax(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getVolumeMax();
- }
-
- public static int getVolumeHandling(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getVolumeHandling();
- }
-
- public static Object getTag(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getTag();
- }
-
- public static void setTag(Object routeObj, Object tag) {
- ((android.media.MediaRouter.RouteInfo)routeObj).setTag(tag);
- }
-
- public static void requestSetVolume(Object routeObj, int volume) {
- ((android.media.MediaRouter.RouteInfo)routeObj).requestSetVolume(volume);
- }
-
- public static void requestUpdateVolume(Object routeObj, int direction) {
- ((android.media.MediaRouter.RouteInfo)routeObj).requestUpdateVolume(direction);
- }
-
- public static Object getGroup(Object routeObj) {
- return ((android.media.MediaRouter.RouteInfo)routeObj).getGroup();
- }
-
- public static boolean isGroup(Object routeObj) {
- return routeObj instanceof android.media.MediaRouter.RouteGroup;
- }
- }
-
- public static final class RouteGroup {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static List getGroupedRoutes(Object groupObj) {
- final android.media.MediaRouter.RouteGroup group =
- (android.media.MediaRouter.RouteGroup)groupObj;
- final int count = group.getRouteCount();
- List out = new ArrayList(count);
- for (int i = 0; i < count; i++) {
- out.add(group.getRouteAt(i));
- }
- return out;
- }
- }
-
- public static final class UserRouteInfo {
- public static void setName(Object routeObj, CharSequence name) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setName(name);
- }
-
- public static void setStatus(Object routeObj, CharSequence status) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setStatus(status);
- }
-
- public static void setIconDrawable(Object routeObj, Drawable icon) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setIconDrawable(icon);
- }
-
- public static void setPlaybackType(Object routeObj, int type) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setPlaybackType(type);
- }
-
- public static void setPlaybackStream(Object routeObj, int stream) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setPlaybackStream(stream);
- }
-
- public static void setVolume(Object routeObj, int volume) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolume(volume);
- }
-
- public static void setVolumeMax(Object routeObj, int volumeMax) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeMax(volumeMax);
- }
-
- public static void setVolumeHandling(Object routeObj, int volumeHandling) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeHandling(volumeHandling);
- }
-
- public static void setVolumeCallback(Object routeObj, Object volumeCallbackObj) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeCallback(
- (android.media.MediaRouter.VolumeCallback)volumeCallbackObj);
- }
-
- public static void setRemoteControlClient(Object routeObj, Object rccObj) {
- ((android.media.MediaRouter.UserRouteInfo)routeObj).setRemoteControlClient(
- (android.media.RemoteControlClient)rccObj);
- }
- }
-
- public static final class RouteCategory {
- public static CharSequence getName(Object categoryObj, Context context) {
- return ((android.media.MediaRouter.RouteCategory)categoryObj).getName(context);
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static List getRoutes(Object categoryObj) {
- ArrayList out = new ArrayList();
- ((android.media.MediaRouter.RouteCategory)categoryObj).getRoutes(out);
- return out;
- }
-
- public static int getSupportedTypes(Object categoryObj) {
- return ((android.media.MediaRouter.RouteCategory)categoryObj).getSupportedTypes();
- }
-
- public static boolean isGroupable(Object categoryObj) {
- return ((android.media.MediaRouter.RouteCategory)categoryObj).isGroupable();
- }
- }
-
- public static interface Callback {
- public void onRouteSelected(int type, Object routeObj);
- public void onRouteUnselected(int type, Object routeObj);
- public void onRouteAdded(Object routeObj);
- public void onRouteRemoved(Object routeObj);
- public void onRouteChanged(Object routeObj);
- public void onRouteGrouped(Object routeObj, Object groupObj, int index);
- public void onRouteUngrouped(Object routeObj, Object groupObj);
- public void onRouteVolumeChanged(Object routeObj);
- }
-
- public static interface VolumeCallback {
- public void onVolumeSetRequest(Object routeObj, int volume);
- public void onVolumeUpdateRequest(Object routeObj, int direction);
- }
-
- /**
- * Workaround for limitations of selectRoute() on JB and JB MR1.
- * Do not use on JB MR2 and above.
- */
- public static final class SelectRouteWorkaround {
- private Method mSelectRouteIntMethod;
-
- public SelectRouteWorkaround() {
- if (Build.VERSION.SDK_INT < 16 || Build.VERSION.SDK_INT > 17) {
- throw new UnsupportedOperationException();
- }
- try {
- mSelectRouteIntMethod = android.media.MediaRouter.class.getMethod(
- "selectRouteInt", int.class, android.media.MediaRouter.RouteInfo.class);
- } catch (NoSuchMethodException ex) {
- }
- }
-
- public void selectRoute(Object routerObj, int types, Object routeObj) {
- android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
- android.media.MediaRouter.RouteInfo route =
- (android.media.MediaRouter.RouteInfo)routeObj;
-
- int routeTypes = route.getSupportedTypes();
- if ((routeTypes & ROUTE_TYPE_USER) == 0) {
- // Handle non-user routes.
- // On JB and JB MR1, the selectRoute() API only supports programmatically
- // selecting user routes. So instead we rely on the hidden selectRouteInt()
- // method on these versions of the platform.
- // This limitation was removed in JB MR2.
- if (mSelectRouteIntMethod != null) {
- try {
- mSelectRouteIntMethod.invoke(router, types, route);
- return; // success!
- } catch (IllegalAccessException ex) {
- Log.w(TAG, "Cannot programmatically select non-user route. "
- + "Media routing may not work.", ex);
- } catch (InvocationTargetException ex) {
- Log.w(TAG, "Cannot programmatically select non-user route. "
- + "Media routing may not work.", ex);
- }
- } else {
- Log.w(TAG, "Cannot programmatically select non-user route "
- + "because the platform is missing the selectRouteInt() "
- + "method. Media routing may not work.");
- }
- }
-
- // Default handling.
- router.selectRoute(types, route);
- }
- }
-
- /**
- * Workaround the fact that the getDefaultRoute() method does not exist in JB and JB MR1.
- * Do not use on JB MR2 and above.
- */
- public static final class GetDefaultRouteWorkaround {
- private Method mGetSystemAudioRouteMethod;
-
- public GetDefaultRouteWorkaround() {
- if (Build.VERSION.SDK_INT < 16 || Build.VERSION.SDK_INT > 17) {
- throw new UnsupportedOperationException();
- }
- try {
- mGetSystemAudioRouteMethod =
- android.media.MediaRouter.class.getMethod("getSystemAudioRoute");
- } catch (NoSuchMethodException ex) {
- }
- }
-
- public Object getDefaultRoute(Object routerObj) {
- android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
-
- if (mGetSystemAudioRouteMethod != null) {
- try {
- return mGetSystemAudioRouteMethod.invoke(router);
- } catch (IllegalAccessException ex) {
- } catch (InvocationTargetException ex) {
- }
- }
-
- // Could not find the method or it does not work.
- // Return the first route and hope for the best.
- return router.getRouteAt(0);
- }
- }
-
- static class CallbackProxy<T extends Callback>
- extends android.media.MediaRouter.Callback {
- protected final T mCallback;
-
- public CallbackProxy(T callback) {
- mCallback = callback;
- }
-
- @Override
- public void onRouteSelected(android.media.MediaRouter router,
- int type, android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteSelected(type, route);
- }
-
- @Override
- public void onRouteUnselected(android.media.MediaRouter router,
- int type, android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteUnselected(type, route);
- }
-
- @Override
- public void onRouteAdded(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteAdded(route);
- }
-
- @Override
- public void onRouteRemoved(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteRemoved(route);
- }
-
- @Override
- public void onRouteChanged(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteChanged(route);
- }
-
- @Override
- public void onRouteGrouped(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route,
- android.media.MediaRouter.RouteGroup group, int index) {
- mCallback.onRouteGrouped(route, group, index);
- }
-
- @Override
- public void onRouteUngrouped(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route,
- android.media.MediaRouter.RouteGroup group) {
- mCallback.onRouteUngrouped(route, group);
- }
-
- @Override
- public void onRouteVolumeChanged(android.media.MediaRouter router,
- android.media.MediaRouter.RouteInfo route) {
- mCallback.onRouteVolumeChanged(route);
- }
- }
-
- static class VolumeCallbackProxy<T extends VolumeCallback>
- extends android.media.MediaRouter.VolumeCallback {
- protected final T mCallback;
-
- public VolumeCallbackProxy(T callback) {
- mCallback = callback;
- }
-
- @Override
- public void onVolumeSetRequest(android.media.MediaRouter.RouteInfo route,
- int volume) {
- mCallback.onVolumeSetRequest(route, volume);
- }
-
- @Override
- public void onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo route,
- int direction) {
- mCallback.onVolumeUpdateRequest(route, direction);
- }
- }
-}
diff --git a/v4/tests/AndroidManifest.xml b/v4/tests/AndroidManifest.xml
index f99c5d1..85ffd7d 100644
--- a/v4/tests/AndroidManifest.xml
+++ b/v4/tests/AndroidManifest.xml
@@ -20,7 +20,8 @@
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="23"
- tools:overrideLibrary="android.support.test,android.support.test.espresso, android.support.test.espresso.idling"/>
+ tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+ android.support.test.espresso, android.support.test.espresso.idling"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
@@ -29,7 +30,7 @@
<application android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
- <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
+ <activity android:name="android.support.v4.widget.TextViewTestActivity"/>
<activity android:name="android.support.v4.view.ViewPagerWithTitleStripActivity"/>
diff --git a/v4/tests/java/android/support/v4/BaseInstrumentationTestCase.java b/v4/tests/java/android/support/v4/BaseInstrumentationTestCase.java
new file mode 100644
index 0000000..5f9ce85
--- /dev/null
+++ b/v4/tests/java/android/support/v4/BaseInstrumentationTestCase.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.support.v4;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public abstract class BaseInstrumentationTestCase<A extends Activity> {
+ @Rule
+ public final ActivityTestRule<A> mActivityTestRule;
+
+ protected BaseInstrumentationTestCase(Class<A> activityClass) {
+ mActivityTestRule = new ActivityTestRule<A>(activityClass);
+ }
+}
diff --git a/v4/tests/java/android/support/v4/BaseTestActivity.java b/v4/tests/java/android/support/v4/BaseTestActivity.java
new file mode 100755
index 0000000..e0682ce
--- /dev/null
+++ b/v4/tests/java/android/support/v4/BaseTestActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package android.support.v4;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public abstract class BaseTestActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ final int contentView = getContentViewLayoutResId();
+ if (contentView > 0) {
+ setContentView(contentView);
+ }
+ onContentViewSet();
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ protected abstract int getContentViewLayoutResId();
+
+ protected void onContentViewSet() {}
+}
diff --git a/v4/tests/java/android/support/v4/testutils/LayoutDirectionActions.java b/v4/tests/java/android/support/v4/testutils/LayoutDirectionActions.java
new file mode 100755
index 0000000..25ae971
--- /dev/null
+++ b/v4/tests/java/android/support/v4/testutils/LayoutDirectionActions.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.testutils;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+public class LayoutDirectionActions {
+ /**
+ * Sets layout direction on the view.
+ */
+ public static ViewAction setLayoutDirection(final int layoutDirection) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "set layout direction";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ ViewCompat.setLayoutDirection(view, layoutDirection);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+}
diff --git a/v4/tests/java/android/support/v4/testutils/TextViewActions.java b/v4/tests/java/android/support/v4/testutils/TextViewActions.java
new file mode 100644
index 0000000..f67e8c0
--- /dev/null
+++ b/v4/tests/java/android/support/v4/testutils/TextViewActions.java
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.testutils;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.annotation.StyleRes;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.v4.widget.TextViewCompat;
+import android.view.View;
+import android.widget.TextView;
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+
+public class TextViewActions {
+ /**
+ * Sets max lines count on <code>TextView</code>.
+ */
+ public static ViewAction setMaxLines(final int maxLines) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set max lines";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ textView.setMaxLines(maxLines);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets min lines count on <code>TextView</code>.
+ */
+ public static ViewAction setMinLines(final int minLines) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set min lines";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ textView.setMinLines(minLines);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets text content on <code>TextView</code>.
+ */
+ public static ViewAction setText(final @StringRes int stringResId) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set text";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ textView.setText(stringResId);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets text appearance on <code>TextView</code>.
+ */
+ public static ViewAction setTextAppearance(final @StyleRes int styleResId) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set text appearance";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ TextViewCompat.setTextAppearance(textView, styleResId);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets compound drawables on <code>TextView</code>.
+ */
+ public static ViewAction setCompoundDrawablesRelative(final @Nullable Drawable start,
+ final @Nullable Drawable top, final @Nullable Drawable end,
+ final @Nullable Drawable bottom) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set compound drawables";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ TextViewCompat.setCompoundDrawablesRelative(textView, start, top, end, bottom);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets compound drawables on <code>TextView</code>.
+ */
+ public static ViewAction setCompoundDrawablesRelativeWithIntrinsicBounds(
+ final @Nullable Drawable start, final @Nullable Drawable top,
+ final @Nullable Drawable end, final @Nullable Drawable bottom) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set compound drawables";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ textView, start, top, end, bottom);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets compound drawables on <code>TextView</code>.
+ */
+ public static ViewAction setCompoundDrawablesRelativeWithIntrinsicBounds(
+ final @DrawableRes int start, final @DrawableRes int top, final @DrawableRes int end,
+ final @DrawableRes int bottom) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isAssignableFrom(TextView.class);
+ }
+
+ @Override
+ public String getDescription() {
+ return "TextView set compound drawables";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ TextView textView = (TextView) view;
+ TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ textView, start, top, end, bottom);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+}
diff --git a/v4/tests/java/android/support/v4/view/BaseViewPagerTest.java b/v4/tests/java/android/support/v4/view/BaseViewPagerTest.java
index 166fb1e..13d8372 100644
--- a/v4/tests/java/android/support/v4/view/BaseViewPagerTest.java
+++ b/v4/tests/java/android/support/v4/view/BaseViewPagerTest.java
@@ -17,47 +17,32 @@
import android.app.Activity;
import android.graphics.Color;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.test.R;
+import android.support.v4.testutils.TestUtilsAssertions;
+import android.support.v4.testutils.TestUtilsMatchers;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.UiController;
-import android.support.v4.test.R;
-import android.support.v4.testutils.TestUtilsAssertions;
-import android.support.v4.testutils.TestUtilsMatchers;
-import android.support.v4.view.ViewPager;
-import android.support.v4.view.PagerTitleStrip;
-import android.support.v4.widget.TestActivity;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
import java.util.ArrayList;
-import org.hamcrest.Matcher;
-
import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.swipeLeft;
import static android.support.test.espresso.action.ViewActions.swipeRight;
+import static android.support.test.espresso.assertion.PositionAssertions.*;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.assertion.PositionAssertions.isBelow;
-import static android.support.test.espresso.assertion.PositionAssertions.isBottomAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isLeftAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isRightAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isTopAlignedWith;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
+import static android.support.test.espresso.matcher.ViewMatchers.*;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertEquals;
/**
* Base class for testing <code>ViewPager</code>. Most of the testing logic should be in this
@@ -67,8 +52,7 @@
* Testing logic that does depend on the specific pager title implementation is pushed into the
* extending classes in <code>assertStripInteraction()</code> method.
*/
-public abstract class BaseViewPagerTest<T extends Activity>
- extends ActivityInstrumentationTestCase2<T> {
+public abstract class BaseViewPagerTest<T extends Activity> extends BaseInstrumentationTestCase<T> {
protected ViewPager mViewPager;
protected static class BasePagerAdapter<Q> extends PagerAdapter {
@@ -181,14 +165,12 @@
}
public BaseViewPagerTest(Class<T> activityClass) {
- super("android.support.v4.view", activityClass);
+ super(activityClass);
}
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
- final T activity = getActivity();
+ final T activity = mActivityTestRule.getActivity();
mViewPager = (ViewPager) activity.findViewById(R.id.pager);
ColorPagerAdapter adapter = new ColorPagerAdapter();
@@ -199,13 +181,12 @@
ViewPagerActions.scrollToPage(0));
}
- @Override
+ @After
public void tearDown() throws Exception {
onView(withId(R.id.pager)).perform(ViewPagerActions.setAdapter(null));
-
- super.tearDown();
}
+ @Test
@SmallTest
public void testPageSelections() {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
@@ -232,6 +213,7 @@
}
+ @Test
@SmallTest
public void testPageSwipes() {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
@@ -257,6 +239,7 @@
assertEquals("Swipe right beyond first page", 0, mViewPager.getCurrentItem());
}
+ @Test
@SmallTest
public void testPageSwipesComposite() {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
@@ -275,6 +258,7 @@
assertEquals("Swipe right beyond first page and then left", 1, mViewPager.getCurrentItem());
}
+ @Test
@SmallTest
public void testPageContent() {
assertEquals("Initial state", 0, mViewPager.getCurrentItem());
@@ -315,6 +299,7 @@
TestUtilsMatchers.backgroundColor(Color.BLUE))));
}
+ @Test
@SmallTest
public void testAdapterChange() {
// Verify that we have the expected initial adapter
@@ -427,6 +412,7 @@
}
}
+ @Test
@SmallTest
public void testPagerStrip() {
// Set an adapter with 5 pages
diff --git a/v4/tests/java/android/support/v4/view/GravityCompatTest.java b/v4/tests/java/android/support/v4/view/GravityCompatTest.java
index db62b0c..2e2f180 100644
--- a/v4/tests/java/android/support/v4/view/GravityCompatTest.java
+++ b/v4/tests/java/android/support/v4/view/GravityCompatTest.java
@@ -17,15 +17,10 @@
import android.graphics.Rect;
import android.os.Build;
-import android.view.Gravity;
-import android.view.View;
-
import android.support.v4.testutils.TestUtils;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Gravity;
public class GravityCompatTest extends AndroidTestCase {
@SmallTest
diff --git a/v4/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java b/v4/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
index db08a1a..057db99 100644
--- a/v4/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
+++ b/v4/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
@@ -15,16 +15,10 @@
*/
package android.support.v4.view;
-import android.view.View;
-
-import android.support.v4.view.MarginLayoutParamsCompat;
-import android.support.v4.view.ViewCompat;
-
import android.os.Build;
-import android.view.ViewGroup;
-
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ViewGroup;
public class MarginLayoutParamsCompatTest extends AndroidTestCase {
@SmallTest
diff --git a/v4/tests/java/android/support/v4/view/ViewCompatTest.java b/v4/tests/java/android/support/v4/view/ViewCompatTest.java
index 483d16b..29a0f5a 100644
--- a/v4/tests/java/android/support/v4/view/ViewCompatTest.java
+++ b/v4/tests/java/android/support/v4/view/ViewCompatTest.java
@@ -15,12 +15,9 @@
*/
package android.support.v4.view;
-import android.view.View;
-
-import android.support.v4.view.ViewCompat;
-
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
public class ViewCompatTest extends AndroidTestCase {
@SmallTest
diff --git a/v4/tests/java/android/support/v4/view/ViewPagerActions.java b/v4/tests/java/android/support/v4/view/ViewPagerActions.java
index b1e1a76..2b37e6f 100644
--- a/v4/tests/java/android/support/v4/view/ViewPagerActions.java
+++ b/v4/tests/java/android/support/v4/view/ViewPagerActions.java
@@ -22,20 +22,12 @@
import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tap;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.TextView;
-
import org.hamcrest.Matcher;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.allOf;
public class ViewPagerActions {
/**
diff --git a/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java b/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
index edc4da9..2cb3048 100644
--- a/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
+++ b/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
@@ -21,8 +21,6 @@
import android.support.v4.test.R;
import android.view.WindowManager;
-import java.util.ArrayList;
-
public class ViewPagerWithTabStripActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java b/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java
index 706d2e2..3e4a82f 100644
--- a/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java
+++ b/v4/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java
@@ -15,7 +15,6 @@
*/
package android.support.v4.view;
-import android.support.v4.view.PagerTitleStrip;
import android.support.v4.test.R;
import static android.support.test.espresso.Espresso.onView;
@@ -23,8 +22,8 @@
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.assertEquals;
/**
* Provides assertions that depend on the interactive nature of <code>PagerTabStrip</code>.
diff --git a/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java b/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
index 28dcb07..49d6e76 100644
--- a/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
+++ b/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
@@ -21,8 +21,6 @@
import android.support.v4.test.R;
import android.view.WindowManager;
-import java.util.ArrayList;
-
public class ViewPagerWithTitleStripActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java b/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
index 528db86..8d831dc 100644
--- a/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
+++ b/v4/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
@@ -15,7 +15,6 @@
*/
package android.support.v4.view;
-import android.support.v4.view.PagerTitleStrip;
import android.support.v4.test.R;
import static android.support.test.espresso.Espresso.onView;
@@ -23,8 +22,8 @@
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.assertEquals;
/**
* Provides assertions that depend on the non-interactive nature of <code>PagerTabStrip</code>.
diff --git a/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
index d0f5b00..3ef236f 100644
--- a/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
+++ b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
@@ -17,35 +17,27 @@
package android.support.v4.widget;
-import org.junit.After;
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.test.R;
+import android.support.v4.testutils.TestUtils;
+import android.support.v4.view.ViewCompat;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.TextView;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import android.app.Instrumentation;
-import android.content.res.Resources;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Looper;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.support.annotation.ColorInt;
-import android.support.annotation.LayoutRes;
-import android.support.test.InstrumentationRegistry;
-import android.support.v4.test.R;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.TextViewCompat;
-import android.support.v4.testutils.TestUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.v4.testutils.LayoutDirectionActions.setLayoutDirection;
+import static android.support.v4.testutils.TextViewActions.*;
+import static org.junit.Assert.*;
-public class TextViewCompatTest extends ActivityInstrumentationTestCase2<TestActivity> {
+public class TextViewCompatTest extends BaseInstrumentationTestCase<TextViewTestActivity> {
private static final String TAG = "TextViewCompatTest";
private TextView mTextView;
@@ -72,127 +64,75 @@
}
public TextViewCompatTest() {
- super("android.support.v4.widget", TestActivity.class);
+ super(TextViewTestActivity.class);
}
- @Override
- public void tearDown() throws Exception {
- if (mTextView != null) {
- removeTextView();
- }
-
- getInstrumentation().waitForIdleSync();
- super.tearDown();
+ @Before
+ public void setUp() {
+ mTextView = (TextView) mActivityTestRule.getActivity().findViewById(R.id.text_view);
}
- private boolean isMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
-
- private void removeTextView() {
- if (mTextView == null) {
- return;
- }
- if (!isMainThread()) {
- getInstrumentation().waitForIdleSync();
- }
- try {
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- getActivity().mContainer.removeAllViews();
- }
- });
- } catch (Throwable throwable) {
- Log.e(TAG, "", throwable);
- }
- mTextView = null;
- }
-
- private void createAndAddTextView() {
- final TestActivity activity = getActivity();
- mTextView = new TextView(activity);
- activity.mContainer.addView(mTextView);
-
- // Explicitly measure and layout the text view. This way the core TextView updates its
- // internal tracking of various visual facets so those can be tested in the relevant
- // tests - such as, for example, where each drawable is positioned relative to the text.
- final DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
- int textViewWidthPx = TestUtils.convertSizeDipsToPixels(metrics, 200);
- int textViewHeightPx = TestUtils.convertSizeDipsToPixels(metrics, 60);
- mTextView.measure(
- View.MeasureSpec.makeMeasureSpec(textViewWidthPx, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(textViewHeightPx, View.MeasureSpec.EXACTLY));
- mTextView.layout(0, 0, textViewWidthPx, textViewHeightPx);
- }
-
- @UiThreadTest
+ @Test
@SmallTest
public void testMaxLines() throws Throwable {
- createAndAddTextView();
final int maxLinesCount = 4;
- mTextView.setMaxLines(maxLinesCount);
+ onView(withId(R.id.text_view)).perform(setMaxLines(maxLinesCount));
assertEquals("Empty view: Max lines must match", TextViewCompat.getMaxLines(mTextView),
maxLinesCount);
- mTextView.setText(R.string.test_text_short);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_short));
assertEquals("Short text: Max lines must match", TextViewCompat.getMaxLines(mTextView),
maxLinesCount);
- mTextView.setText(R.string.test_text_medium);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_medium));
assertEquals("Medium text: Max lines must match", TextViewCompat.getMaxLines(mTextView),
maxLinesCount);
- mTextView.setText(R.string.test_text_long);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
assertEquals("Long text: Max lines must match", TextViewCompat.getMaxLines(mTextView),
maxLinesCount);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testMinLines() throws Throwable {
- createAndAddTextView();
final int minLinesCount = 3;
- mTextView.setMinLines(minLinesCount);
+ onView(withId(R.id.text_view)).perform(setMinLines(minLinesCount));
assertEquals("Empty view: Min lines must match", TextViewCompat.getMinLines(mTextView),
minLinesCount);
- mTextView.setText(R.string.test_text_short);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_short));
assertEquals("Short text: Min lines must match", TextViewCompat.getMinLines(mTextView),
minLinesCount);
- mTextView.setText(R.string.test_text_medium);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_medium));
assertEquals("Medium text: Min lines must match", TextViewCompat.getMinLines(mTextView),
minLinesCount);
- mTextView.setText(R.string.test_text_long);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
assertEquals("Long text: Min lines must match", TextViewCompat.getMinLines(mTextView),
minLinesCount);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testStyle() throws Throwable {
- createAndAddTextView();
+ onView(withId(R.id.text_view)).perform(setTextAppearance(R.style.TextMediumStyle));
- TextViewCompat.setTextAppearance(mTextView, R.style.TextMediumStyle);
-
- final Resources res = getActivity().getResources();
+ final Resources res = mActivityTestRule.getActivity().getResources();
assertTrue("Styled text view: style",
mTextView.getTypeface().isItalic() || (mTextView.getPaint().getTextSkewX() < 0));
assertEquals("Styled text view: color", mTextView.getTextColors().getDefaultColor(),
res.getColor(R.color.text_color));
assertEquals("Styled text view: size", mTextView.getTextSize(),
- (float) res.getDimensionPixelSize(R.dimen.text_medium_size));
+ (float) res.getDimensionPixelSize(R.dimen.text_medium_size), 1.0f);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testCompoundDrawablesRelative() throws Throwable {
- createAndAddTextView();
-
final Drawable drawableStart = new ColorDrawable(0xFFFF0000);
drawableStart.setBounds(0, 0, 20, 20);
final Drawable drawableTop = new ColorDrawable(0xFF00FF00);
@@ -200,9 +140,9 @@
final Drawable drawableEnd = new ColorDrawable(0xFF0000FF);
drawableEnd.setBounds(0, 0, 25, 20);
- mTextView.setText(R.string.test_text_medium);
- TextViewCompat.setCompoundDrawablesRelative(mTextView, drawableStart, drawableTop,
- drawableEnd, null);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_medium));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelative(drawableStart,
+ drawableTop, drawableEnd, null));
final Drawable[] drawablesAbsolute = mTextView.getCompoundDrawables();
@@ -227,12 +167,10 @@
assertNull("Compound drawable: bottom", drawablesAbsolute[3]);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testCompoundDrawablesRelativeRtl() throws Throwable {
- createAndAddTextView();
-
- ViewCompat.setLayoutDirection(mTextView, ViewCompat.LAYOUT_DIRECTION_RTL);
+ onView(withId(R.id.text_view)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
final Drawable drawableStart = new ColorDrawable(0xFFFF0000);
drawableStart.setBounds(0, 0, 20, 20);
@@ -241,9 +179,9 @@
final Drawable drawableEnd = new ColorDrawable(0xFF0000FF);
drawableEnd.setBounds(0, 0, 25, 20);
- mTextView.setText(R.string.test_text_medium);
- TextViewCompat.setCompoundDrawablesRelative(mTextView, drawableStart, drawableTop,
- drawableEnd, null);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_medium));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelative(drawableStart,
+ drawableTop, drawableEnd, null));
// Check to see whether our text view is under RTL mode
if (ViewCompat.getLayoutDirection(mTextView) != ViewCompat.LAYOUT_DIRECTION_RTL) {
@@ -276,18 +214,16 @@
assertNull("Compound drawable: bottom", drawablesAbsolute[3]);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testCompoundDrawablesRelativeWithIntrinsicBounds() throws Throwable {
- createAndAddTextView();
-
final Drawable drawableStart = new TestDrawable(0xFFFF0000, 30, 20);
final Drawable drawableEnd = new TestDrawable(0xFF0000FF, 25, 45);
final Drawable drawableBottom = new TestDrawable(0xFF00FF00, 15, 35);
- mTextView.setText(R.string.test_text_long);
- TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mTextView, drawableStart,
- null, drawableEnd, drawableBottom);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelativeWithIntrinsicBounds(
+ drawableStart, null, drawableEnd, drawableBottom));
final Drawable[] drawablesAbsolute = mTextView.getCompoundDrawables();
@@ -312,20 +248,18 @@
drawablesAbsolute[3].getBounds().height(), 35);
}
- @UiThreadTest
+ @Test
@SmallTest
public void testCompoundDrawablesRelativeWithIntrinsicBoundsRtl() throws Throwable {
- createAndAddTextView();
-
- ViewCompat.setLayoutDirection(mTextView, ViewCompat.LAYOUT_DIRECTION_RTL);
+ onView(withId(R.id.text_view)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
final Drawable drawableStart = new TestDrawable(0xFFFF0000, 30, 20);
final Drawable drawableEnd = new TestDrawable(0xFF0000FF, 25, 45);
final Drawable drawableBottom = new TestDrawable(0xFF00FF00, 15, 35);
- mTextView.setText(R.string.test_text_long);
- TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mTextView, drawableStart,
- null, drawableEnd, drawableBottom);
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelativeWithIntrinsicBounds(
+ drawableStart, null, drawableEnd, drawableBottom));
// Check to see whether our text view is under RTL mode
if (ViewCompat.getLayoutDirection(mTextView) != ViewCompat.LAYOUT_DIRECTION_RTL) {
@@ -358,18 +292,16 @@
drawablesAbsolute[3].getBounds().height(), 35);
}
- @UiThreadTest
+ @Test
@MediumTest
public void testCompoundDrawablesRelativeWithIntrinsicBoundsById() throws Throwable {
- createAndAddTextView();
-
- mTextView.setText(R.string.test_text_long);
- TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mTextView,
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.test_drawable_red, 0,
- R.drawable.test_drawable_green, R.drawable.test_drawable_blue);
+ R.drawable.test_drawable_green, R.drawable.test_drawable_blue));
final Drawable[] drawablesAbsolute = mTextView.getCompoundDrawables();
- final Resources res = getActivity().getResources();
+ final Resources res = mActivityTestRule.getActivity().getResources();
// The entire left drawable should be the specific red color
TestUtils.assertAllPixelsOfColor("Compound drawable: left color",
@@ -404,17 +336,15 @@
res.getDimensionPixelSize(R.dimen.drawable_small_size));
}
- @UiThreadTest
+ @Test
@MediumTest
public void testCompoundDrawablesRelativeWithIntrinsicBoundsByIdRtl() throws Throwable {
- createAndAddTextView();
+ onView(withId(R.id.text_view)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
- ViewCompat.setLayoutDirection(mTextView, ViewCompat.LAYOUT_DIRECTION_RTL);
-
- mTextView.setText(R.string.test_text_long);
- TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mTextView,
+ onView(withId(R.id.text_view)).perform(setText(R.string.test_text_long));
+ onView(withId(R.id.text_view)).perform(setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.test_drawable_red, 0,
- R.drawable.test_drawable_green, R.drawable.test_drawable_blue);
+ R.drawable.test_drawable_green, R.drawable.test_drawable_blue));
// Check to see whether our text view is under RTL mode
if (ViewCompat.getLayoutDirection(mTextView) != ViewCompat.LAYOUT_DIRECTION_RTL) {
@@ -423,7 +353,7 @@
}
final Drawable[] drawablesAbsolute = mTextView.getCompoundDrawables();
- final Resources res = getActivity().getResources();
+ final Resources res = mActivityTestRule.getActivity().getResources();
// The entire left / end drawable should be the specific green color
TestUtils.assertAllPixelsOfColor("Compound drawable: left color",
diff --git a/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java b/v4/tests/java/android/support/v4/widget/TextViewTestActivity.java
similarity index 68%
rename from v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
rename to v4/tests/java/android/support/v4/widget/TextViewTestActivity.java
index 7366127..dcaab70 100644
--- a/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
+++ b/v4/tests/java/android/support/v4/widget/TextViewTestActivity.java
@@ -14,11 +14,14 @@
* limitations under the License.
*/
-package android.support.v4.widget.test;
+package android.support.v4.widget;
+import android.support.v4.BaseTestActivity;
+import android.support.v4.test.R;
-import android.app.Activity;
-
-public class TextViewTestActivity extends Activity {
-
+public class TextViewTestActivity extends BaseTestActivity {
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.text_view_activity;
+ }
}
diff --git a/v4/tests/res/layout/text_view_activity.xml b/v4/tests/res/layout/text_view_activity.xml
new file mode 100644
index 0000000..ba5d688
--- /dev/null
+++ b/v4/tests/res/layout/text_view_activity.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="200dip"
+ android:layout_height="60dip" />
+</FrameLayout>
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index 8515409..734f46f 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.LayoutRes;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.v4.app.ActivityCompat;
@@ -96,20 +97,20 @@
}
/**
- * Set a {@link android.widget.Toolbar Toolbar} to act as the {@link android.support.v7.app.ActionBar} for this
- * Activity window.
+ * Set a {@link android.widget.Toolbar Toolbar} to act as the
+ * {@link android.support.v7.app.ActionBar} for this Activity window.
*
* <p>When set to a non-null value the {@link #getActionBar()} method will return
- * an {@link android.support.v7.app.ActionBar} object that can be used to control the given toolbar as if it were
- * a traditional window decor action bar. The toolbar's menu will be populated with the
- * Activity's options menu and the navigation button will be wired through the standard
- * {@link android.R.id#home home} menu select action.</p>
+ * an {@link android.support.v7.app.ActionBar} object that can be used to control the given
+ * toolbar as if it were a traditional window decor action bar. The toolbar's menu will be
+ * populated with the Activity's options menu and the navigation button will be wired through
+ * the standard {@link android.R.id#home home} menu select action.</p>
*
* <p>In order to use a Toolbar within the Activity's window content the application
* must not request the window feature
* {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
*
- * @param toolbar Toolbar to set as the Activity's action bar
+ * @param toolbar Toolbar to set as the Activity's action bar, or {@code null} to clear it
*/
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
@@ -221,7 +222,7 @@
* @param mode The new action mode.
*/
@CallSuper
- public void onSupportActionModeStarted(ActionMode mode) {
+ public void onSupportActionModeStarted(@NonNull ActionMode mode) {
}
/**
@@ -231,7 +232,7 @@
* @param mode The action mode that just finished.
*/
@CallSuper
- public void onSupportActionModeFinished(ActionMode mode) {
+ public void onSupportActionModeFinished(@NonNull ActionMode mode) {
}
/**
@@ -245,11 +246,18 @@
*/
@Nullable
@Override
- public ActionMode onWindowStartingSupportActionMode(ActionMode.Callback callback) {
+ public ActionMode onWindowStartingSupportActionMode(@NonNull ActionMode.Callback callback) {
return null;
}
- public ActionMode startSupportActionMode(ActionMode.Callback callback) {
+ /**
+ * Start an action mode.
+ *
+ * @param callback Callback that will manage lifecycle events for this context mode
+ * @return The ContextMode that was started, or null if it was canceled
+ */
+ @Nullable
+ public ActionMode startSupportActionMode(@NonNull ActionMode.Callback callback) {
return getDelegate().startSupportActionMode(callback);
}
@@ -304,7 +312,7 @@
* @param builder An empty TaskStackBuilder - the application should add intents representing
* the desired task stack
*/
- public void onCreateSupportNavigateUpTaskStack(TaskStackBuilder builder) {
+ public void onCreateSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) {
builder.addParentStack(this);
}
@@ -323,7 +331,7 @@
* @param builder A TaskStackBuilder that has been populated with Intents by
* onCreateNavigateUpTaskStack.
*/
- public void onPrepareSupportNavigateUpTaskStack(TaskStackBuilder builder) {
+ public void onPrepareSupportNavigateUpTaskStack(@NonNull TaskStackBuilder builder) {
}
/**
@@ -403,7 +411,7 @@
* @return true if navigating up should recreate a new task stack, false if the same task
* should be used for the destination
*/
- public boolean supportShouldUpRecreateTask(Intent targetIntent) {
+ public boolean supportShouldUpRecreateTask(@NonNull Intent targetIntent) {
return NavUtils.shouldUpRecreateTask(this, targetIntent);
}
@@ -419,7 +427,7 @@
*
* @param upIntent An intent representing the target destination for up navigation
*/
- public void supportNavigateUpTo(Intent upIntent) {
+ public void supportNavigateUpTo(@NonNull Intent upIntent) {
NavUtils.navigateUpTo(this, upIntent);
}
@@ -473,6 +481,7 @@
/**
* @return The {@link AppCompatDelegate} being used by this Activity.
*/
+ @NonNull
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index becfe6c..2f887cc 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -26,6 +26,7 @@
import android.support.annotation.IntDef;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.WindowCompat;
import android.support.v7.appcompat.R;
@@ -187,6 +188,7 @@
*
* @return AppCompat's action bar, or null if it does not have one.
*/
+ @Nullable
public abstract ActionBar getSupportActionBar();
/**
@@ -202,9 +204,9 @@
* must not request the window feature
* {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
*
- * @param toolbar Toolbar to set as the Activity's action bar
+ * @param toolbar Toolbar to set as the Activity's action bar, or {@code null} to clear it
*/
- public abstract void setSupportActionBar(Toolbar toolbar);
+ public abstract void setSupportActionBar(@Nullable Toolbar toolbar);
/**
* Return the value of this call from your {@link Activity#getMenuInflater()}
@@ -271,7 +273,7 @@
/**
* Should be called from {@link Activity#onTitleChanged(CharSequence, int)}}
*/
- public abstract void setTitle(CharSequence title);
+ public abstract void setTitle(@Nullable CharSequence title);
/**
* Should be called from {@link Activity#invalidateOptionsMenu()}} or
@@ -288,6 +290,7 @@
* Returns an {@link ActionBarDrawerToggle.Delegate} which can be returned from your Activity
* if it implements {@link ActionBarDrawerToggle.DelegateProvider}.
*/
+ @Nullable
public abstract ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
/**
@@ -317,7 +320,8 @@
* @param callback Callback that will manage lifecycle events for this context mode
* @return The ContextMode that was started, or null if it was canceled
*/
- public abstract ActionMode startSupportActionMode(ActionMode.Callback callback);
+ @Nullable
+ public abstract ActionMode startSupportActionMode(@NonNull ActionMode.Callback callback);
/**
* Installs AppCompat's {@link android.view.LayoutInflater} Factory so that it can replace
@@ -348,7 +352,7 @@
* {@link android.view.LayoutInflater LayoutInflater} factory, and have therefore not
* installed the default factory via {@link #installViewFactory()}.
*/
- public abstract View createView(View parent, String name, @NonNull Context context,
+ public abstract View createView(@Nullable View parent, String name, @NonNull Context context,
@NonNull AttributeSet attrs);
/**
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index 05c8ec3..cc13909 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -206,11 +206,18 @@
ab.onDestroy();
}
- ToolbarActionBar tbab = new ToolbarActionBar(toolbar, ((Activity) mContext).getTitle(),
- mAppCompatWindowCallback);
- mActionBar = tbab;
- mWindow.setCallback(tbab.getWrappedWindowCallback());
- tbab.invalidateOptionsMenu();
+ if (toolbar != null) {
+ final ToolbarActionBar tbab = new ToolbarActionBar(toolbar,
+ ((Activity) mContext).getTitle(), mAppCompatWindowCallback);
+ mActionBar = tbab;
+ mWindow.setCallback(tbab.getWrappedWindowCallback());
+ } else {
+ mActionBar = null;
+ // Re-set the original window callback since we may have already set a Toolbar wrapper
+ mWindow.setCallback(mAppCompatWindowCallback);
+ }
+
+ invalidateOptionsMenu();
}
@Override
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
index b517fc3..2ae4d64 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
@@ -24,17 +24,20 @@
import android.support.annotation.NonNull;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.graphics.ColorUtils;
+import android.support.v7.app.BaseInstrumentationTestCase;
import android.support.v7.appcompat.test.R;
import android.support.v7.testutils.AppCompatTintableViewActions;
import android.support.v7.testutils.BaseTestActivity;
import android.support.v7.testutils.TestUtils;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.view.ViewGroup;
+import org.junit.Before;
+import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.assertNull;
/**
* Base class for testing custom view extensions in appcompat-v7 that implement the
@@ -43,19 +46,20 @@
* base view class (such as <code>AppCompatTextView</code>'s all-caps support).
*/
public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extends View>
- extends ActivityInstrumentationTestCase2<A> {
+ extends BaseInstrumentationTestCase<A> {
protected ViewGroup mContainer;
+ protected Resources mResources;
+
public AppCompatBaseViewTest(Class clazz) {
super(clazz);
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- final A activity = getActivity();
+ @Before
+ public void setUp() {
+ final A activity = mActivityTestRule.getActivity();
mContainer = (ViewGroup) activity.findViewById(R.id.container);
+ mResources = activity.getResources();
}
private void verifyBackgroundIsColoredAs(String description, @NonNull View view,
@@ -70,10 +74,10 @@
* This method tests that background tinting is not applied when the
* tintable view has no background.
*/
+ @Test
@SmallTest
public void testBackgroundTintingWithNoBackground() {
final @IdRes int viewId = R.id.view_tinted_no_background;
- final Resources res = getActivity().getResources();
final T view = (T) mContainer.findViewById(viewId);
// Note that all the asserts in this test check that the view background
@@ -93,7 +97,7 @@
// Load a new color state list, set it on the view and check that the background
// is still null.
final ColorStateList sandColor = ResourcesCompat.getColorStateList(
- res, R.color.color_state_list_sand, null);
+ mResources, R.color.color_state_list_sand, null);
onView(withId(viewId)).perform(
AppCompatTintableViewActions.setBackgroundTintList(sandColor));
@@ -111,18 +115,24 @@
* in enabled and disabled state across a number of <code>ColorStateList</code>s set as
* background tint lists on the same background.
*/
+ @Test
@SmallTest
public void testBackgroundTintingAcrossStateChange() {
final @IdRes int viewId = R.id.view_tinted_background;
- final Resources res = getActivity().getResources();
final T view = (T) mContainer.findViewById(viewId);
- @ColorInt int lilacDefault = ResourcesCompat.getColor(res, R.color.lilac_default, null);
- @ColorInt int lilacDisabled = ResourcesCompat.getColor(res, R.color.lilac_disabled, null);
- @ColorInt int sandDefault = ResourcesCompat.getColor(res, R.color.sand_default, null);
- @ColorInt int sandDisabled = ResourcesCompat.getColor(res, R.color.sand_disabled, null);
- @ColorInt int oceanDefault = ResourcesCompat.getColor(res, R.color.ocean_default, null);
- @ColorInt int oceanDisabled = ResourcesCompat.getColor(res, R.color.ocean_disabled, null);
+ final @ColorInt int lilacDefault = ResourcesCompat.getColor(
+ mResources, R.color.lilac_default, null);
+ final @ColorInt int lilacDisabled = ResourcesCompat.getColor(
+ mResources, R.color.lilac_disabled, null);
+ final @ColorInt int sandDefault = ResourcesCompat.getColor(
+ mResources, R.color.sand_default, null);
+ final @ColorInt int sandDisabled = ResourcesCompat.getColor(
+ mResources, R.color.sand_disabled, null);
+ final @ColorInt int oceanDefault = ResourcesCompat.getColor(
+ mResources, R.color.ocean_default, null);
+ final @ColorInt int oceanDisabled = ResourcesCompat.getColor(
+ mResources, R.color.ocean_disabled, null);
// Test the default state for tinting set up in the layout XML file.
verifyBackgroundIsColoredAs("Default lilac tinting in enabled state", view,
@@ -143,7 +153,7 @@
// Load a new color state list, set it on the view and check that the background has
// switched to the matching entry in newly set color state list.
final ColorStateList sandColor = ResourcesCompat.getColorStateList(
- res, R.color.color_state_list_sand, null);
+ mResources, R.color.color_state_list_sand, null);
onView(withId(viewId)).perform(
AppCompatTintableViewActions.setBackgroundTintList(sandColor));
verifyBackgroundIsColoredAs("New sand tinting in enabled state", view,
@@ -164,7 +174,7 @@
// Load another color state list, set it on the view and check that the background has
// switched to the matching entry in newly set color state list.
final ColorStateList oceanColor = ResourcesCompat.getColorStateList(
- res, R.color.color_state_list_ocean, null);
+ mResources, R.color.color_state_list_ocean, null);
onView(withId(viewId)).perform(
AppCompatTintableViewActions.setBackgroundTintList(oceanColor));
verifyBackgroundIsColoredAs("New ocean tinting in enabled state", view,
@@ -188,20 +198,20 @@
* in enabled and disabled state across the same background respects the currently set
* background tinting mode.
*/
+ @Test
@SmallTest
public void testBackgroundTintingAcrossModeChange() {
final @IdRes int viewId = R.id.view_untinted_background;
- final Resources res = getActivity().getResources();
final T view = (T) mContainer.findViewById(viewId);
- @ColorInt int emeraldDefault = ResourcesCompat.getColor(
- res, R.color.emerald_translucent_default, null);
- @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
- res, R.color.emerald_translucent_disabled, null);
+ final @ColorInt int emeraldDefault = ResourcesCompat.getColor(
+ mResources, R.color.emerald_translucent_default, null);
+ final @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
+ mResources, R.color.emerald_translucent_disabled, null);
// This is the fill color of R.drawable.test_background_green set on our view
// that we'll be testing in this method
- @ColorInt int backgroundColor = ResourcesCompat.getColor(
- res, R.color.test_green, null);
+ final @ColorInt int backgroundColor = ResourcesCompat.getColor(
+ mResources, R.color.test_green, null);
// Test the default state for tinting set up in the layout XML file.
verifyBackgroundIsColoredAs("Default no tinting in enabled state", view,
@@ -221,7 +231,7 @@
// Load a new color state list, set it on the view and check that the background has
// switched to the matching entry in newly set color state list.
final ColorStateList emeraldColor = ResourcesCompat.getColorStateList(
- res, R.color.color_state_list_emerald_translucent, null);
+ mResources, R.color.color_state_list_emerald_translucent, null);
onView(withId(viewId)).perform(
AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_in", view,
@@ -259,20 +269,22 @@
* This method tests that opaque background tinting applied to tintable view
* is applied correctly after changing the background itself of the view.
*/
+ @Test
@SmallTest
public void testBackgroundOpaqueTintingAcrossBackgroundChange() {
final @IdRes int viewId = R.id.view_tinted_no_background;
- final Resources res = getActivity().getResources();
final T view = (T) mContainer.findViewById(viewId);
- @ColorInt int lilacDefault = ResourcesCompat.getColor(res, R.color.lilac_default, null);
- @ColorInt int lilacDisabled = ResourcesCompat.getColor(res, R.color.lilac_disabled, null);
+ final @ColorInt int lilacDefault = ResourcesCompat.getColor(
+ mResources, R.color.lilac_default, null);
+ final @ColorInt int lilacDisabled = ResourcesCompat.getColor(
+ mResources, R.color.lilac_disabled, null);
assertNull("No background after XML loading", view.getBackground());
// Set background on our view
onView(withId(viewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
- ResourcesCompat.getDrawable(res, R.drawable.test_background_green, null)));
+ ResourcesCompat.getDrawable(mResources, R.drawable.test_background_green, null)));
// Test the default state for tinting set up in the layout XML file.
verifyBackgroundIsColoredAs("Default lilac tinting in enabled state on green background",
@@ -315,22 +327,22 @@
* This method tests that translucent background tinting applied to tintable view
* is applied correctly after changing the background itself of the view.
*/
+ @Test
@SmallTest
public void testBackgroundTranslucentTintingAcrossBackgroundChange() {
final @IdRes int viewId = R.id.view_untinted_no_background;
- final Resources res = getActivity().getResources();
final T view = (T) mContainer.findViewById(viewId);
- @ColorInt int emeraldDefault = ResourcesCompat.getColor(
- res, R.color.emerald_translucent_default, null);
- @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
- res, R.color.emerald_translucent_disabled, null);
+ final @ColorInt int emeraldDefault = ResourcesCompat.getColor(
+ mResources, R.color.emerald_translucent_default, null);
+ final @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
+ mResources, R.color.emerald_translucent_disabled, null);
// This is the fill color of R.drawable.test_background_green set on our view
// that we'll be testing in this method
- @ColorInt int backgroundColorGreen = ResourcesCompat.getColor(
- res, R.color.test_green, null);
- @ColorInt int backgroundColorRed = ResourcesCompat.getColor(
- res, R.color.test_red, null);
+ final @ColorInt int backgroundColorGreen = ResourcesCompat.getColor(
+ mResources, R.color.test_green, null);
+ final @ColorInt int backgroundColorRed = ResourcesCompat.getColor(
+ mResources, R.color.test_red, null);
assertNull("No background after XML loading", view.getBackground());
@@ -342,13 +354,13 @@
AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
// Load and set a translucent color state list as the background tint list
final ColorStateList emeraldColor = ResourcesCompat.getColorStateList(
- res, R.color.color_state_list_emerald_translucent, null);
+ mResources, R.color.color_state_list_emerald_translucent, null);
onView(withId(viewId)).perform(
AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
// Set background on our view
onView(withId(viewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
- ResourcesCompat.getDrawable(res, R.drawable.test_background_green, null)));
+ ResourcesCompat.getDrawable(mResources, R.drawable.test_background_green, null)));
// From this point on in this method we're allowing a margin of error in checking the
// color of the view background. This is due to both translucent colors being used
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
index d2abe95..8d6233d 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
@@ -15,14 +15,6 @@
*/
package android.support.v7.widget;
-import android.content.res.Resources;
-import android.support.v7.appcompat.test.R;
-import android.support.v7.testutils.AppCompatTextViewActions;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
/**
* In addition to all tinting-related tests done by the base class, this class provides
* tests specific to <code>AppCompatImageView</code> class.
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
index 6448e7d..e2c6edf 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
@@ -15,13 +15,14 @@
*/
package android.support.v7.widget;
-import android.content.res.Resources;
import android.support.v7.appcompat.test.R;
import android.support.v7.testutils.AppCompatTextViewActions;
import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.assertEquals;
/**
* In addition to all tinting-related tests done by the base class, this class provides
@@ -33,11 +34,11 @@
super(AppCompatTextViewActivity.class);
}
+ @Test
@SmallTest
public void testAllCaps() throws Throwable {
- final Resources res = getActivity().getResources();
- final String text1 = res.getString(R.string.sample_text1);
- final String text2 = res.getString(R.string.sample_text2);
+ final String text1 = mResources.getString(R.string.sample_text1);
+ final String text2 = mResources.getString(R.string.sample_text2);
final AppCompatTextView textView1 =
(AppCompatTextView) mContainer.findViewById(R.id.text_view_caps1);
diff --git a/v7/mediarouter/api/current.txt b/v7/mediarouter/api/current.txt
index d082642..75b0fce 100644
--- a/v7/mediarouter/api/current.txt
+++ b/v7/mediarouter/api/current.txt
@@ -565,6 +565,7 @@
method public void onRouteRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
method public void onRouteSelected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo, int);
method public void onRouteVolumeChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
}
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index 8926e53..20d784f 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -78,12 +78,14 @@
/**
* Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
- * when the reason the route was unselected is unknown.
+ * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the reason the route
+ * was unselected is unknown.
*/
public static final int UNSELECT_REASON_UNKNOWN = 0;
/**
* Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
- * when the user pressed the disconnect button to disconnect and keep playing.
+ * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
+ * the disconnect button to disconnect and keep playing.
* <p>
*
* @see {@link MediaRouteDescriptor#canDisconnectAndKeepPlaying()}.
@@ -91,12 +93,14 @@
public static final int UNSELECT_REASON_DISCONNECTED = 1;
/**
* Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
- * when the user pressed the stop casting button.
+ * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
+ * the stop casting button.
*/
public static final int UNSELECT_REASON_STOPPED = 2;
/**
* Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
- * when the user selected a different route.
+ * and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user selected
+ * a different route.
*/
public static final int UNSELECT_REASON_ROUTE_CHANGED = 3;
@@ -1712,6 +1716,8 @@
/**
* Called when the supplied media route becomes unselected as the active route.
+ * For detailed reason, override {@link #onRouteUnselected(MediaRouter, RouteInfo, int)}
+ * instead.
*
* @param router The media router reporting the event.
* @param route The route that has been unselected.
@@ -1720,6 +1726,26 @@
}
/**
+ * Called when the supplied media route becomes unselected as the active route.
+ * The default implementation calls {@link #onRouteUnselected}.
+ * <p>
+ * The reason provided will be one of the following:
+ * <ul>
+ * <li>{@link MediaRouter#UNSELECT_REASON_UNKNOWN}</li>
+ * <li>{@link MediaRouter#UNSELECT_REASON_DISCONNECTED}</li>
+ * <li>{@link MediaRouter#UNSELECT_REASON_STOPPED}</li>
+ * <li>{@link MediaRouter#UNSELECT_REASON_ROUTE_CHANGED}</li>
+ * </ul>
+ *
+ * @param router The media router reporting the event.
+ * @param route The route that has been unselected.
+ * @param reason The reason for unselecting the route.
+ */
+ public void onRouteUnselected(MediaRouter router, RouteInfo route, int reason) {
+ onRouteUnselected(router, route);
+ }
+
+ /**
* Called when a media route has been added.
*
* @param router The media router reporting the event.
@@ -2444,7 +2470,8 @@
Log.d(TAG, "Route unselected: " + mSelectedRoute + " reason: "
+ unselectReason);
}
- mCallbackHandler.post(CallbackHandler.MSG_ROUTE_UNSELECTED, mSelectedRoute);
+ mCallbackHandler.post(CallbackHandler.MSG_ROUTE_UNSELECTED, mSelectedRoute,
+ unselectReason);
if (mSelectedRouteController != null) {
mSelectedRouteController.onUnselect(unselectReason);
mSelectedRouteController.onRelease();
@@ -2733,10 +2760,17 @@
obtainMessage(msg, obj).sendToTarget();
}
+ public void post(int msg, Object obj, int arg) {
+ Message message = obtainMessage(msg, obj);
+ message.arg1 = arg;
+ message.sendToTarget();
+ }
+
@Override
public void handleMessage(Message msg) {
final int what = msg.what;
final Object obj = msg.obj;
+ final int arg = msg.arg1;
// Synchronize state with the system media router.
syncWithSystemProvider(what, obj);
@@ -2756,7 +2790,7 @@
final int callbackCount = mTempCallbackRecords.size();
for (int i = 0; i < callbackCount; i++) {
- invokeCallback(mTempCallbackRecords.get(i), what, obj);
+ invokeCallback(mTempCallbackRecords.get(i), what, obj, arg);
}
} finally {
mTempCallbackRecords.clear();
@@ -2780,7 +2814,7 @@
}
}
- private void invokeCallback(CallbackRecord record, int what, Object obj) {
+ private void invokeCallback(CallbackRecord record, int what, Object obj, int arg) {
final MediaRouter router = record.mRouter;
final MediaRouter.Callback callback = record.mCallback;
switch (what & MSG_TYPE_MASK) {
@@ -2809,7 +2843,7 @@
callback.onRouteSelected(router, route);
break;
case MSG_ROUTE_UNSELECTED:
- callback.onRouteUnselected(router, route);
+ callback.onRouteUnselected(router, route, arg);
break;
}
break;