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.text.Editable; 26 import android.util.AttributeSet; 27 import android.view.inputmethod.EditorInfo; 28 import android.view.inputmethod.InputConnection; 29 import android.widget.EditText; 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.os.BuildCompat; 36 import androidx.core.view.TintableBackgroundView; 37 38 /** 39 * A {@link EditText} which supports compatible features on older versions of the platform, 40 * including: 41 * <ul> 42 * <li>Allows dynamic tint of its background via the background tint methods in 43 * {@link androidx.core.view.ViewCompat}.</li> 44 * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and 45 * {@link R.attr#backgroundTintMode}.</li> 46 * </ul> 47 * 48 * <p>This will automatically be used when you use {@link EditText} in your layouts 49 * and the top-level activity / dialog is provided by 50 * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>. 51 * You should only need to manually use this class when writing custom views.</p> 52 */ 53 public class AppCompatEditText extends EditText implements TintableBackgroundView { 54 55 private final AppCompatBackgroundHelper mBackgroundTintHelper; 56 private final AppCompatTextHelper mTextHelper; 57 58 public AppCompatEditText(Context context) { 59 this(context, null); 60 } 61 62 public AppCompatEditText(Context context, AttributeSet attrs) { 63 this(context, attrs, R.attr.editTextStyle); 64 } 65 66 public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) { 67 super(TintContextWrapper.wrap(context), attrs, defStyleAttr); 68 69 mBackgroundTintHelper = new AppCompatBackgroundHelper(this); 70 mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); 71 72 mTextHelper = new AppCompatTextHelper(this); 73 mTextHelper.loadFromAttributes(attrs, defStyleAttr); 74 mTextHelper.applyCompoundDrawablesTints(); 75 } 76 77 /** 78 * Return the text that the view is displaying. If an editable text has not been set yet, this 79 * will return null. 80 */ 81 @Override 82 @Nullable public Editable getText() { 83 if (BuildCompat.isAtLeastP()) { 84 return super.getText(); 85 } 86 // A bug pre-P makes getText() crash if called before the first setText due to a cast, so 87 // retrieve the editable text. 88 return super.getEditableText(); 89 } 90 91 @Override 92 public void setBackgroundResource(@DrawableRes int resId) { 93 super.setBackgroundResource(resId); 94 if (mBackgroundTintHelper != null) { 95 mBackgroundTintHelper.onSetBackgroundResource(resId); 96 } 97 } 98 99 @Override 100 public void setBackgroundDrawable(Drawable background) { 101 super.setBackgroundDrawable(background); 102 if (mBackgroundTintHelper != null) { 103 mBackgroundTintHelper.onSetBackgroundDrawable(background); 104 } 105 } 106 107 /** 108 * This should be accessed via 109 * {@link androidx.core.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} 110 * 111 * @hide 112 */ 113 @RestrictTo(LIBRARY_GROUP) 114 @Override 115 public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { 116 if (mBackgroundTintHelper != null) { 117 mBackgroundTintHelper.setSupportBackgroundTintList(tint); 118 } 119 } 120 121 /** 122 * This should be accessed via 123 * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)} 124 * 125 * @hide 126 */ 127 @RestrictTo(LIBRARY_GROUP) 128 @Override 129 @Nullable 130 public ColorStateList getSupportBackgroundTintList() { 131 return mBackgroundTintHelper != null 132 ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; 133 } 134 135 /** 136 * This should be accessed via 137 * {@link androidx.core.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} 138 * 139 * @hide 140 */ 141 @RestrictTo(LIBRARY_GROUP) 142 @Override 143 public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 144 if (mBackgroundTintHelper != null) { 145 mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); 146 } 147 } 148 149 /** 150 * This should be accessed via 151 * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)} 152 * 153 * @hide 154 */ 155 @RestrictTo(LIBRARY_GROUP) 156 @Override 157 @Nullable 158 public PorterDuff.Mode getSupportBackgroundTintMode() { 159 return mBackgroundTintHelper != null 160 ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; 161 } 162 163 @Override 164 protected void drawableStateChanged() { 165 super.drawableStateChanged(); 166 if (mBackgroundTintHelper != null) { 167 mBackgroundTintHelper.applySupportBackgroundTint(); 168 } 169 if (mTextHelper != null) { 170 mTextHelper.applyCompoundDrawablesTints(); 171 } 172 } 173 174 @Override 175 public void setTextAppearance(Context context, int resId) { 176 super.setTextAppearance(context, resId); 177 if (mTextHelper != null) { 178 mTextHelper.onSetTextAppearance(context, resId); 179 } 180 } 181 182 @Override 183 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 184 return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs), 185 outAttrs, this); 186 } 187 } 188