Merge "More tests for background tinting of AppCompatTextView" into mnc-ub-dev
diff --git a/v7/appcompat/tests/res/color/color_state_list_emerald_translucent.xml b/v7/appcompat/tests/res/color/color_state_list_emerald_translucent.xml
new file mode 100644
index 0000000..56fd16a
--- /dev/null
+++ b/v7/appcompat/tests/res/color/color_state_list_emerald_translucent.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/emerald_translucent_disabled" />
+    <item android:color="@color/emerald_translucent_default"/>
+</selector>
+
diff --git a/v7/appcompat/tests/res/drawable-mdpi/test_drawable.png b/v7/appcompat/tests/res/drawable-mdpi/test_drawable.png
index 1ce5321..c66ad10 100644
--- a/v7/appcompat/tests/res/drawable-mdpi/test_drawable.png
+++ b/v7/appcompat/tests/res/drawable-mdpi/test_drawable.png
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/test_background_blue.xml b/v7/appcompat/tests/res/drawable/test_background_blue.xml
new file mode 100644
index 0000000..fe4bca2
--- /dev/null
+++ b/v7/appcompat/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/v7/appcompat/tests/res/drawable/test_background_green.xml b/v7/appcompat/tests/res/drawable/test_background_green.xml
new file mode 100644
index 0000000..b90d9bc
--- /dev/null
+++ b/v7/appcompat/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/v7/appcompat/tests/res/drawable/test_background_red.xml b/v7/appcompat/tests/res/drawable/test_background_red.xml
new file mode 100644
index 0000000..87d808b
--- /dev/null
+++ b/v7/appcompat/tests/res/drawable/test_background_red.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_red" />
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml b/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
index c621d0b..a7b33e6 100644
--- a/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
+++ b/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
@@ -40,7 +40,7 @@
             android:text="@string/sample_text2" />
 
         <android.support.v7.widget.AppCompatTextView
-            android:id="@+id/text_view_no_background"
+            android:id="@+id/text_view_tinted_no_background"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="@string/sample_text1"
@@ -48,13 +48,26 @@
             app:backgroundTintMode="src_in" />
 
         <android.support.v7.widget.AppCompatTextView
-            android:id="@+id/text_view_tinted"
+            android:id="@+id/text_view_tinted_background"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="@string/sample_text2"
             android:background="@drawable/test_drawable"
             app:backgroundTint="@color/color_state_list_lilac"
             app:backgroundTintMode="src_in" />
+
+        <android.support.v7.widget.AppCompatTextView
+            android:id="@+id/text_view_untinted_no_background"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/sample_text2" />
+
+        <android.support.v7.widget.AppCompatTextView
+            android:id="@+id/text_view_untinted_background"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/sample_text2"
+            android:background="@drawable/test_background_green" />
     </LinearLayout>
 
 </ScrollView>
diff --git a/v7/appcompat/tests/res/values/colors.xml b/v7/appcompat/tests/res/values/colors.xml
index 7f13157..eaf38da 100644
--- a/v7/appcompat/tests/res/values/colors.xml
+++ b/v7/appcompat/tests/res/values/colors.xml
@@ -27,4 +27,7 @@
     <color name="sand_disabled">#FFC080</color>
     <color name="ocean_default">#50C0FF</color>
     <color name="ocean_disabled">#90F0FF</color>
+
+    <color name="emerald_translucent_default">#8020A060</color>
+    <color name="emerald_translucent_disabled">#8070C090</color>
 </resources>
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
index 769875e..8f86796 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
@@ -17,6 +17,9 @@
 package android.support.v7.testutils;
 
 import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
 import android.support.v4.view.TintableBackgroundView;
@@ -83,4 +86,87 @@
             }
         };
     }
+
+    /**
+     * Sets the passed mode as the background tint mode on a <code>View</code> that
+     * implements the <code>TintableBackgroundView</code> interface.
+     */
+    public static ViewAction setBackgroundTintMode(final PorterDuff.Mode tintMode) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return allOf(isDisplayingAtLeast(90), TestUtilsMatchers.isTintableBackgroundView());
+            }
+
+            @Override
+            public String getDescription() {
+                return "set background tint mode";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                TintableBackgroundView tintableBackgroundView = (TintableBackgroundView) view;
+                tintableBackgroundView.setSupportBackgroundTintMode(tintMode);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    /**
+     * Sets background drawable on a <code>View</code> that implements the
+     * <code>TintableBackgroundView</code> interface.
+     */
+    public static ViewAction setBackgroundDrawable(final Drawable background) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return allOf(TestUtilsMatchers.isTintableBackgroundView());
+            }
+
+            @Override
+            public String getDescription() {
+                return "set background drawable";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                view.setBackgroundDrawable(background);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    /**
+     * Sets background resource on a <code>View</code> that implements the
+     * <code>TintableBackgroundView</code> interface.
+     */
+    public static ViewAction setBackgroundResource(final @DrawableRes int resId) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return allOf(TestUtilsMatchers.isTintableBackgroundView());
+            }
+
+            @Override
+            public String getDescription() {
+                return "set background resource";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                view.setBackgroundResource(resId);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
index c366381..ae8e681 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
@@ -36,7 +36,7 @@
      */
     public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
             int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
-            boolean throwExceptionIfFails) {
+            int allowedComponentVariance, boolean throwExceptionIfFails) {
         // Create a bitmap
         Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
         // Create a canvas that wraps the bitmap
@@ -53,15 +53,34 @@
             for (int row = 0; row < drawableHeight; row++) {
                 bitmap.getPixels(rowPixels, 0, drawableWidth, 0, row, drawableWidth, 1);
                 for (int column = 0; column < drawableWidth; column++) {
-                    if (rowPixels[column] != color) {
+                    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 ["
-                                + Color.red(color) + "," + Color.green(color) + ","
-                                + Color.blue(color)
+                                + expectedAlpha + "," + expectedRed + ","
+                                + expectedGreen + "," + expectedBlue
                                 + "] but at position (" + row + "," + column + ") found ["
-                                + Color.red(rowPixels[column]) + ","
-                                + Color.green(rowPixels[column]) + ","
-                                + Color.blue(rowPixels[column]) + "]";
+                                + sourceAlpha + "," + sourceRed + ","
+                                + sourceGreen + "," + sourceBlue + "]";
                         if (throwExceptionIfFails) {
                             throw new RuntimeException(mismatchDescription);
                         } else {
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
index 5a4bb4a..cab4518 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
@@ -58,7 +58,7 @@
                 // all pixels in a Drawable are of the same specified color.
                 try {
                     TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
-                            view.getHeight(), true, color, true);
+                            view.getHeight(), true, color, 0, true);
                     // If we are here, the color comparison has passed.
                     failedComparisonDescription = null;
                     return true;
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 cd92e6a..d31ce90 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
@@ -17,11 +17,13 @@
 
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
-import android.graphics.Rect;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
+import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
 import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.graphics.ColorUtils;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.AppCompatTextViewActions;
 import android.support.v7.testutils.AppCompatTintableViewActions;
@@ -83,18 +85,23 @@
     }
 
     private void verifyBackgroundIsColoredAs(String description,
-            @NonNull AppCompatTextView textView, @ColorInt int color) {
-        final Drawable background = textView.getBackground();
-        final Rect backgroundBounds = background.getBounds();
+            @NonNull AppCompatTextView textView, @ColorInt int color,
+            int allowedComponentVariance) {
+        Drawable background = textView.getBackground();
         TestUtils.assertAllPixelsOfColor(description,
-                background, backgroundBounds.width(), backgroundBounds.height(), false,
-                color, false);
+                background, textView.getWidth(), textView.getHeight(), true,
+                color, allowedComponentVariance, false);
     }
 
+    /**
+     * This method tests that background tinting is not applied when the
+     * <code>AppCompatTextView</code> has no background.
+     */
     @SmallTest
     public void testBackgroundTintingWithNoBackground() {
+        final @IdRes int textViewId = R.id.text_view_tinted_no_background;
         final AppCompatTextView textView =
-                (AppCompatTextView) mContainer.findViewById(R.id.text_view_no_background);
+                (AppCompatTextView) mContainer.findViewById(textViewId);
 
         // Note that all the asserts in this test check that the AppCompatTextView background
         // is null. This is because the matching child in the activity doesn't define any
@@ -103,12 +110,12 @@
         assertNull("No background after XML loading", textView.getBackground());
 
         // Disable the text view and check that the background is still null.
-        onView(withId(R.id.text_view_tinted)).perform(
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setEnabled(false));
         assertNull("No background after disabling", textView.getBackground());
 
         // Enable the text view and check that the background is still null.
-        onView(withId(R.id.text_view_tinted)).perform(
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setEnabled(true));
         assertNull("No background after re-enabling", textView.getBackground());
 
@@ -116,22 +123,28 @@
         // is still null.
         final ColorStateList sandColor = ResourcesCompat.getColorStateList(
                 getActivity().getResources(), R.color.color_state_list_sand, null);
-        onView(withId(R.id.text_view_tinted)).perform(
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setBackgroundTintList(sandColor));
 
         // Disable the text view and check that the background is still null.
-        onView(withId(R.id.text_view_tinted)).perform(
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setEnabled(false));
         assertNull("No background after disabling", textView.getBackground());
 
         // Enable the text view and check that the background is still null.
-        onView(withId(R.id.text_view_tinted)).perform(
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setEnabled(true));
         assertNull("No background after re-enabling", textView.getBackground());
     }
 
+    /**
+     * This method tests that background tinting is applied to <code>AppCompatTextView</code>
+     * in enabled and disabled state across a number of <code>ColorStateList</code>s set as
+     * background tint lists on the same background.
+     */
     @SmallTest
-    public void testBackgroundTinting() {
+    public void testBackgroundTintingAcrossStateChange() {
+        final @IdRes int textViewId = R.id.text_view_tinted_background;
         final Resources res = getActivity().getResources();
 
         @ColorInt int lilacDefault = ResourcesCompat.getColor(res, R.color.lilac_default, null);
@@ -141,71 +154,281 @@
         @ColorInt int oceanDefault = ResourcesCompat.getColor(res, R.color.ocean_default, null);
         @ColorInt int oceanDisabled = ResourcesCompat.getColor(res, R.color.ocean_disabled, null);
 
-        final AppCompatTextView textViewTinted =
-                (AppCompatTextView) mContainer.findViewById(R.id.text_view_tinted);
+        final AppCompatTextView textView =
+                (AppCompatTextView) mContainer.findViewById(textViewId);
 
-        // Test the default state from tinting set up in the layout XML file.
-        verifyBackgroundIsColoredAs("Default lilac tinting in enabled state", textViewTinted,
-                lilacDefault);
+        // Test the default state for tinting set up in the layout XML file.
+        verifyBackgroundIsColoredAs("Default lilac tinting in enabled state", textView,
+                lilacDefault, 0);
 
         // Disable the text view and check that the background has switched to the matching entry
         // in the default color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(false));
-        verifyBackgroundIsColoredAs("Default lilac tinting in disabled state", textViewTinted,
-                lilacDisabled);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("Default lilac tinting in disabled state", textView,
+                lilacDisabled, 0);
 
         // Enable the text view and check that the background has switched to the matching entry
         // in the default color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(true));
-        verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state", textViewTinted,
-                lilacDefault);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state", textView,
+                lilacDefault, 0);
 
         // Load a new color state list, set it on the text view and check that the background has
         // switched to the matching entry in newly set color state list.
         final ColorStateList sandColor = ResourcesCompat.getColorStateList(
-                getActivity().getResources(), R.color.color_state_list_sand, null);
-        onView(withId(R.id.text_view_tinted)).perform(
+                res, R.color.color_state_list_sand, null);
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setBackgroundTintList(sandColor));
-        verifyBackgroundIsColoredAs("New sand tinting in enabled state", textViewTinted,
-                sandDefault);
+        verifyBackgroundIsColoredAs("New sand tinting in enabled state", textView,
+                sandDefault, 0);
 
         // Disable the text view and check that the background has switched to the matching entry
         // in the newly set color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(false));
-        verifyBackgroundIsColoredAs("New sand tinting in disabled state", textViewTinted,
-                sandDisabled);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("New sand tinting in disabled state", textView,
+                sandDisabled, 0);
 
         // Enable the text view and check that the background has switched to the matching entry
         // in the newly set color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(true));
-        verifyBackgroundIsColoredAs("New sand tinting in re-enabled state", textViewTinted,
-                sandDefault);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("New sand tinting in re-enabled state", textView,
+                sandDefault, 0);
 
         // Load another color state list, set it on the text view and check that the background has
         // switched to the matching entry in newly set color state list.
         final ColorStateList oceanColor = ResourcesCompat.getColorStateList(
-                getActivity().getResources(), R.color.color_state_list_ocean, null);
-        onView(withId(R.id.text_view_tinted)).perform(
+                res, R.color.color_state_list_ocean, null);
+        onView(withId(textViewId)).perform(
                 AppCompatTintableViewActions.setBackgroundTintList(oceanColor));
-        verifyBackgroundIsColoredAs("New ocean tinting in enabled state", textViewTinted,
-                oceanDefault);
+        verifyBackgroundIsColoredAs("New ocean tinting in enabled state", textView,
+                oceanDefault, 0);
 
         // Disable the text view and check that the background has switched to the matching entry
         // in the newly set color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(false));
-        verifyBackgroundIsColoredAs("New ocean tinting in disabled state", textViewTinted,
-                oceanDisabled);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("New ocean tinting in disabled state", textView,
+                oceanDisabled, 0);
 
         // Enable the text view and check that the background has switched to the matching entry
         // in the newly set color state list.
-        onView(withId(R.id.text_view_tinted)).perform(
-                AppCompatTintableViewActions.setEnabled(true));
-        verifyBackgroundIsColoredAs("New ocean tinting in re-enabled state", textViewTinted,
-                oceanDefault);
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("New ocean tinting in re-enabled state", textView,
+                oceanDefault, 0);
+    }
+
+    /**
+     * This method tests that background tinting applied to <code>AppCompatTextView</code>
+     * in enabled and disabled state across the same background respects the currently set
+     * background tinting mode.
+     */
+    @SmallTest
+    public void testBackgroundTintingAcrossModeChange() {
+        final @IdRes int textViewId = R.id.text_view_untinted_background;
+        final Resources res = getActivity().getResources();
+
+        @ColorInt int emeraldDefault = ResourcesCompat.getColor(
+                res, R.color.emerald_translucent_default, null);
+        @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
+                res, R.color.emerald_translucent_disabled, null);
+        // This is the fill color of R.drawable.test_background_green set on our text view
+        // that we'll be testing in this method
+        @ColorInt int backgroundColor = ResourcesCompat.getColor(
+                res, R.color.test_green, null);
+
+        final AppCompatTextView textView =
+                (AppCompatTextView) mContainer.findViewById(textViewId);
+
+        // Test the default state for tinting set up in the layout XML file.
+        verifyBackgroundIsColoredAs("Default no tinting in enabled state", textView,
+                backgroundColor, 0);
+
+        // From this point on in this method we're allowing a margin of error in checking the
+        // color of the text view background. This is due to both translucent colors being used
+        // in the color state list and off-by-one discrepancies of SRC_OVER when it's compositing
+        // translucent color on top of solid fill color. This is where the allowed variance
+        // value of 2 comes from - one for compositing and one for color translucency.
+        final int allowedComponentVariance = 2;
+
+        // Set src_in tint mode on our text view
+        onView(withId(textViewId)).perform(
+                AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_IN));
+
+        // Load a new color state list, set it on the text 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);
+        onView(withId(textViewId)).perform(
+                AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
+        verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_in", textView,
+                emeraldDefault, allowedComponentVariance);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in the newly set color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_in", textView,
+                emeraldDisabled, allowedComponentVariance);
+
+        // Set src_over tint mode on our text view. As the currently set tint list is using
+        // translucent colors, we expect the actual background of the view to be different under
+        // this new mode (unlike src_in and src_over that behave identically when the destination is
+        // a fully filled rectangle and the source is an opaque color).
+        onView(withId(textViewId)).perform(
+                AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
+
+        // Enable the text view and check that the background has switched to the matching entry
+        // in the color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_over", textView,
+                ColorUtils.compositeColors(emeraldDefault, backgroundColor),
+                allowedComponentVariance);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in the newly set color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_over",
+                textView, ColorUtils.compositeColors(emeraldDisabled, backgroundColor),
+                allowedComponentVariance);
+    }
+
+    /**
+     * This method tests that opaque background tinting applied to <code>AppCompatTextView</code>
+     * is applied correctly after changing the background itself of the view.
+     */
+    @SmallTest
+    public void testBackgroundOpaqueTintingAcrossBackgroundChange() {
+        final @IdRes int textViewId = R.id.text_view_tinted_no_background;
+        final Resources res = getActivity().getResources();
+
+        @ColorInt int lilacDefault = ResourcesCompat.getColor(res, R.color.lilac_default, null);
+        @ColorInt int lilacDisabled = ResourcesCompat.getColor(res, R.color.lilac_disabled, null);
+
+        final AppCompatTextView textView =
+                (AppCompatTextView) mContainer.findViewById(textViewId);
+
+        assertNull("No background after XML loading", textView.getBackground());
+
+        // Set background on our text view
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
+                ResourcesCompat.getDrawable(res, 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 BG",
+                textView, lilacDefault, 0);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("Default lilac tinting in disabled state on green BG",
+                textView, lilacDisabled, 0);
+
+        // Enable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state on green BG",
+                textView, lilacDefault, 0);
+
+        // Set a different background on our view based on resource ID
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setBackgroundResource(
+                R.drawable.test_background_red));
+
+        // Test the default state for tinting set up in the layout XML file.
+        verifyBackgroundIsColoredAs("Default lilac tinting in enabled state on red BG",
+                textView, lilacDefault, 0);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("Default lilac tinting in disabled state on red BG",
+                textView, lilacDisabled, 0);
+
+        // Enable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state on red BG",
+                textView, lilacDefault, 0);
+    }
+
+    /**
+     * This method tests that translucent background tinting applied to <code>AppCompatTextView</code>
+     * is applied correctly after changing the background itself of the view.
+     */
+    @SmallTest
+    public void testBackgroundTranslucentTintingAcrossBackgroundChange() {
+        final @IdRes int textViewId = R.id.text_view_untinted_no_background;
+        final Resources res = getActivity().getResources();
+
+        @ColorInt int emeraldDefault = ResourcesCompat.getColor(
+                res, R.color.emerald_translucent_default, null);
+        @ColorInt int emeraldDisabled = ResourcesCompat.getColor(
+                res, R.color.emerald_translucent_disabled, null);
+        // This is the fill color of R.drawable.test_background_green set on our text 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 AppCompatTextView textView =
+                (AppCompatTextView) mContainer.findViewById(textViewId);
+
+        assertNull("No background after XML loading", textView.getBackground());
+
+        // Set src_over tint mode on our text view. As the currently set tint list is using
+        // translucent colors, we expect the actual background of the view to be different under
+        // this new mode (unlike src_in and src_over that behave identically when the destination is
+        // a fully filled rectangle and the source is an opaque color).
+        onView(withId(textViewId)).perform(
+                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);
+        onView(withId(textViewId)).perform(
+                AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
+
+        // Set background on our text view
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
+                ResourcesCompat.getDrawable(res, 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 text view background. This is due to both translucent colors being used
+        // in the color state list and off-by-one discrepancies of SRC_OVER when it's compositing
+        // translucent color on top of solid fill color. This is where the allowed variance
+        // value of 2 comes from - one for compositing and one for color translucency.
+
+        // Test the default state for tinting set up with the just loaded tint list.
+        verifyBackgroundIsColoredAs("Emerald tinting in enabled state on green BG",
+                textView, ColorUtils.compositeColors(emeraldDefault, backgroundColorGreen), 2);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("Emerald tinting in disabled state on green BG",
+                textView, ColorUtils.compositeColors(emeraldDisabled, backgroundColorGreen), 2);
+
+        // Enable the text view and check that the background has switched to the matching entry
+        // in the default color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("Emerald tinting in re-enabled state on green BG",
+                textView, ColorUtils.compositeColors(emeraldDefault, backgroundColorGreen), 2);
+
+        // Set a different background on our view based on resource ID
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setBackgroundResource(
+                R.drawable.test_background_red));
+
+        // Test the default state for tinting the new background with the same color state list
+        verifyBackgroundIsColoredAs("Emerald tinting in enabled state on red BG",
+                textView, ColorUtils.compositeColors(emeraldDefault, backgroundColorRed), 2);
+
+        // Disable the text view and check that the background has switched to the matching entry
+        // in our current color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+        verifyBackgroundIsColoredAs("Emerald tinting in disabled state on red BG",
+                textView, ColorUtils.compositeColors(emeraldDisabled, backgroundColorRed), 2);
+
+        // Enable the text view and check that the background has switched to the matching entry
+        // in our current color state list.
+        onView(withId(textViewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+        verifyBackgroundIsColoredAs("Emerald tinting in re-enabled state on red BG",
+                textView, ColorUtils.compositeColors(emeraldDefault, backgroundColorRed), 2);
     }
 }