/* * 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 androidx.appcompat.widget; import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; import static androidx.appcompat.widget.ViewUtils.SDK_LEVEL_SUPPORTS_AUTOSIZE; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION_CODES; import android.text.InputFilter; import android.util.AttributeSet; import android.view.ActionMode; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.textclassifier.TextClassifier; import android.widget.TextView; import androidx.annotation.DrawableRes; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.annotation.UiThread; import androidx.appcompat.content.res.AppCompatResources; import androidx.core.graphics.TypefaceCompat; import androidx.core.text.PrecomputedTextCompat; import androidx.core.view.TintableBackgroundView; import androidx.core.widget.AutoSizeableTextView; import androidx.core.widget.TextViewCompat; import androidx.core.widget.TintableCompoundDrawablesView; import androidx.resourceinspection.annotation.AppCompatShadowedAttributes; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; /** * A {@link TextView} which supports compatible features on older versions of the platform, * including: *
This will automatically be used when you use {@link TextView} in your layouts * and the top-level activity / dialog is provided by * appcompat. * You should only need to manually use this class when writing custom views.
*/ @AppCompatShadowedAttributes public class AppCompatTextView extends TextView implements TintableBackgroundView, TintableCompoundDrawablesView, AutoSizeableTextView, EmojiCompatConfigurationView { private final AppCompatBackgroundHelper mBackgroundTintHelper; private final AppCompatTextHelper mTextHelper; private final AppCompatTextClassifierHelper mTextClassifierHelper; @SuppressWarnings("NotNullFieldNotInitialized") // initialized in getter @NonNull private AppCompatEmojiTextHelper mEmojiTextViewHelper; private boolean mIsSetTypefaceProcessing = false; @Nullable private SuperCaller mSuperCaller = null; @Nullable private Future* Subsequent calls to {@link #setCompoundDrawables(Drawable, Drawable, Drawable, Drawable)} and * related methods will automatically mutate the drawables and apply the specified tint and tint * mode using {@link Drawable#setTintList(ColorStateList)}. * * @param tintList the tint to apply, may be {@code null} to clear tint * @attr ref androidx.appcompat.R.styleable#AppCompatTextView_drawableTint * @see #getSupportCompoundDrawablesTintList() * * @hide */ @Override @RestrictTo(LIBRARY_GROUP_PREFIX) public void setSupportCompoundDrawablesTintList(@Nullable ColorStateList tintList) { mTextHelper.setCompoundDrawableTintList(tintList); mTextHelper.applyCompoundDrawablesTints(); } /** * This should be accessed via * {@link androidx.core.widget.TextViewCompat#getCompoundDrawableTintMode(TextView)} * * Returns the blending mode used to apply the tint to the compound drawables, if specified. * * @return the blending mode used to apply the tint to the compound drawables * @attr ref androidx.appcompat.R.styleable#AppCompatTextView_drawableTintMode * @see #setSupportCompoundDrawablesTintMode(PorterDuff.Mode) * * @hide */ @Nullable @Override @RestrictTo(LIBRARY_GROUP_PREFIX) public PorterDuff.Mode getSupportCompoundDrawablesTintMode() { return mTextHelper.getCompoundDrawableTintMode(); } /** * This should be accessed via {@link * androidx.core.widget.TextViewCompat#setCompoundDrawableTintMode(TextView, PorterDuff.Mode)} * * Specifies the blending mode used to apply the tint specified by * {@link #setSupportCompoundDrawablesTintList(ColorStateList)} to the compound drawables. The * default mode is {@link PorterDuff.Mode#SRC_IN}. * * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint * @attr ref androidx.appcompat.R.styleable#AppCompatTextView_drawableTintMode * @see #setSupportCompoundDrawablesTintList(ColorStateList) * * @hide */ @Override @RestrictTo(LIBRARY_GROUP_PREFIX) public void setSupportCompoundDrawablesTintMode(@Nullable PorterDuff.Mode tintMode) { mTextHelper.setCompoundDrawableTintMode(tintMode); mTextHelper.applyCompoundDrawablesTints(); } @Override public void setTypeface(@Nullable Typeface tf, int style) { if (mIsSetTypefaceProcessing) { // b/151782655 // Some device up to API19 recursively calls setTypeface. To avoid infinity recursive // setTypeface call, exit if we know this is re-entrant call. // TODO(nona): Remove this once Android X minSdkVersion moves to API21. return; } Typeface finalTypeface = null; if (tf != null && style > 0) { finalTypeface = TypefaceCompat.create(getContext(), tf, style); } mIsSetTypefaceProcessing = true; try { super.setTypeface(finalTypeface != null ? finalTypeface : tf, style); } finally { mIsSetTypefaceProcessing = false; } } @UiThread @RequiresApi(api = 26) SuperCaller getSuperCaller() { if (mSuperCaller == null) { if (Build.VERSION.SDK_INT >= 28) { mSuperCaller = new SuperCallerApi28(); } else if (Build.VERSION.SDK_INT >= 26) { mSuperCaller = new SuperCallerApi26(); } } return mSuperCaller; } private interface SuperCaller { // api 26 int getAutoSizeMaxTextSize(); int getAutoSizeMinTextSize(); int getAutoSizeStepGranularity(); int[] getAutoSizeTextAvailableSizes(); int getAutoSizeTextType(); TextClassifier getTextClassifier(); void setAutoSizeTextTypeUniformWithConfiguration(int autoSizeMinTextSize, int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit); void setAutoSizeTextTypeUniformWithPresetSizes(int[] presetSizes, int unit); void setAutoSizeTextTypeWithDefaults(int autoSizeTextType); void setTextClassifier(@Nullable TextClassifier textClassifier); // api 28 void setFirstBaselineToTopHeight(@Px int firstBaselineToTopHeight); void setLastBaselineToBottomHeight(@Px int lastBaselineToBottomHeight); } @RequiresApi(api = 26) class SuperCallerApi26 implements SuperCaller { @Override public int getAutoSizeMaxTextSize() { return AppCompatTextView.super.getAutoSizeMaxTextSize(); } @Override public int getAutoSizeMinTextSize() { return AppCompatTextView.super.getAutoSizeMinTextSize(); } @Override public int getAutoSizeStepGranularity() { return AppCompatTextView.super.getAutoSizeStepGranularity(); } @Override public int[] getAutoSizeTextAvailableSizes() { return AppCompatTextView.super.getAutoSizeTextAvailableSizes(); } @Override public int getAutoSizeTextType() { return AppCompatTextView.super.getAutoSizeTextType(); } @Override public TextClassifier getTextClassifier() { return AppCompatTextView.super.getTextClassifier(); } @Override public void setAutoSizeTextTypeUniformWithConfiguration(int autoSizeMinTextSize, int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit) { AppCompatTextView.super.setAutoSizeTextTypeUniformWithConfiguration(autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit); } @Override public void setAutoSizeTextTypeUniformWithPresetSizes(int[] presetSizes, int unit) { AppCompatTextView.super.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit); } @Override public void setAutoSizeTextTypeWithDefaults(int autoSizeTextType) { AppCompatTextView.super.setAutoSizeTextTypeWithDefaults(autoSizeTextType); } @Override public void setTextClassifier(@Nullable TextClassifier textClassifier) { AppCompatTextView.super.setTextClassifier(textClassifier); } @Override public void setFirstBaselineToTopHeight(int firstBaselineToTopHeight) {} @Override public void setLastBaselineToBottomHeight(int lastBaselineToBottomHeight) {} } @RequiresApi(api = 28) class SuperCallerApi28 extends SuperCallerApi26 { @Override public void setFirstBaselineToTopHeight(@Px int firstBaselineToTopHeight) { AppCompatTextView.super.setFirstBaselineToTopHeight(firstBaselineToTopHeight); } @Override public void setLastBaselineToBottomHeight(@Px int lastBaselineToBottomHeight) { AppCompatTextView.super.setLastBaselineToBottomHeight(lastBaselineToBottomHeight); } } }