Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 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.PorterDuff;
     24 import android.graphics.drawable.Drawable;
     25 import android.util.AttributeSet;
     26 import android.view.accessibility.AccessibilityEvent;
     27 import android.view.accessibility.AccessibilityNodeInfo;
     28 import android.widget.Button;
     29 import android.widget.TextView;
     30 
     31 import androidx.annotation.DrawableRes;
     32 import androidx.annotation.NonNull;
     33 import androidx.annotation.Nullable;
     34 import androidx.annotation.RestrictTo;
     35 import androidx.appcompat.R;
     36 import androidx.core.view.TintableBackgroundView;
     37 import androidx.core.widget.AutoSizeableTextView;
     38 import androidx.core.widget.TextViewCompat;
     39 
     40 /**
     41  * A {@link Button} which supports compatible features on older versions of the platform,
     42  * including:
     43  * <ul>
     44  *     <li>Allows dynamic tint of its background via the background tint methods in
     45  *     {@link androidx.core.view.ViewCompat}.</li>
     46  *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
     47  *     {@link R.attr#backgroundTintMode}.</li>
     48  * </ul>
     49  *
     50  * <p>This will automatically be used when you use {@link Button} in your layouts
     51  * and the top-level activity / dialog is provided by
     52  * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>.
     53  * You should only need to manually use this class when writing custom views.</p>
     54  */
     55 public class AppCompatButton extends Button implements TintableBackgroundView,
     56         AutoSizeableTextView {
     57 
     58     private final AppCompatBackgroundHelper mBackgroundTintHelper;
     59     private final AppCompatTextHelper mTextHelper;
     60 
     61     public AppCompatButton(Context context) {
     62         this(context, null);
     63     }
     64 
     65     public AppCompatButton(Context context, AttributeSet attrs) {
     66         this(context, attrs, R.attr.buttonStyle);
     67     }
     68 
     69     public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
     70         super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
     71 
     72         mBackgroundTintHelper = new AppCompatBackgroundHelper(this);
     73         mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
     74 
     75         mTextHelper = new AppCompatTextHelper(this);
     76         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
     77         mTextHelper.applyCompoundDrawablesTints();
     78     }
     79 
     80     @Override
     81     public void setBackgroundResource(@DrawableRes int resId) {
     82         super.setBackgroundResource(resId);
     83         if (mBackgroundTintHelper != null) {
     84             mBackgroundTintHelper.onSetBackgroundResource(resId);
     85         }
     86     }
     87 
     88     @Override
     89     public void setBackgroundDrawable(Drawable background) {
     90         super.setBackgroundDrawable(background);
     91         if (mBackgroundTintHelper != null) {
     92             mBackgroundTintHelper.onSetBackgroundDrawable(background);
     93         }
     94     }
     95 
     96     /**
     97      * This should be accessed via
     98      * {@link androidx.core.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
     99      *
    100      * @hide
    101      */
    102     @RestrictTo(LIBRARY_GROUP)
    103     @Override
    104     public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
    105         if (mBackgroundTintHelper != null) {
    106             mBackgroundTintHelper.setSupportBackgroundTintList(tint);
    107         }
    108     }
    109 
    110     /**
    111      * This should be accessed via
    112      * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)}
    113      *
    114      * @hide
    115      */
    116     @RestrictTo(LIBRARY_GROUP)
    117     @Override
    118     @Nullable
    119     public ColorStateList getSupportBackgroundTintList() {
    120         return mBackgroundTintHelper != null
    121                 ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
    122     }
    123 
    124     /**
    125      * This should be accessed via
    126      * {@link androidx.core.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
    127      *
    128      * @hide
    129      */
    130     @RestrictTo(LIBRARY_GROUP)
    131     @Override
    132     public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
    133         if (mBackgroundTintHelper != null) {
    134             mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
    135         }
    136     }
    137 
    138     /**
    139      * This should be accessed via
    140      * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)}
    141      *
    142      * @hide
    143      */
    144     @RestrictTo(LIBRARY_GROUP)
    145     @Override
    146     @Nullable
    147     public PorterDuff.Mode getSupportBackgroundTintMode() {
    148         return mBackgroundTintHelper != null
    149                 ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
    150     }
    151 
    152     @Override
    153     protected void drawableStateChanged() {
    154         super.drawableStateChanged();
    155         if (mBackgroundTintHelper != null) {
    156             mBackgroundTintHelper.applySupportBackgroundTint();
    157         }
    158         if (mTextHelper != null) {
    159             mTextHelper.applyCompoundDrawablesTints();
    160         }
    161     }
    162 
    163     @Override
    164     public void setTextAppearance(Context context, int resId) {
    165         super.setTextAppearance(context, resId);
    166         if (mTextHelper != null) {
    167             mTextHelper.onSetTextAppearance(context, resId);
    168         }
    169     }
    170 
    171     @Override
    172     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
    173         super.onInitializeAccessibilityEvent(event);
    174         event.setClassName(Button.class.getName());
    175     }
    176 
    177     @Override
    178     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    179         super.onInitializeAccessibilityNodeInfo(info);
    180         info.setClassName(Button.class.getName());
    181     }
    182 
    183     @Override
    184     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    185         super.onLayout(changed, left, top, right, bottom);
    186         if (mTextHelper != null) {
    187             mTextHelper.onLayout(changed, left, top, right, bottom);
    188         }
    189     }
    190 
    191     @Override
    192     public void setTextSize(int unit, float size) {
    193         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    194             super.setTextSize(unit, size);
    195         } else {
    196             if (mTextHelper != null) {
    197                 mTextHelper.setTextSize(unit, size);
    198             }
    199         }
    200     }
    201 
    202     @Override
    203     protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
    204         super.onTextChanged(text, start, lengthBefore, lengthAfter);
    205         if (mTextHelper != null && !PLATFORM_SUPPORTS_AUTOSIZE && mTextHelper.isAutoSizeEnabled()) {
    206             mTextHelper.autoSizeText();
    207         }
    208     }
    209 
    210     /**
    211      * @hide
    212      */
    213     @RestrictTo(LIBRARY_GROUP)
    214     @Override
    215     public void setAutoSizeTextTypeWithDefaults(
    216             @TextViewCompat.AutoSizeTextType int autoSizeTextType) {
    217         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    218             super.setAutoSizeTextTypeWithDefaults(autoSizeTextType);
    219         } else {
    220             if (mTextHelper != null) {
    221                 mTextHelper.setAutoSizeTextTypeWithDefaults(autoSizeTextType);
    222             }
    223         }
    224     }
    225 
    226     /**
    227      * @hide
    228      */
    229     @RestrictTo(LIBRARY_GROUP)
    230     @Override
    231     public void setAutoSizeTextTypeUniformWithConfiguration(
    232             int autoSizeMinTextSize,
    233             int autoSizeMaxTextSize,
    234             int autoSizeStepGranularity,
    235             int unit) throws IllegalArgumentException {
    236         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    237             super.setAutoSizeTextTypeUniformWithConfiguration(
    238                     autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit);
    239         } else {
    240             if (mTextHelper != null) {
    241                 mTextHelper.setAutoSizeTextTypeUniformWithConfiguration(
    242                         autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit);
    243             }
    244         }
    245     }
    246 
    247     /**
    248      * @hide
    249      */
    250     @RestrictTo(LIBRARY_GROUP)
    251     @Override
    252     public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit)
    253             throws IllegalArgumentException {
    254         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    255             super.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit);
    256         } else {
    257             if (mTextHelper != null) {
    258                 mTextHelper.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit);
    259             }
    260         }
    261     }
    262 
    263     /**
    264      * @hide
    265      */
    266     @RestrictTo(LIBRARY_GROUP)
    267     @Override
    268     @TextViewCompat.AutoSizeTextType
    269     public int getAutoSizeTextType() {
    270         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    271             return super.getAutoSizeTextType() == TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM
    272                     ? TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM
    273                     : TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE;
    274         } else {
    275             if (mTextHelper != null) {
    276                 return mTextHelper.getAutoSizeTextType();
    277             }
    278         }
    279         return TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE;
    280     }
    281 
    282     /**
    283      * @hide
    284      */
    285     @RestrictTo(LIBRARY_GROUP)
    286     @Override
    287     public int getAutoSizeStepGranularity() {
    288         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    289             return super.getAutoSizeStepGranularity();
    290         } else {
    291             if (mTextHelper != null) {
    292                 return mTextHelper.getAutoSizeStepGranularity();
    293             }
    294         }
    295         return -1;
    296     }
    297 
    298     /**
    299      * @hide
    300      */
    301     @RestrictTo(LIBRARY_GROUP)
    302     @Override
    303     public int getAutoSizeMinTextSize() {
    304         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    305             return super.getAutoSizeMinTextSize();
    306         } else {
    307             if (mTextHelper != null) {
    308                 return mTextHelper.getAutoSizeMinTextSize();
    309             }
    310         }
    311         return -1;
    312     }
    313 
    314     /**
    315      * @hide
    316      */
    317     @RestrictTo(LIBRARY_GROUP)
    318     @Override
    319     public int getAutoSizeMaxTextSize() {
    320         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    321             return super.getAutoSizeMaxTextSize();
    322         } else {
    323             if (mTextHelper != null) {
    324                 return mTextHelper.getAutoSizeMaxTextSize();
    325             }
    326         }
    327         return -1;
    328     }
    329 
    330     /**
    331      * @hide
    332      */
    333     @RestrictTo(LIBRARY_GROUP)
    334     @Override
    335     public int[] getAutoSizeTextAvailableSizes() {
    336         if (PLATFORM_SUPPORTS_AUTOSIZE) {
    337             return super.getAutoSizeTextAvailableSizes();
    338         } else {
    339             if (mTextHelper != null) {
    340                 return mTextHelper.getAutoSizeTextAvailableSizes();
    341             }
    342         }
    343         return new int[0];
    344     }
    345 
    346     /**
    347      * Sets the properties of this field to transform input to ALL CAPS
    348      * display. This may use a "small caps" formatting if available.
    349      * This setting will be ignored if this field is editable or selectable.
    350      *
    351      * This call replaces the current transformation method. Disabling this
    352      * will not necessarily restore the previous behavior from before this
    353      * was enabled.
    354      */
    355     public void setSupportAllCaps(boolean allCaps) {
    356         if (mTextHelper != null) {
    357             mTextHelper.setAllCaps(allCaps);
    358         }
    359     }
    360 }
    361