| /* |
| * 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 androidx.appcompat.widget; |
| |
| import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; |
| |
| import android.annotation.SuppressLint; |
| import android.content.Context; |
| import android.content.res.ColorStateList; |
| import android.graphics.PorterDuff; |
| import android.graphics.drawable.Drawable; |
| import android.os.Build; |
| import android.util.AttributeSet; |
| import android.view.ActionMode; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.accessibility.AccessibilityNodeInfo; |
| import android.widget.Button; |
| import android.widget.TextView; |
| |
| import androidx.annotation.DrawableRes; |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.RestrictTo; |
| import androidx.appcompat.R; |
| import androidx.core.view.TintableBackgroundView; |
| import androidx.core.widget.AutoSizeableTextView; |
| import androidx.core.widget.TextViewCompat; |
| import androidx.core.widget.TintableCompoundDrawablesView; |
| |
| /** |
| * A {@link Button} which supports compatible features on older versions of the platform, |
| * including: |
| * <ul> |
| * <li>Allows dynamic tint of its background via the background tint methods in |
| * {@link androidx.core.view.ViewCompat}.</li> |
| * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and |
| * {@link R.attr#backgroundTintMode}.</li> |
| * <li>Allows setting of the font family using {@link android.R.attr#fontFamily}</li> |
| * </ul> |
| * |
| * <p>This will automatically be used when you use {@link Button} in your layouts |
| * and the top-level activity / dialog is provided by |
| * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>. |
| * You should only need to manually use this class when writing custom views.</p> |
| */ |
| public class AppCompatButton extends Button implements TintableBackgroundView, |
| AutoSizeableTextView, TintableCompoundDrawablesView { |
| |
| private final AppCompatBackgroundHelper mBackgroundTintHelper; |
| private final AppCompatTextHelper mTextHelper; |
| |
| public AppCompatButton(@NonNull Context context) { |
| this(context, null); |
| } |
| |
| public AppCompatButton(@NonNull Context context, @Nullable AttributeSet attrs) { |
| this(context, attrs, R.attr.buttonStyle); |
| } |
| |
| public AppCompatButton( |
| @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { |
| super(TintContextWrapper.wrap(context), attrs, defStyleAttr); |
| |
| ThemeUtils.checkAppCompatTheme(this, getContext()); |
| |
| mBackgroundTintHelper = new AppCompatBackgroundHelper(this); |
| mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); |
| |
| mTextHelper = new AppCompatTextHelper(this); |
| mTextHelper.loadFromAttributes(attrs, defStyleAttr); |
| mTextHelper.applyCompoundDrawablesTints(); |
| } |
| |
| @Override |
| public void setBackgroundResource(@DrawableRes int resId) { |
| super.setBackgroundResource(resId); |
| if (mBackgroundTintHelper != null) { |
| mBackgroundTintHelper.onSetBackgroundResource(resId); |
| } |
| } |
| |
| @Override |
| public void setBackgroundDrawable(@Nullable Drawable background) { |
| super.setBackgroundDrawable(background); |
| if (mBackgroundTintHelper != null) { |
| mBackgroundTintHelper.onSetBackgroundDrawable(background); |
| } |
| } |
| |
| /** |
| * This should be accessed via |
| * {@link androidx.core.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} |
| * |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return; |
| } |
| if (mBackgroundTintHelper != null) { |
| mBackgroundTintHelper.setSupportBackgroundTintList(tint); |
| } |
| } |
| |
| /** |
| * This should be accessed via |
| * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)} |
| * |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| @Nullable |
| public ColorStateList getSupportBackgroundTintList() { |
| return mBackgroundTintHelper != null |
| ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; |
| } |
| |
| /** |
| * This should be accessed via |
| * {@link androidx.core.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} |
| * |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return; |
| } |
| if (mBackgroundTintHelper != null) { |
| mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); |
| } |
| } |
| |
| /** |
| * This should be accessed via |
| * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)} |
| * |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| @Nullable |
| public PorterDuff.Mode getSupportBackgroundTintMode() { |
| return mBackgroundTintHelper != null |
| ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; |
| } |
| |
| @Override |
| protected void drawableStateChanged() { |
| super.drawableStateChanged(); |
| if (mBackgroundTintHelper != null) { |
| mBackgroundTintHelper.applySupportBackgroundTint(); |
| } |
| if (mTextHelper != null) { |
| mTextHelper.applyCompoundDrawablesTints(); |
| } |
| } |
| |
| @Override |
| public void setTextAppearance(Context context, int resId) { |
| super.setTextAppearance(context, resId); |
| if (mTextHelper != null) { |
| mTextHelper.onSetTextAppearance(context, resId); |
| } |
| } |
| |
| @Override |
| public void onInitializeAccessibilityEvent(AccessibilityEvent event) { |
| super.onInitializeAccessibilityEvent(event); |
| event.setClassName(Button.class.getName()); |
| } |
| |
| @Override |
| public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { |
| super.onInitializeAccessibilityNodeInfo(info); |
| info.setClassName(Button.class.getName()); |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
| super.onLayout(changed, left, top, right, bottom); |
| if (mTextHelper != null) { |
| mTextHelper.onLayout(changed, left, top, right, bottom); |
| } |
| } |
| |
| @Override |
| public void setTextSize(int unit, float size) { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| super.setTextSize(unit, size); |
| } else { |
| if (mTextHelper != null) { |
| mTextHelper.setTextSize(unit, size); |
| } |
| } |
| } |
| |
| @Override |
| protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { |
| super.onTextChanged(text, start, lengthBefore, lengthAfter); |
| if (mTextHelper != null && !PLATFORM_SUPPORTS_AUTOSIZE && mTextHelper.isAutoSizeEnabled()) { |
| mTextHelper.autoSizeText(); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public void setAutoSizeTextTypeWithDefaults( |
| @TextViewCompat.AutoSizeTextType int autoSizeTextType) { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| super.setAutoSizeTextTypeWithDefaults(autoSizeTextType); |
| } else { |
| if (mTextHelper != null) { |
| mTextHelper.setAutoSizeTextTypeWithDefaults(autoSizeTextType); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public void setAutoSizeTextTypeUniformWithConfiguration( |
| int autoSizeMinTextSize, |
| int autoSizeMaxTextSize, |
| int autoSizeStepGranularity, |
| int unit) throws IllegalArgumentException { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| super.setAutoSizeTextTypeUniformWithConfiguration( |
| autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit); |
| } else { |
| if (mTextHelper != null) { |
| mTextHelper.setAutoSizeTextTypeUniformWithConfiguration( |
| autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit) |
| throws IllegalArgumentException { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| super.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit); |
| } else { |
| if (mTextHelper != null) { |
| mTextHelper.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit); |
| } |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| @TextViewCompat.AutoSizeTextType |
| // Suppress lint error for TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM [WrongConstant] |
| @SuppressLint("WrongConstant") |
| public int getAutoSizeTextType() { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| return super.getAutoSizeTextType() == TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM |
| ? TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM |
| : TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE; |
| } else { |
| if (mTextHelper != null) { |
| return mTextHelper.getAutoSizeTextType(); |
| } |
| } |
| return TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public int getAutoSizeStepGranularity() { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| return super.getAutoSizeStepGranularity(); |
| } else { |
| if (mTextHelper != null) { |
| return mTextHelper.getAutoSizeStepGranularity(); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public int getAutoSizeMinTextSize() { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| return super.getAutoSizeMinTextSize(); |
| } else { |
| if (mTextHelper != null) { |
| return mTextHelper.getAutoSizeMinTextSize(); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public int getAutoSizeMaxTextSize() { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| return super.getAutoSizeMaxTextSize(); |
| } else { |
| if (mTextHelper != null) { |
| return mTextHelper.getAutoSizeMaxTextSize(); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @Override |
| public int[] getAutoSizeTextAvailableSizes() { |
| if (PLATFORM_SUPPORTS_AUTOSIZE) { |
| return super.getAutoSizeTextAvailableSizes(); |
| } else { |
| if (mTextHelper != null) { |
| return mTextHelper.getAutoSizeTextAvailableSizes(); |
| } |
| } |
| return new int[0]; |
| } |
| |
| /** |
| * Sets the properties of this field to transform input to ALL CAPS |
| * display. This may use a "small caps" formatting if available. |
| * This setting will be ignored if this field is editable or selectable. |
| * |
| * This call replaces the current transformation method. Disabling this |
| * will not necessarily restore the previous behavior from before this |
| * was enabled. |
| */ |
| public void setSupportAllCaps(boolean allCaps) { |
| if (mTextHelper != null) { |
| mTextHelper.setAllCaps(allCaps); |
| } |
| } |
| |
| /** |
| * See |
| * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)} |
| */ |
| @Override |
| public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) { |
| super.setCustomSelectionActionModeCallback(TextViewCompat |
| .wrapCustomSelectionActionModeCallback(this, actionModeCallback)); |
| } |
| |
| /** |
| * @hide |
| * @param tint the tint to apply, may be {@code null} to clear tint |
| */ |
| @Override |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public void setSupportCompoundDrawablesTintList(@Nullable ColorStateList tint) { |
| mTextHelper.setCompoundDrawableTintList(tint); |
| mTextHelper.applyCompoundDrawablesTints(); |
| } |
| |
| /** |
| * @hide |
| * @return the tint applied to the compound drawables |
| */ |
| @Nullable |
| @Override |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public ColorStateList getSupportCompoundDrawablesTintList() { |
| return mTextHelper.getCompoundDrawableTintList(); |
| } |
| |
| /** |
| * @hide |
| * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint |
| */ |
| @Override |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public void setSupportCompoundDrawablesTintMode(@Nullable PorterDuff.Mode tintMode) { |
| mTextHelper.setCompoundDrawableTintMode(tintMode); |
| mTextHelper.applyCompoundDrawablesTints(); |
| } |
| |
| /** |
| * @hide |
| * @return the blending mode used to apply the tint to the compound drawables |
| */ |
| @Nullable |
| @Override |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public PorterDuff.Mode getSupportCompoundDrawablesTintMode() { |
| return mTextHelper.getCompoundDrawableTintMode(); |
| } |
| } |