1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.appcompat.widget;
18 
19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20 
21 import android.content.Context;
22 import android.content.res.ColorStateList;
23 import android.graphics.Bitmap;
24 import android.graphics.PorterDuff;
25 import android.graphics.drawable.Drawable;
26 import android.net.Uri;
27 import android.util.AttributeSet;
28 import android.widget.ImageButton;
29 import android.widget.ImageView;
30 
31 import androidx.annotation.DrawableRes;
32 import androidx.annotation.Nullable;
33 import androidx.annotation.RestrictTo;
34 import androidx.appcompat.R;
35 import androidx.core.view.TintableBackgroundView;
36 import androidx.core.widget.ImageViewCompat;
37 import androidx.core.widget.TintableImageSourceView;
38 
39 /**
40  * A {@link ImageButton} which supports compatible features on older versions of the platform,
41  * including:
42  * <ul>
43  *     <li>Allows dynamic tint of its background via the background tint methods in
44  *     {@link androidx.core.view.ViewCompat}.</li>
45  *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
46  *     {@link R.attr#backgroundTintMode}.</li>
47  *     <li>Allows dynamic tint of its image via the image tint methods in
48  *     {@link ImageViewCompat}.</li>
49  *     <li>Allows setting of the image tint using {@link R.attr#tint} and
50  *     {@link R.attr#tintMode}.</li>
51  * </ul>
52  *
53  * <p>This will automatically be used when you use {@link ImageButton} in your layouts
54  * and the top-level activity / dialog is provided by
55  * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>.
56  * You should only need to manually use this class when writing custom views.</p>
57  */
58 public class AppCompatImageButton extends ImageButton implements TintableBackgroundView,
59         TintableImageSourceView {
60 
61     private final AppCompatBackgroundHelper mBackgroundTintHelper;
62     private final AppCompatImageHelper mImageHelper;
63 
AppCompatImageButton(Context context)64     public AppCompatImageButton(Context context) {
65         this(context, null);
66     }
67 
AppCompatImageButton(Context context, AttributeSet attrs)68     public AppCompatImageButton(Context context, AttributeSet attrs) {
69         this(context, attrs, R.attr.imageButtonStyle);
70     }
71 
AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr)72     public AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
73         super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
74 
75         mBackgroundTintHelper = new AppCompatBackgroundHelper(this);
76         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
77 
78         mImageHelper = new AppCompatImageHelper(this);
79         mImageHelper.loadFromAttributes(attrs, defStyleAttr);
80     }
81 
82     @Override
setImageResource(@rawableRes int resId)83     public void setImageResource(@DrawableRes int resId) {
84         // Intercept this call and instead retrieve the Drawable via the image helper
85         mImageHelper.setImageResource(resId);
86     }
87 
88     @Override
setImageDrawable(@ullable Drawable drawable)89     public void setImageDrawable(@Nullable Drawable drawable) {
90         super.setImageDrawable(drawable);
91         if (mImageHelper != null) {
92             mImageHelper.applySupportImageTint();
93         }
94     }
95 
96     @Override
setImageBitmap(Bitmap bm)97     public void setImageBitmap(Bitmap bm) {
98         super.setImageBitmap(bm);
99         if (mImageHelper != null) {
100             mImageHelper.applySupportImageTint();
101         }
102     }
103 
104     @Override
setImageURI(@ullable Uri uri)105     public void setImageURI(@Nullable Uri uri) {
106         super.setImageURI(uri);
107         if (mImageHelper != null) {
108             mImageHelper.applySupportImageTint();
109         }
110     }
111 
112     @Override
setBackgroundResource(@rawableRes int resId)113     public void setBackgroundResource(@DrawableRes int resId) {
114         super.setBackgroundResource(resId);
115         if (mBackgroundTintHelper != null) {
116             mBackgroundTintHelper.onSetBackgroundResource(resId);
117         }
118     }
119 
120     @Override
setBackgroundDrawable(Drawable background)121     public void setBackgroundDrawable(Drawable background) {
122         super.setBackgroundDrawable(background);
123         if (mBackgroundTintHelper != null) {
124             mBackgroundTintHelper.onSetBackgroundDrawable(background);
125         }
126     }
127 
128     /**
129      * This should be accessed via
130      * {@link androidx.core.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
131      *
132      * @hide
133      */
134     @RestrictTo(LIBRARY_GROUP)
135     @Override
setSupportBackgroundTintList(@ullable ColorStateList tint)136     public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
137         if (mBackgroundTintHelper != null) {
138             mBackgroundTintHelper.setSupportBackgroundTintList(tint);
139         }
140     }
141 
142     /**
143      * This should be accessed via
144      * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)}
145      *
146      * @hide
147      */
148     @RestrictTo(LIBRARY_GROUP)
149     @Override
150     @Nullable
getSupportBackgroundTintList()151     public ColorStateList getSupportBackgroundTintList() {
152         return mBackgroundTintHelper != null
153                 ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
154     }
155 
156     /**
157      * This should be accessed via
158      * {@link androidx.core.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
159      *
160      * @hide
161      */
162     @RestrictTo(LIBRARY_GROUP)
163     @Override
setSupportBackgroundTintMode(@ullable PorterDuff.Mode tintMode)164     public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
165         if (mBackgroundTintHelper != null) {
166             mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
167         }
168     }
169 
170     /**
171      * This should be accessed via
172      * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)}
173      *
174      * @hide
175      */
176     @RestrictTo(LIBRARY_GROUP)
177     @Override
178     @Nullable
getSupportBackgroundTintMode()179     public PorterDuff.Mode getSupportBackgroundTintMode() {
180         return mBackgroundTintHelper != null
181                 ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
182     }
183     /**
184      * This should be accessed via
185      * {@link androidx.core.widget.ImageViewCompat#setImageTintList(ImageView, ColorStateList)}
186      *
187      * @hide
188      */
189     @RestrictTo(LIBRARY_GROUP)
190     @Override
setSupportImageTintList(@ullable ColorStateList tint)191     public void setSupportImageTintList(@Nullable ColorStateList tint) {
192         if (mImageHelper != null) {
193             mImageHelper.setSupportImageTintList(tint);
194         }
195     }
196 
197     /**
198      * This should be accessed via
199      * {@link androidx.core.widget.ImageViewCompat#getImageTintList(ImageView)}
200      *
201      * @hide
202      */
203     @RestrictTo(LIBRARY_GROUP)
204     @Override
205     @Nullable
getSupportImageTintList()206     public ColorStateList getSupportImageTintList() {
207         return mImageHelper != null
208                 ? mImageHelper.getSupportImageTintList() : null;
209     }
210 
211     /**
212      * This should be accessed via
213      * {@link androidx.core.widget.ImageViewCompat#setImageTintMode(ImageView, PorterDuff.Mode)}
214      *
215      * @hide
216      */
217     @RestrictTo(LIBRARY_GROUP)
218     @Override
setSupportImageTintMode(@ullable PorterDuff.Mode tintMode)219     public void setSupportImageTintMode(@Nullable PorterDuff.Mode tintMode) {
220         if (mImageHelper != null) {
221             mImageHelper.setSupportImageTintMode(tintMode);
222         }
223     }
224 
225     /**
226      * This should be accessed via
227      * {@link androidx.core.widget.ImageViewCompat#getImageTintMode(ImageView)}
228      *
229      * @hide
230      */
231     @RestrictTo(LIBRARY_GROUP)
232     @Override
233     @Nullable
getSupportImageTintMode()234     public PorterDuff.Mode getSupportImageTintMode() {
235         return mImageHelper != null
236                 ? mImageHelper.getSupportImageTintMode() : null;
237     }
238 
239     @Override
drawableStateChanged()240     protected void drawableStateChanged() {
241         super.drawableStateChanged();
242         if (mBackgroundTintHelper != null) {
243             mBackgroundTintHelper.applySupportBackgroundTint();
244         }
245         if (mImageHelper != null) {
246             mImageHelper.applySupportImageTint();
247         }
248     }
249 
250     @Override
hasOverlappingRendering()251     public boolean hasOverlappingRendering() {
252         return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering();
253     }
254 }
255