1 /* 2 * Copyright (C) 2006 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 android.widget; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.content.res.TypedArray; 22 import android.text.Editable; 23 import android.text.Selection; 24 import android.text.Spannable; 25 import android.text.TextUtils; 26 import android.text.method.ArrowKeyMovementMethod; 27 import android.text.method.MovementMethod; 28 import android.text.style.SpanUtils; 29 import android.util.AttributeSet; 30 import android.view.KeyEvent; 31 32 /* 33 * This is supposed to be a *very* thin veneer over TextView. 34 * Do not make any changes here that do anything that a TextView 35 * with a key listener and a movement method wouldn't do! 36 */ 37 38 /** 39 * A user interface element for entering and modifying text. 40 * When you define an edit text widget, you must specify the 41 * {@link android.R.styleable#TextView_inputType} 42 * attribute. For example, for plain text input set inputType to "text": 43 * <p> 44 * <pre> 45 * <EditText 46 * android:id="@+id/plain_text_input" 47 * android:layout_height="wrap_content" 48 * android:layout_width="match_parent" 49 * android:inputType="text"/></pre> 50 * 51 * Choosing the input type configures the keyboard type that is shown, acceptable characters, 52 * and appearance of the edit text. 53 * For example, if you want to accept a secret number, like a unique pin or serial number, 54 * you can set inputType to "numericPassword". 55 * An inputType of "numericPassword" results in an edit text that accepts numbers only, 56 * shows a numeric keyboard when focused, and masks the text that is entered for privacy. 57 * <p> 58 * See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a> 59 * guide for examples of other 60 * {@link android.R.styleable#TextView_inputType} settings. 61 * </p> 62 * <p>You also can receive callbacks as a user changes text by 63 * adding a {@link android.text.TextWatcher} to the edit text. 64 * This is useful when you want to add auto-save functionality as changes are made, 65 * or validate the format of user input, for example. 66 * You add a text watcher using the {@link TextView#addTextChangedListener} method. 67 * </p> 68 * <p> 69 * This widget does not support auto-sizing text. 70 * <p> 71 * <b>XML attributes</b> 72 * <p> 73 * See {@link android.R.styleable#EditText EditText Attributes}, 74 * {@link android.R.styleable#TextView TextView Attributes}, 75 * {@link android.R.styleable#View View Attributes} 76 * 77 * @attr ref android.R.styleable#EditText_enableTextStylingShortcuts 78 */ 79 public class EditText extends TextView { 80 81 // True if the style shortcut is enabled. 82 private boolean mStyleShortcutsEnabled = false; 83 84 private static final int ID_BOLD = android.R.id.bold; 85 private static final int ID_ITALIC = android.R.id.italic; 86 private static final int ID_UNDERLINE = android.R.id.underline; 87 EditText(Context context)88 public EditText(Context context) { 89 this(context, null); 90 } 91 EditText(Context context, AttributeSet attrs)92 public EditText(Context context, AttributeSet attrs) { 93 this(context, attrs, com.android.internal.R.attr.editTextStyle); 94 } 95 EditText(Context context, AttributeSet attrs, int defStyleAttr)96 public EditText(Context context, AttributeSet attrs, int defStyleAttr) { 97 this(context, attrs, defStyleAttr, 0); 98 } 99 EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)100 public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 101 super(context, attrs, defStyleAttr, defStyleRes); 102 103 final Resources.Theme theme = context.getTheme(); 104 final TypedArray a = theme.obtainStyledAttributes(attrs, 105 com.android.internal.R.styleable.EditText, defStyleAttr, defStyleRes); 106 107 final int n = a.getIndexCount(); 108 for (int i = 0; i < n; ++i) { 109 int attr = a.getIndex(i); 110 switch (attr) { 111 case com.android.internal.R.styleable.EditText_enableTextStylingShortcuts: 112 mStyleShortcutsEnabled = a.getBoolean(attr, false); 113 break; 114 } 115 } 116 } 117 118 @Override getFreezesText()119 public boolean getFreezesText() { 120 return true; 121 } 122 123 @Override getDefaultEditable()124 protected boolean getDefaultEditable() { 125 return true; 126 } 127 128 @Override getDefaultMovementMethod()129 protected MovementMethod getDefaultMovementMethod() { 130 return ArrowKeyMovementMethod.getInstance(); 131 } 132 133 @Override getText()134 public Editable getText() { 135 CharSequence text = super.getText(); 136 // This can only happen during construction. 137 if (text == null) { 138 return null; 139 } 140 if (text instanceof Editable) { 141 return (Editable) text; 142 } 143 super.setText(text, BufferType.EDITABLE); 144 return (Editable) super.getText(); 145 } 146 147 @Override setText(CharSequence text, BufferType type)148 public void setText(CharSequence text, BufferType type) { 149 super.setText(text, BufferType.EDITABLE); 150 } 151 152 /** 153 * Convenience for {@link Selection#setSelection(Spannable, int, int)}. 154 */ setSelection(int start, int stop)155 public void setSelection(int start, int stop) { 156 Selection.setSelection(getText(), start, stop); 157 } 158 159 /** 160 * Convenience for {@link Selection#setSelection(Spannable, int)}. 161 */ setSelection(int index)162 public void setSelection(int index) { 163 Selection.setSelection(getText(), index); 164 } 165 166 /** 167 * Convenience for {@link Selection#selectAll}. 168 */ selectAll()169 public void selectAll() { 170 Selection.selectAll(getText()); 171 } 172 173 /** 174 * Convenience for {@link Selection#extendSelection}. 175 */ extendSelection(int index)176 public void extendSelection(int index) { 177 Selection.extendSelection(getText(), index); 178 } 179 180 /** 181 * Causes words in the text that are longer than the view's width to be ellipsized instead of 182 * broken in the middle. {@link TextUtils.TruncateAt#MARQUEE 183 * TextUtils.TruncateAt#MARQUEE} is not supported. 184 * 185 * @param ellipsis Type of ellipsis to be applied. 186 * @throws IllegalArgumentException When the value of <code>ellipsis</code> parameter is 187 * {@link TextUtils.TruncateAt#MARQUEE}. 188 * @see TextView#setEllipsize(TextUtils.TruncateAt) 189 */ 190 @Override setEllipsize(TextUtils.TruncateAt ellipsis)191 public void setEllipsize(TextUtils.TruncateAt ellipsis) { 192 if (ellipsis == TextUtils.TruncateAt.MARQUEE) { 193 throw new IllegalArgumentException("EditText cannot use the ellipsize mode " 194 + "TextUtils.TruncateAt.MARQUEE"); 195 } 196 super.setEllipsize(ellipsis); 197 } 198 199 @Override getAccessibilityClassName()200 public CharSequence getAccessibilityClassName() { 201 return EditText.class.getName(); 202 } 203 204 /** @hide */ 205 @Override supportsAutoSizeText()206 protected boolean supportsAutoSizeText() { 207 return false; 208 } 209 210 @Override onKeyShortcut(int keyCode, KeyEvent event)211 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 212 if (event.hasModifiers(KeyEvent.META_CTRL_ON)) { 213 // Handle Ctrl-only shortcuts. 214 switch (keyCode) { 215 case KeyEvent.KEYCODE_B: 216 if (mStyleShortcutsEnabled && hasSelection()) { 217 return onTextContextMenuItem(ID_BOLD); 218 } 219 break; 220 case KeyEvent.KEYCODE_I: 221 if (mStyleShortcutsEnabled && hasSelection()) { 222 return onTextContextMenuItem(ID_ITALIC); 223 } 224 break; 225 case KeyEvent.KEYCODE_U: 226 if (mStyleShortcutsEnabled && hasSelection()) { 227 return onTextContextMenuItem(ID_UNDERLINE); 228 } 229 break; 230 } 231 } 232 return super.onKeyShortcut(keyCode, event); 233 } 234 235 @Override onTextContextMenuItem(int id)236 public boolean onTextContextMenuItem(int id) { 237 // TODO: Move to switch-case once the resource ID is finalized. 238 if (id == ID_BOLD || id == ID_ITALIC || id == ID_UNDERLINE) { 239 return performStylingAction(id); 240 } 241 return super.onTextContextMenuItem(id); 242 } 243 performStylingAction(int actionId)244 private boolean performStylingAction(int actionId) { 245 final int selectionStart = getSelectionStart(); 246 final int selectionEnd = getSelectionEnd(); 247 if (selectionStart < 0 || selectionEnd < 0) { 248 return false; // There is no selection. 249 } 250 int min = Math.min(selectionStart, selectionEnd); 251 int max = Math.max(selectionStart, selectionEnd); 252 253 254 Spannable spannable = getText(); 255 if (actionId == ID_BOLD) { 256 return SpanUtils.toggleBold(spannable, min, max); 257 } else if (actionId == ID_ITALIC) { 258 return SpanUtils.toggleItalic(spannable, min, max); 259 } else if (actionId == ID_UNDERLINE) { 260 return SpanUtils.toggleUnderline(spannable, min, max); 261 } 262 263 return false; 264 } 265 266 /** 267 * Enables styls shortcuts, e.g. Ctrl+B for making text bold. 268 * 269 * @param enabled true for enabled, false for disabled. 270 */ setStyleShortcutsEnabled(boolean enabled)271 public void setStyleShortcutsEnabled(boolean enabled) { 272 mStyleShortcutsEnabled = enabled; 273 } 274 275 /** 276 * Return true if style shortcut is enabled, otherwise returns false. 277 * @return true if style shortcut is enabled, otherwise returns false. 278 */ isStyleShortcutEnabled()279 public boolean isStyleShortcutEnabled() { 280 return mStyleShortcutsEnabled; 281 } 282 } 283