Add AppCompatImageButton + AppCompatImageView

Moved usage of the old ImageView impl to be
implicit through our view inflater functionality.

Also re-ordered the view order so that more common
views are at the top.

BUG: 21715295

Change-Id: I28eedbc1f7d0bd55fbfbdb5aa85b72a8498f790f
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index f8c7754..f0e90e1 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -436,6 +436,7 @@
     field public static int homeLayout;
     field public static int icon;
     field public static int iconifiedByDefault;
+    field public static int imageButtonStyle;
     field public static int indeterminateProgressStyle;
     field public static int initialActivityCount;
     field public static int isLightTheme;
@@ -1066,6 +1067,7 @@
     field public static int Base_Widget_AppCompat_DrawerArrowToggle_Common;
     field public static int Base_Widget_AppCompat_DropDownItem_Spinner;
     field public static int Base_Widget_AppCompat_EditText;
+    field public static int Base_Widget_AppCompat_ImageButton;
     field public static int Base_Widget_AppCompat_Light_ActionBar;
     field public static int Base_Widget_AppCompat_Light_ActionBar_Solid;
     field public static int Base_Widget_AppCompat_Light_ActionBar_TabBar;
@@ -1211,6 +1213,7 @@
     field public static int Widget_AppCompat_DrawerArrowToggle;
     field public static int Widget_AppCompat_DropDownItem_Spinner;
     field public static int Widget_AppCompat_EditText;
+    field public static int Widget_AppCompat_ImageButton;
     field public static int Widget_AppCompat_Light_ActionBar;
     field public static int Widget_AppCompat_Light_ActionBar_Solid;
     field public static int Widget_AppCompat_Light_ActionBar_Solid_Inverse;
@@ -1493,6 +1496,7 @@
     field public static int Theme_editTextColor;
     field public static int Theme_editTextStyle;
     field public static int Theme_homeAsUpIndicator;
+    field public static int Theme_imageButtonStyle;
     field public static int Theme_listChoiceBackgroundIndicator;
     field public static int Theme_listDividerAlertDialog;
     field public static int Theme_listPopupWindowStyle;
@@ -1718,6 +1722,18 @@
     ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
   }
 
+  public class AppCompatImageButton extends android.widget.ImageButton {
+    ctor public AppCompatImageButton(android.content.Context);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+  }
+
+  public class AppCompatImageView extends android.widget.ImageView {
+    ctor public AppCompatImageView(android.content.Context);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+  }
+
   public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
     ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
     ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
diff --git a/v7/appcompat/res-public/values/public_attrs.xml b/v7/appcompat/res-public/values/public_attrs.xml
index f8fae53..58f0152 100644
--- a/v7/appcompat/res-public/values/public_attrs.xml
+++ b/v7/appcompat/res-public/values/public_attrs.xml
@@ -115,6 +115,7 @@
      <public type="attr" name="iconifiedByDefault"/>
      <public type="attr" name="indeterminateProgressStyle"/>
      <public type="attr" name="isLightTheme"/>
+     <public type="attr" name="imageButtonStyle"/>
      <public type="attr" name="itemPadding"/>
      <public type="attr" name="layout"/>
      <public type="attr" name="listChoiceBackgroundIndicator"/>
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
index 083fbc6..991ab54 100644
--- a/v7/appcompat/res-public/values/public_styles.xml
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -102,6 +102,7 @@
     <public type="style" name="Widget.AppCompat.DrawerArrowToggle"/>
     <public type="style" name="Widget.AppCompat.DropDownItem.Spinner"/>
     <public type="style" name="Widget.AppCompat.EditText"/>
+    <public type="style" name="Widget.AppCompat.ImageButton"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid"/>
     <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid.Inverse"/>
diff --git a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
index dfc4deb..2944d98 100644
--- a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
+++ b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
@@ -14,13 +14,13 @@
      limitations under the License.
 -->
 
-<android.support.v7.internal.widget.TintImageView
-             xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/action_mode_close_button"
-             android:contentDescription="@string/abc_action_mode_done"
-             android:focusable="true"
-             android:clickable="true"
-             android:src="?attr/actionModeCloseDrawable"
-             style="?attr/actionModeCloseButtonStyle"
-             android:layout_width="wrap_content"
-             android:layout_height="match_parent" />
\ No newline at end of file
+<ImageView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/action_mode_close_button"
+        android:contentDescription="@string/abc_action_mode_done"
+        android:focusable="true"
+        android:clickable="true"
+        android:src="?attr/actionModeCloseDrawable"
+        style="?attr/actionModeCloseButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
index 7407498..b81d5d8 100644
--- a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
+++ b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
@@ -24,7 +24,7 @@
 
     <!-- Icons come first in the layout, since their placement doesn't depend on
          the placement of the text views. -->
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@android:id/icon1"
                android:layout_width="@dimen/abc_dropdownitem_icon_width"
                android:layout_height="48dip"
@@ -34,7 +34,7 @@
                android:visibility="invisible"
                style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@+id/edit_query"
                android:layout_width="48dip"
                android:layout_height="48dip"
@@ -45,7 +45,7 @@
                android:visibility="gone"
                style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
                android:id="@id/android:icon2"
                android:layout_width="48dip"
                android:layout_height="48dip"
diff --git a/v7/appcompat/res/layout/abc_search_view.xml b/v7/appcompat/res/layout/abc_search_view.xml
index ff9361d..a7446e3 100644
--- a/v7/appcompat/res/layout/abc_search_view.xml
+++ b/v7/appcompat/res/layout/abc_search_view.xml
@@ -35,7 +35,7 @@
             android:textColor="?android:attr/textColorPrimary"
             android:visibility="gone" />
 
-    <android.support.v7.internal.widget.TintImageView
+    <ImageView
             android:id="@+id/search_button"
             style="?attr/actionButtonStyle"
             android:layout_width="wrap_content"
@@ -57,7 +57,7 @@
             android:orientation="horizontal"
             android:layoutDirection="locale">
 
-        <android.support.v7.internal.widget.TintImageView
+        <ImageView
                 android:id="@+id/search_mag_icon"
                 android:layout_width="@dimen/abc_dropdownitem_icon_width"
                 android:layout_height="wrap_content"
@@ -94,7 +94,7 @@
                   android:dropDownVerticalOffset="0dip"
                   android:dropDownHorizontalOffset="0dip" />
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_close_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
@@ -113,7 +113,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent">
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_go_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
@@ -125,7 +125,7 @@
                     android:focusable="true"
                     android:contentDescription="@string/abc_searchview_description_submit" />
 
-            <android.support.v7.internal.widget.TintImageView
+            <ImageView
                     android:id="@+id/search_voice_btn"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
index f0c783e..4f11ace 100644
--- a/v7/appcompat/res/values-v21/styles_base.xml
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -188,6 +188,8 @@
 
     <style name="Base.Widget.AppCompat.CompoundButton.RadioButton" parent="android:Widget.Material.CompoundButton.RadioButton" />
 
+    <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.Material.ImageButton" />
+
     <!-- Progress Bar -->
 
     <style name="Base.Widget.AppCompat.ProgressBar.Horizontal"
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index c5c4244..3300564 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -239,6 +239,9 @@
         <!-- EditText background drawable. -->
         <attr name="editTextBackground" format="reference" />
 
+        <!-- ImageButton background drawable. -->
+        <attr name="imageButtonStyle" format="reference" />
+
         <!-- ============================ -->
         <!-- SearchView styles and assets -->
         <!-- ============================ -->
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index 9453944..95d9483 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -218,6 +218,8 @@
 
     <style name="Widget.AppCompat.ButtonBar.AlertDialog" parent="Base.Widget.AppCompat.ButtonBar.AlertDialog" />
 
+    <style name="Widget.AppCompat.ImageButton" parent="Base.Widget.AppCompat.ImageButton" />
+
     <style name="Widget.AppCompat.TextView.SpinnerItem" parent="Base.Widget.AppCompat.TextView.SpinnerItem" />
 
     <style name="AlertDialog.AppCompat" parent="Base.AlertDialog.AppCompat" />
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index 0c3c056..3017e6f 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -446,6 +446,10 @@
         <item name="android:minHeight">@dimen/abc_alert_dialog_button_bar_height</item>
     </style>
 
+    <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.ImageButton">
+        <item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
+    </style>
+
     <style name="Base.Widget.AppCompat.TextView.SpinnerItem" parent="android:Widget.TextView.SpinnerItem">
         <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem</item>
         <item name="android:paddingLeft">8dp</item>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index bb4d308..c946918 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -238,6 +238,8 @@
         <item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
         <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
 
+        <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
         <item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
         <item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
         <item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
@@ -391,6 +393,8 @@
         <item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
         <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
 
+        <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
         <item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
         <item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
         <item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
diff --git a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
index 7cf3e2d..0eea40b 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
+++ b/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
@@ -31,6 +31,8 @@
 import android.support.v7.widget.AppCompatCheckBox;
 import android.support.v7.widget.AppCompatCheckedTextView;
 import android.support.v7.widget.AppCompatEditText;
+import android.support.v7.widget.AppCompatImageButton;
+import android.support.v7.widget.AppCompatImageView;
 import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
 import android.support.v7.widget.AppCompatRadioButton;
 import android.support.v7.widget.AppCompatRatingBar;
@@ -89,12 +91,24 @@
 
         // We need to 'inject' our tint aware Views in place of the standard framework versions
         switch (name) {
+            case "TextView":
+                view = new AppCompatTextView(context, attrs);
+                break;
+            case "ImageView":
+                view = new AppCompatImageView(context, attrs);
+                break;
+            case "Button":
+                view = new AppCompatButton(context, attrs);
+                break;
             case "EditText":
                 view = new AppCompatEditText(context, attrs);
                 break;
             case "Spinner":
                 view = new AppCompatSpinner(context, attrs);
                 break;
+            case "ImageButton":
+                view = new AppCompatImageButton(context, attrs);
+                break;
             case "CheckBox":
                 view = new AppCompatCheckBox(context, attrs);
                 break;
@@ -113,12 +127,6 @@
             case "RatingBar":
                 view = new AppCompatRatingBar(context, attrs);
                 break;
-            case "Button":
-                view = new AppCompatButton(context, attrs);
-                break;
-            case "TextView":
-                view = new AppCompatTextView(context, attrs);
-                break;
             case "SeekBar":
                 view = new AppCompatSeekBar(context, attrs);
                 break;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java b/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
deleted file mode 100644
index 17dd557..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 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.v7.internal.widget;
-
-import android.content.Context;
-import android.support.annotation.DrawableRes;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-/**
- * An tint aware {@link android.widget.ImageView}
- *
- * @hide
- */
-public class TintImageView extends ImageView {
-
-    private static final int[] TINT_ATTRS = {
-            android.R.attr.background,
-            android.R.attr.src
-    };
-
-    private final TintManager mTintManager;
-
-    public TintImageView(Context context) {
-        this(context, null);
-    }
-
-    public TintImageView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TintImageView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, TINT_ATTRS,
-                defStyleAttr, 0);
-        if (a.length() > 0) {
-            if (a.hasValue(0)) {
-                setBackgroundDrawable(a.getDrawable(0));
-            }
-            if (a.hasValue(1)) {
-                setImageDrawable(a.getDrawable(1));
-            }
-        }
-        a.recycle();
-
-        // Keep the TintManager in case we need it later
-        mTintManager = a.getTintManager();
-    }
-
-    @Override
-    public void setImageResource(@DrawableRes int resId) {
-        // Intercept this call and instead retrieve the Drawable via the tint manager
-        setImageDrawable(mTintManager.getDrawable(resId));
-    }
-}
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index 7b68805..e3d04e1 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -35,7 +35,6 @@
 import android.support.v7.internal.view.menu.MenuPopupHelper;
 import android.support.v7.internal.view.menu.MenuView;
 import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.TintImageView;
 import android.util.SparseBooleanArray;
 import android.view.MenuItem;
 import android.view.SoundEffectConstants;
@@ -606,7 +605,8 @@
         };
     }
 
-    private class OverflowMenuButton extends TintImageView implements ActionMenuView.ActionMenuChildView {
+    private class OverflowMenuButton extends AppCompatImageView
+            implements ActionMenuView.ActionMenuChildView {
         private final float[] mTempPts = new float[2];
 
         public OverflowMenuButton(Context context) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
new file mode 100644
index 0000000..20c5402
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.support.v7.internal.widget.TintManager;
+import android.util.AttributeSet;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+/**
+ * A {@link ImageButton} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ *     <li>Allows dynamic tint of it background via the background tint methods in
+ *     {@link android.support.v4.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageButton} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageButton extends ImageButton implements TintableBackgroundView {
+
+    private AppCompatBackgroundHelper mBackgroundTintHelper;
+    private AppCompatImageHelper mImageHelper;
+
+    public AppCompatImageButton(Context context) {
+        this(context, null);
+    }
+
+    public AppCompatImageButton(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.imageButtonStyle);
+    }
+
+    public AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final TintManager tintManager = TintManager.get(context);
+
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, tintManager);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mImageHelper = new AppCompatImageHelper(this, tintManager);
+        mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setImageResource(@DrawableRes int resId) {
+        // Intercept this call and instead retrieve the Drawable via the image helper
+        mImageHelper.setImageResource(resId);
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
new file mode 100644
index 0000000..41bda8b
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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.v7.widget;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.internal.widget.TintInfo;
+import android.support.v7.internal.widget.TintManager;
+import android.support.v7.internal.widget.TintTypedArray;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+class AppCompatImageHelper {
+
+    private static final int[] VIEW_ATTRS = {android.R.attr.src};
+
+    private final ImageView mView;
+    private final TintManager mTintManager;
+
+    AppCompatImageHelper(ImageView view, TintManager tintManager) {
+        mView = view;
+        mTintManager = tintManager;
+    }
+
+    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+                VIEW_ATTRS, defStyleAttr, 0);
+        try {
+            if (a.hasValue(0)) {
+                mView.setImageDrawable(a.getDrawable(0));
+            }
+        } finally {
+            a.recycle();
+        }
+    }
+
+    void setImageResource(int resId) {
+        mView.setImageDrawable(mTintManager != null
+                ? mTintManager.getDrawable(resId)
+                : ContextCompat.getDrawable(mView.getContext(), resId));
+    }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
new file mode 100644
index 0000000..c289028
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.support.v7.internal.widget.TintManager;
+import android.support.v7.internal.widget.TintTypedArray;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+/**
+ * A {@link ImageView} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ *     <li>Allows dynamic tint of it background via the background tint methods in
+ *     {@link android.support.v4.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageView} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageView extends ImageView implements TintableBackgroundView {
+
+    private AppCompatBackgroundHelper mBackgroundTintHelper;
+    private AppCompatImageHelper mImageHelper;
+
+    public AppCompatImageView(Context context) {
+        this(context, null);
+    }
+
+    public AppCompatImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AppCompatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final TintManager tintManager = TintManager.get(context);
+
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this, tintManager);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mImageHelper = new AppCompatImageHelper(this, tintManager);
+        mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setImageResource(@DrawableRes int resId) {
+        // Intercept this call and instead retrieve the Drawable via the image helper
+        mImageHelper.setImageResource(resId);
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+    }
+}