The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2007 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 | |
Tor Norbye | 7b9c912 | 2013-05-30 16:48:33 -0700 | [diff] [blame] | 19 | import android.annotation.DrawableRes; |
Ralston Da Silva | f954e23 | 2019-03-11 15:11:01 -0700 | [diff] [blame] | 20 | import android.annotation.IntDef; |
Artur Satayev | ad9254c | 2019-12-10 17:47:54 +0000 | [diff] [blame] | 21 | import android.compat.annotation.UnsupportedAppUsage; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 22 | import android.content.Context; |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 23 | import android.content.res.Resources.Theme; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 24 | import android.content.res.TypedArray; |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 25 | import android.database.DataSetObserver; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 26 | import android.graphics.Rect; |
| 27 | import android.graphics.drawable.Drawable; |
Mathew Inwood | 8c854f8 | 2018-09-14 12:35:36 +0100 | [diff] [blame] | 28 | import android.os.Build; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 29 | import android.text.Editable; |
| 30 | import android.text.Selection; |
| 31 | import android.text.TextUtils; |
| 32 | import android.text.TextWatcher; |
| 33 | import android.util.AttributeSet; |
| 34 | import android.util.Log; |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 35 | import android.view.ContextThemeWrapper; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 36 | import android.view.KeyEvent; |
| 37 | import android.view.LayoutInflater; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 38 | import android.view.View; |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 39 | import android.view.ViewGroup.LayoutParams; |
Romain Guy | 374aaaed3 | 2009-07-14 15:11:59 -0700 | [diff] [blame] | 40 | import android.view.WindowManager; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 41 | import android.view.inputmethod.CompletionInfo; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 42 | import android.view.inputmethod.EditorInfo; |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 43 | import android.view.inputmethod.InputMethodManager; |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 44 | import android.view.inspector.InspectableProperty; |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 45 | |
Gilles Debunne | 688df79 | 2011-09-14 15:52:03 -0700 | [diff] [blame] | 46 | import com.android.internal.R; |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 47 | |
Ralston Da Silva | f954e23 | 2019-03-11 15:11:01 -0700 | [diff] [blame] | 48 | import java.lang.annotation.Retention; |
| 49 | import java.lang.annotation.RetentionPolicy; |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 50 | import java.lang.ref.WeakReference; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 51 | |
| 52 | /** |
| 53 | * <p>An editable text view that shows completion suggestions automatically |
| 54 | * while the user is typing. The list of suggestions is displayed in a drop |
| 55 | * down menu from which the user can choose an item to replace the content |
| 56 | * of the edit box with.</p> |
| 57 | * |
| 58 | * <p>The drop down can be dismissed at any time by pressing the back key or, |
| 59 | * if no item is selected in the drop down, by pressing the enter/dpad center |
| 60 | * key.</p> |
| 61 | * |
| 62 | * <p>The list of suggestions is obtained from a data adapter and appears |
| 63 | * only after a given number of characters defined by |
| 64 | * {@link #getThreshold() the threshold}.</p> |
| 65 | * |
| 66 | * <p>The following code snippet shows how to create a text view which suggests |
| 67 | * various countries names while the user is typing:</p> |
| 68 | * |
| 69 | * <pre class="prettyprint"> |
| 70 | * public class CountriesActivity extends Activity { |
| 71 | * protected void onCreate(Bundle icicle) { |
| 72 | * super.onCreate(icicle); |
| 73 | * setContentView(R.layout.countries); |
| 74 | * |
| 75 | * ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, |
| 76 | * android.R.layout.simple_dropdown_item_1line, COUNTRIES); |
| 77 | * AutoCompleteTextView textView = (AutoCompleteTextView) |
| 78 | * findViewById(R.id.countries_list); |
| 79 | * textView.setAdapter(adapter); |
| 80 | * } |
| 81 | * |
| 82 | * private static final String[] COUNTRIES = new String[] { |
| 83 | * "Belgium", "France", "Italy", "Germany", "Spain" |
| 84 | * }; |
| 85 | * } |
| 86 | * </pre> |
| 87 | * |
Scott Main | 4c359b7 | 2012-07-24 15:51:27 -0700 | [diff] [blame] | 88 | * <p>See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a> |
| 89 | * guide.</p> |
Scott Main | 41ec653 | 2010-08-19 16:57:07 -0700 | [diff] [blame] | 90 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 91 | * @attr ref android.R.styleable#AutoCompleteTextView_completionHint |
| 92 | * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold |
| 93 | * @attr ref android.R.styleable#AutoCompleteTextView_completionHintView |
| 94 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector |
| 95 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor |
| 96 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 97 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight |
Alan Viverette | 40ce070 | 2014-08-28 15:27:04 -0700 | [diff] [blame] | 98 | * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset |
| 99 | * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 100 | */ |
| 101 | public class AutoCompleteTextView extends EditText implements Filter.FilterListener { |
| 102 | static final boolean DEBUG = false; |
| 103 | static final String TAG = "AutoCompleteTextView"; |
| 104 | |
Adam Powell | 348e69c | 2011-02-16 16:49:50 -0800 | [diff] [blame] | 105 | static final int EXPAND_MAX = 3; |
| 106 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 107 | /** Context used to inflate the popup window or dialog. */ |
| 108 | private final Context mPopupContext; |
| 109 | |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 110 | @UnsupportedAppUsage |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 111 | private final ListPopupWindow mPopup; |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 112 | @UnsupportedAppUsage |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 113 | private final PassThroughClickListener mPassThroughClickListener; |
| 114 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 115 | private CharSequence mHintText; |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 116 | @UnsupportedAppUsage |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 117 | private TextView mHintView; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 118 | private int mHintResource; |
| 119 | |
| 120 | private ListAdapter mAdapter; |
| 121 | private Filter mFilter; |
| 122 | private int mThreshold; |
| 123 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 124 | private int mDropDownAnchorId; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 125 | |
| 126 | private AdapterView.OnItemClickListener mItemClickListener; |
| 127 | private AdapterView.OnItemSelectedListener mItemSelectedListener; |
| 128 | |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 129 | private boolean mDropDownDismissedOnCompletion = true; |
| 130 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 131 | private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 132 | private MyWatcher mAutoCompleteTextWatcher; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 133 | |
| 134 | private Validator mValidator = null; |
| 135 | |
Gilles Debunne | be2c4f9 | 2011-01-17 15:14:32 -0800 | [diff] [blame] | 136 | // Set to true when text is set directly and no filtering shall be performed |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 137 | private boolean mBlockCompletion; |
| 138 | |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 139 | // When set, an update in the underlying adapter will update the result list popup. |
| 140 | // Set to false when the list is hidden to prevent asynchronous updates to popup the list again. |
| 141 | private boolean mPopupCanBeUpdated = true; |
| 142 | |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 143 | @UnsupportedAppUsage |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 144 | private PopupDataSetObserver mObserver; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 145 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 146 | /** |
| 147 | * Constructs a new auto-complete text view with the given context's theme. |
| 148 | * |
| 149 | * @param context The Context the view is running in, through which it can |
| 150 | * access the current theme, resources, etc. |
| 151 | */ |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 152 | public AutoCompleteTextView(Context context) { |
| 153 | this(context, null); |
| 154 | } |
| 155 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 156 | /** |
| 157 | * Constructs a new auto-complete text view with the given context's theme |
| 158 | * and the supplied attribute set. |
| 159 | * |
| 160 | * @param context The Context the view is running in, through which it can |
| 161 | * access the current theme, resources, etc. |
| 162 | * @param attrs The attributes of the XML tag that is inflating the view. |
| 163 | */ |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 164 | public AutoCompleteTextView(Context context, AttributeSet attrs) { |
Alan Viverette | f023c25 | 2014-08-28 13:55:18 -0700 | [diff] [blame] | 165 | this(context, attrs, R.attr.autoCompleteTextViewStyle); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 166 | } |
| 167 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 168 | /** |
| 169 | * Constructs a new auto-complete text view with the given context's theme, |
| 170 | * the supplied attribute set, and default style attribute. |
| 171 | * |
| 172 | * @param context The Context the view is running in, through which it can |
| 173 | * access the current theme, resources, etc. |
| 174 | * @param attrs The attributes of the XML tag that is inflating the view. |
| 175 | * @param defStyleAttr An attribute in the current theme that contains a |
| 176 | * reference to a style resource that supplies default |
| 177 | * values for the view. Can be 0 to not look for |
| 178 | * defaults. |
| 179 | */ |
Alan Viverette | 617feb9 | 2013-09-09 18:09:13 -0700 | [diff] [blame] | 180 | public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) { |
| 181 | this(context, attrs, defStyleAttr, 0); |
| 182 | } |
| 183 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 184 | /** |
| 185 | * Constructs a new auto-complete text view with the given context's theme, |
| 186 | * the supplied attribute set, and default styles. |
| 187 | * |
| 188 | * @param context The Context the view is running in, through which it can |
| 189 | * access the current theme, resources, etc. |
| 190 | * @param attrs The attributes of the XML tag that is inflating the view. |
| 191 | * @param defStyleAttr An attribute in the current theme that contains a |
| 192 | * reference to a style resource that supplies default |
| 193 | * values for the view. Can be 0 to not look for |
| 194 | * defaults. |
| 195 | * @param defStyleRes A resource identifier of a style resource that |
| 196 | * supplies default values for the view, used only if |
| 197 | * defStyleAttr is 0 or can not be found in the theme. |
| 198 | * Can be 0 to not look for defaults. |
| 199 | */ |
Alan Viverette | 617feb9 | 2013-09-09 18:09:13 -0700 | [diff] [blame] | 200 | public AutoCompleteTextView( |
| 201 | Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 202 | this(context, attrs, defStyleAttr, defStyleRes, null); |
| 203 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 204 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 205 | /** |
| 206 | * Constructs a new auto-complete text view with the given context, the |
| 207 | * supplied attribute set, default styles, and the theme against which the |
| 208 | * completion popup should be inflated. |
| 209 | * |
| 210 | * @param context The context against which the view is inflated, which |
| 211 | * provides access to the current theme, resources, etc. |
| 212 | * @param attrs The attributes of the XML tag that is inflating the view. |
| 213 | * @param defStyleAttr An attribute in the current theme that contains a |
| 214 | * reference to a style resource that supplies default |
| 215 | * values for the view. Can be 0 to not look for |
| 216 | * defaults. |
| 217 | * @param defStyleRes A resource identifier of a style resource that |
| 218 | * supplies default values for the view, used only if |
| 219 | * defStyleAttr is 0 or can not be found in the theme. |
| 220 | * Can be 0 to not look for defaults. |
| 221 | * @param popupTheme The theme against which the completion popup window |
| 222 | * should be inflated. May be {@code null} to use the |
| 223 | * view theme. If set, this will override any value |
| 224 | * specified by |
| 225 | * {@link android.R.styleable#AutoCompleteTextView_popupTheme}. |
| 226 | */ |
| 227 | public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr, |
| 228 | int defStyleRes, Theme popupTheme) { |
| 229 | super(context, attrs, defStyleAttr, defStyleRes); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 230 | |
Alan Viverette | f023c25 | 2014-08-28 13:55:18 -0700 | [diff] [blame] | 231 | final TypedArray a = context.obtainStyledAttributes( |
| 232 | attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes); |
Aurimas Liutikas | ab324cf | 2019-02-07 16:46:38 -0800 | [diff] [blame] | 233 | saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView, |
| 234 | attrs, a, defStyleAttr, defStyleRes); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 235 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 236 | if (popupTheme != null) { |
| 237 | mPopupContext = new ContextThemeWrapper(context, popupTheme); |
| 238 | } else { |
| 239 | final int popupThemeResId = a.getResourceId( |
| 240 | R.styleable.AutoCompleteTextView_popupTheme, 0); |
| 241 | if (popupThemeResId != 0) { |
| 242 | mPopupContext = new ContextThemeWrapper(context, popupThemeResId); |
| 243 | } else { |
| 244 | mPopupContext = context; |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | // Load attributes used within the popup against the popup context. |
| 249 | final TypedArray pa; |
| 250 | if (mPopupContext != context) { |
| 251 | pa = mPopupContext.obtainStyledAttributes( |
| 252 | attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes); |
Aurimas Liutikas | ab324cf | 2019-02-07 16:46:38 -0800 | [diff] [blame] | 253 | saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView, |
| 254 | attrs, a, defStyleAttr, defStyleRes); |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 255 | } else { |
| 256 | pa = a; |
| 257 | } |
| 258 | |
| 259 | final Drawable popupListSelector = pa.getDrawable( |
| 260 | R.styleable.AutoCompleteTextView_dropDownSelector); |
| 261 | final int popupWidth = pa.getLayoutDimension( |
| 262 | R.styleable.AutoCompleteTextView_dropDownWidth, LayoutParams.WRAP_CONTENT); |
| 263 | final int popupHeight = pa.getLayoutDimension( |
| 264 | R.styleable.AutoCompleteTextView_dropDownHeight, LayoutParams.WRAP_CONTENT); |
| 265 | final int popupHintLayoutResId = pa.getResourceId( |
| 266 | R.styleable.AutoCompleteTextView_completionHintView, R.layout.simple_dropdown_hint); |
| 267 | final CharSequence popupHintText = pa.getText( |
| 268 | R.styleable.AutoCompleteTextView_completionHint); |
| 269 | |
| 270 | if (pa != a) { |
| 271 | pa.recycle(); |
| 272 | } |
| 273 | |
| 274 | mPopup = new ListPopupWindow(mPopupContext, attrs, defStyleAttr, defStyleRes); |
| 275 | mPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); |
| 276 | mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW); |
| 277 | mPopup.setListSelector(popupListSelector); |
| 278 | mPopup.setOnItemClickListener(new DropDownItemClickListener()); |
| 279 | |
| 280 | // For dropdown width, the developer can specify a specific width, or |
| 281 | // MATCH_PARENT (for full screen width), or WRAP_CONTENT (to match the |
| 282 | // width of the anchored view). |
| 283 | mPopup.setWidth(popupWidth); |
| 284 | mPopup.setHeight(popupHeight); |
| 285 | |
| 286 | // Completion hint must be set after specifying hint layout. |
| 287 | mHintResource = popupHintLayoutResId; |
| 288 | setCompletionHint(popupHintText); |
| 289 | |
| 290 | // Get the anchor's id now, but the view won't be ready, so wait to |
| 291 | // actually get the view and store it in mDropDownAnchorView lazily in |
| 292 | // getDropDownAnchorView later. Defaults to NO_ID, in which case the |
| 293 | // getDropDownAnchorView method will simply return this TextView, as a |
| 294 | // default anchoring point. |
| 295 | mDropDownAnchorId = a.getResourceId( |
| 296 | R.styleable.AutoCompleteTextView_dropDownAnchor, View.NO_ID); |
| 297 | |
Alan Viverette | f023c25 | 2014-08-28 13:55:18 -0700 | [diff] [blame] | 298 | mThreshold = a.getInt(R.styleable.AutoCompleteTextView_completionThreshold, 2); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 299 | |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 300 | a.recycle(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 301 | |
| 302 | // Always turn on the auto complete input type flag, since it |
| 303 | // makes no sense to use this widget without it. |
| 304 | int inputType = getInputType(); |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 305 | if ((inputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 306 | inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; |
| 307 | setRawInputType(inputType); |
| 308 | } |
| 309 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 310 | setFocusable(true); |
| 311 | |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 312 | mAutoCompleteTextWatcher = new MyWatcher(); |
| 313 | addTextChangedListener(mAutoCompleteTextWatcher); |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 314 | |
Karl Rosaen | 98e333f | 2009-04-28 10:39:09 -0700 | [diff] [blame] | 315 | mPassThroughClickListener = new PassThroughClickListener(); |
| 316 | super.setOnClickListener(mPassThroughClickListener); |
| 317 | } |
| 318 | |
| 319 | @Override |
| 320 | public void setOnClickListener(OnClickListener listener) { |
| 321 | mPassThroughClickListener.mWrapped = listener; |
| 322 | } |
| 323 | |
| 324 | /** |
| 325 | * Private hook into the on click event, dispatched from {@link PassThroughClickListener} |
| 326 | */ |
| 327 | private void onClickImpl() { |
Amith Yamasani | d25eb35 | 2010-03-10 21:09:28 -0800 | [diff] [blame] | 328 | // If the dropdown is showing, bring the keyboard to the front |
| 329 | // when the user touches the text field. |
Gilles Debunne | 711734a | 2011-02-07 18:26:11 -0800 | [diff] [blame] | 330 | if (isPopupShowing()) { |
Amith Yamasani | d25eb35 | 2010-03-10 21:09:28 -0800 | [diff] [blame] | 331 | ensureImeVisible(true); |
Karl Rosaen | 98e333f | 2009-04-28 10:39:09 -0700 | [diff] [blame] | 332 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 336 | * <p>Sets the optional hint text that is displayed at the bottom of the |
| 337 | * the matching list. This can be used as a cue to the user on how to |
| 338 | * best use the list, or to provide extra information.</p> |
| 339 | * |
| 340 | * @param hint the text to be displayed to the user |
| 341 | * |
Gilles Debunne | 5c49d11 | 2012-04-30 16:44:14 -0700 | [diff] [blame] | 342 | * @see #getCompletionHint() |
| 343 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 344 | * @attr ref android.R.styleable#AutoCompleteTextView_completionHint |
| 345 | */ |
| 346 | public void setCompletionHint(CharSequence hint) { |
| 347 | mHintText = hint; |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 348 | if (hint != null) { |
| 349 | if (mHintView == null) { |
Alan Viverette | da6b2f6 | 2015-08-12 11:26:15 -0400 | [diff] [blame] | 350 | final TextView hintView = (TextView) LayoutInflater.from(mPopupContext).inflate( |
| 351 | mHintResource, null).findViewById(R.id.text1); |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 352 | hintView.setText(mHintText); |
| 353 | mHintView = hintView; |
| 354 | mPopup.setPromptView(hintView); |
| 355 | } else { |
| 356 | mHintView.setText(hint); |
| 357 | } |
| 358 | } else { |
| 359 | mPopup.setPromptView(null); |
| 360 | mHintView = null; |
| 361 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 362 | } |
Gilles Debunne | 5c49d11 | 2012-04-30 16:44:14 -0700 | [diff] [blame] | 363 | |
| 364 | /** |
| 365 | * Gets the optional hint text displayed at the bottom of the the matching list. |
| 366 | * |
| 367 | * @return The hint text, if any |
| 368 | * |
| 369 | * @see #setCompletionHint(CharSequence) |
| 370 | * |
| 371 | * @attr ref android.R.styleable#AutoCompleteTextView_completionHint |
| 372 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 373 | @InspectableProperty |
Gilles Debunne | 5c49d11 | 2012-04-30 16:44:14 -0700 | [diff] [blame] | 374 | public CharSequence getCompletionHint() { |
| 375 | return mHintText; |
| 376 | } |
| 377 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 378 | /** |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 379 | * Returns the current width for the auto-complete drop down list. |
| 380 | * |
| 381 | * This can be a fixed width, or {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} |
| 382 | * to fill the screen, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} |
| 383 | * to fit the width of its anchor view. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 384 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 385 | * @return the width for the drop down list |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 386 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 387 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 388 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 389 | @InspectableProperty |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 390 | public int getDropDownWidth() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 391 | return mPopup.getWidth(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 392 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 393 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 394 | /** |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 395 | * Sets the current width for the auto-complete drop down list. |
| 396 | * |
| 397 | * This can be a fixed width, or {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} |
| 398 | * to fill the screen, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} |
| 399 | * to fit the width of its anchor view. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 400 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 401 | * @param width the width to use |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 402 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 403 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 404 | */ |
| 405 | public void setDropDownWidth(int width) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 406 | mPopup.setWidth(width); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 407 | } |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 408 | |
| 409 | /** |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 410 | * <p>Returns the current height for the auto-complete drop down list. |
| 411 | * |
| 412 | * This can be a fixed width, or {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} |
| 413 | * to fill the screen, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} |
| 414 | * to fit the width of its anchor view. |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 415 | * |
| 416 | * @return the height for the drop down list |
| 417 | * |
| 418 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight |
| 419 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 420 | @InspectableProperty |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 421 | public int getDropDownHeight() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 422 | return mPopup.getHeight(); |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 423 | } |
| 424 | |
| 425 | /** |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 426 | * Sets the current height for the auto-complete drop down list. |
| 427 | * |
| 428 | * This can be a fixed width, or {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} |
| 429 | * to fill the screen, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} |
| 430 | * to fit the width of its anchor view. |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 431 | * |
| 432 | * @param height the height to use |
| 433 | * |
| 434 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight |
| 435 | */ |
| 436 | public void setDropDownHeight(int height) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 437 | mPopup.setHeight(height); |
Romain Guy | e29f064 | 2009-06-23 21:27:02 -0700 | [diff] [blame] | 438 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 439 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 440 | /** |
| 441 | * <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 442 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 443 | * @return the view's id, or {@link View#NO_ID} if none specified |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 444 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 445 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 446 | */ |
| 447 | public int getDropDownAnchor() { |
| 448 | return mDropDownAnchorId; |
| 449 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 450 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 451 | /** |
| 452 | * <p>Sets the view to which the auto-complete drop down list should anchor. The view |
| 453 | * corresponding to this id will not be loaded until the next time it is needed to avoid |
| 454 | * loading a view which is not yet instantiated.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 455 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 456 | * @param id the id to anchor the drop down list view to |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 457 | * |
| 458 | * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 459 | */ |
| 460 | public void setDropDownAnchor(int id) { |
| 461 | mDropDownAnchorId = id; |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 462 | mPopup.setAnchorView(null); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 463 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 464 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 465 | /** |
| 466 | * <p>Gets the background of the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 467 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 468 | * @return the background drawable |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 469 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 470 | * @attr ref android.R.styleable#PopupWindow_popupBackground |
| 471 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 472 | @InspectableProperty(name = "popupBackground") |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 473 | public Drawable getDropDownBackground() { |
| 474 | return mPopup.getBackground(); |
| 475 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 476 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 477 | /** |
| 478 | * <p>Sets the background of the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 479 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 480 | * @param d the drawable to set as the background |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 481 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 482 | * @attr ref android.R.styleable#PopupWindow_popupBackground |
| 483 | */ |
| 484 | public void setDropDownBackgroundDrawable(Drawable d) { |
| 485 | mPopup.setBackgroundDrawable(d); |
| 486 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 487 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 488 | /** |
| 489 | * <p>Sets the background of the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 490 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 491 | * @param id the id of the drawable to set as the background |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 492 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 493 | * @attr ref android.R.styleable#PopupWindow_popupBackground |
| 494 | */ |
Tor Norbye | 7b9c912 | 2013-05-30 16:48:33 -0700 | [diff] [blame] | 495 | public void setDropDownBackgroundResource(@DrawableRes int id) { |
Alan Viverette | 8eea3ea | 2014-02-03 18:40:20 -0800 | [diff] [blame] | 496 | mPopup.setBackgroundDrawable(getContext().getDrawable(id)); |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 497 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 498 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 499 | /** |
| 500 | * <p>Sets the vertical offset used for the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 501 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 502 | * @param offset the vertical offset |
Alan Viverette | 40ce070 | 2014-08-28 15:27:04 -0700 | [diff] [blame] | 503 | * |
| 504 | * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 505 | */ |
| 506 | public void setDropDownVerticalOffset(int offset) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 507 | mPopup.setVerticalOffset(offset); |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 508 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 509 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 510 | /** |
| 511 | * <p>Gets the vertical offset used for the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 512 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 513 | * @return the vertical offset |
Alan Viverette | 40ce070 | 2014-08-28 15:27:04 -0700 | [diff] [blame] | 514 | * |
| 515 | * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 516 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 517 | @InspectableProperty |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 518 | public int getDropDownVerticalOffset() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 519 | return mPopup.getVerticalOffset(); |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 520 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 521 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 522 | /** |
| 523 | * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 524 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 525 | * @param offset the horizontal offset |
Alan Viverette | 40ce070 | 2014-08-28 15:27:04 -0700 | [diff] [blame] | 526 | * |
| 527 | * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 528 | */ |
| 529 | public void setDropDownHorizontalOffset(int offset) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 530 | mPopup.setHorizontalOffset(offset); |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 531 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 532 | |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 533 | /** |
| 534 | * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 535 | * |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 536 | * @return the horizontal offset |
Alan Viverette | 40ce070 | 2014-08-28 15:27:04 -0700 | [diff] [blame] | 537 | * |
| 538 | * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 539 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 540 | @InspectableProperty |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 541 | public int getDropDownHorizontalOffset() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 542 | return mPopup.getHorizontalOffset(); |
The Android Open Source Project | 7b0b1ed | 2009-03-18 22:20:26 -0700 | [diff] [blame] | 543 | } |
The Android Open Source Project | 8f080ec | 2009-04-29 13:34:51 -0700 | [diff] [blame] | 544 | |
The Android Open Source Project | bff1389 | 2009-04-29 13:41:02 -0700 | [diff] [blame] | 545 | /** |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 546 | * <p>Sets the animation style of the auto-complete drop-down list.</p> |
| 547 | * |
| 548 | * <p>If the drop-down is showing, calling this method will take effect only |
| 549 | * the next time the drop-down is shown.</p> |
| 550 | * |
| 551 | * @param animationStyle animation style to use when the drop-down appears |
| 552 | * and disappears. Set to -1 for the default animation, 0 for no |
| 553 | * animation, or a resource identifier for an explicit animation. |
| 554 | * |
| 555 | * @hide Pending API council approval |
| 556 | */ |
Mathew Inwood | 8c854f8 | 2018-09-14 12:35:36 +0100 | [diff] [blame] | 557 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 558 | public void setDropDownAnimationStyle(int animationStyle) { |
| 559 | mPopup.setAnimationStyle(animationStyle); |
| 560 | } |
| 561 | |
| 562 | /** |
| 563 | * <p>Returns the animation style that is used when the drop-down list appears and disappears |
| 564 | * </p> |
| 565 | * |
| 566 | * @return the animation style that is used when the drop-down list appears and disappears |
| 567 | * |
| 568 | * @hide Pending API council approval |
| 569 | */ |
| 570 | public int getDropDownAnimationStyle() { |
| 571 | return mPopup.getAnimationStyle(); |
| 572 | } |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 573 | |
| 574 | /** |
| 575 | * @return Whether the drop-down is visible as long as there is {@link #enoughToFilter()} |
| 576 | * |
| 577 | * @hide Pending API council approval |
| 578 | */ |
| 579 | public boolean isDropDownAlwaysVisible() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 580 | return mPopup.isDropDownAlwaysVisible(); |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 581 | } |
| 582 | |
| 583 | /** |
| 584 | * Sets whether the drop-down should remain visible as long as there is there is |
| 585 | * {@link #enoughToFilter()}. This is useful if an unknown number of results are expected |
| 586 | * to show up in the adapter sometime in the future. |
| 587 | * |
| 588 | * The drop-down will occupy the entire screen below {@link #getDropDownAnchor} regardless |
| 589 | * of the size or content of the list. {@link #getDropDownBackground()} will fill any space |
| 590 | * that is not used by the list. |
| 591 | * |
| 592 | * @param dropDownAlwaysVisible Whether to keep the drop-down visible. |
| 593 | * |
| 594 | * @hide Pending API council approval |
| 595 | */ |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 596 | @UnsupportedAppUsage |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 597 | public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 598 | mPopup.setDropDownAlwaysVisible(dropDownAlwaysVisible); |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 599 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 600 | |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 601 | /** |
| 602 | * Checks whether the drop-down is dismissed when a suggestion is clicked. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 603 | * |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 604 | * @hide Pending API council approval |
| 605 | */ |
| 606 | public boolean isDropDownDismissedOnCompletion() { |
| 607 | return mDropDownDismissedOnCompletion; |
| 608 | } |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 609 | |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 610 | /** |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 611 | * Sets whether the drop-down is dismissed when a suggestion is clicked. This is |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 612 | * true by default. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 613 | * |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 614 | * @param dropDownDismissedOnCompletion Whether to dismiss the drop-down. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 615 | * |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 616 | * @hide Pending API council approval |
| 617 | */ |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 618 | @UnsupportedAppUsage |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 619 | public void setDropDownDismissedOnCompletion(boolean dropDownDismissedOnCompletion) { |
| 620 | mDropDownDismissedOnCompletion = dropDownDismissedOnCompletion; |
| 621 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 622 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 623 | /** |
| 624 | * <p>Returns the number of characters the user must type before the drop |
| 625 | * down list is shown.</p> |
| 626 | * |
| 627 | * @return the minimum number of characters to type to show the drop down |
| 628 | * |
| 629 | * @see #setThreshold(int) |
Gilles Debunne | 5c49d11 | 2012-04-30 16:44:14 -0700 | [diff] [blame] | 630 | * |
| 631 | * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 632 | */ |
Ashley Rose | 55f9f92 | 2019-01-28 19:29:36 -0500 | [diff] [blame] | 633 | @InspectableProperty(name = "completionThreshold") |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 634 | public int getThreshold() { |
| 635 | return mThreshold; |
| 636 | } |
| 637 | |
| 638 | /** |
| 639 | * <p>Specifies the minimum number of characters the user has to type in the |
| 640 | * edit box before the drop down list is shown.</p> |
| 641 | * |
| 642 | * <p>When <code>threshold</code> is less than or equals 0, a threshold of |
| 643 | * 1 is applied.</p> |
| 644 | * |
| 645 | * @param threshold the number of characters to type before the drop down |
| 646 | * is shown |
| 647 | * |
| 648 | * @see #getThreshold() |
| 649 | * |
| 650 | * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold |
| 651 | */ |
| 652 | public void setThreshold(int threshold) { |
| 653 | if (threshold <= 0) { |
| 654 | threshold = 1; |
| 655 | } |
| 656 | |
| 657 | mThreshold = threshold; |
| 658 | } |
| 659 | |
| 660 | /** |
| 661 | * <p>Sets the listener that will be notified when the user clicks an item |
| 662 | * in the drop down list.</p> |
| 663 | * |
| 664 | * @param l the item click listener |
| 665 | */ |
| 666 | public void setOnItemClickListener(AdapterView.OnItemClickListener l) { |
| 667 | mItemClickListener = l; |
| 668 | } |
| 669 | |
| 670 | /** |
| 671 | * <p>Sets the listener that will be notified when the user selects an item |
| 672 | * in the drop down list.</p> |
| 673 | * |
| 674 | * @param l the item selected listener |
| 675 | */ |
| 676 | public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener l) { |
| 677 | mItemSelectedListener = l; |
| 678 | } |
| 679 | |
| 680 | /** |
| 681 | * <p>Returns the listener that is notified whenever the user clicks an item |
| 682 | * in the drop down list.</p> |
| 683 | * |
| 684 | * @return the item click listener |
| 685 | * |
| 686 | * @deprecated Use {@link #getOnItemClickListener()} intead |
| 687 | */ |
| 688 | @Deprecated |
| 689 | public AdapterView.OnItemClickListener getItemClickListener() { |
| 690 | return mItemClickListener; |
| 691 | } |
| 692 | |
| 693 | /** |
| 694 | * <p>Returns the listener that is notified whenever the user selects an |
| 695 | * item in the drop down list.</p> |
| 696 | * |
| 697 | * @return the item selected listener |
| 698 | * |
| 699 | * @deprecated Use {@link #getOnItemSelectedListener()} intead |
| 700 | */ |
| 701 | @Deprecated |
| 702 | public AdapterView.OnItemSelectedListener getItemSelectedListener() { |
| 703 | return mItemSelectedListener; |
| 704 | } |
| 705 | |
| 706 | /** |
| 707 | * <p>Returns the listener that is notified whenever the user clicks an item |
| 708 | * in the drop down list.</p> |
| 709 | * |
| 710 | * @return the item click listener |
| 711 | */ |
| 712 | public AdapterView.OnItemClickListener getOnItemClickListener() { |
| 713 | return mItemClickListener; |
| 714 | } |
| 715 | |
| 716 | /** |
| 717 | * <p>Returns the listener that is notified whenever the user selects an |
| 718 | * item in the drop down list.</p> |
| 719 | * |
| 720 | * @return the item selected listener |
| 721 | */ |
| 722 | public AdapterView.OnItemSelectedListener getOnItemSelectedListener() { |
| 723 | return mItemSelectedListener; |
| 724 | } |
| 725 | |
| 726 | /** |
Adam Powell | 780c491 | 2012-08-30 17:30:05 -0700 | [diff] [blame] | 727 | * Set a listener that will be invoked whenever the AutoCompleteTextView's |
| 728 | * list of completions is dismissed. |
| 729 | * @param dismissListener Listener to invoke when completions are dismissed |
| 730 | */ |
| 731 | public void setOnDismissListener(final OnDismissListener dismissListener) { |
| 732 | PopupWindow.OnDismissListener wrappedListener = null; |
| 733 | if (dismissListener != null) { |
| 734 | wrappedListener = new PopupWindow.OnDismissListener() { |
| 735 | @Override public void onDismiss() { |
| 736 | dismissListener.onDismiss(); |
| 737 | } |
| 738 | }; |
| 739 | } |
| 740 | mPopup.setOnDismissListener(wrappedListener); |
| 741 | } |
| 742 | |
| 743 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 744 | * <p>Returns a filterable list adapter used for auto completion.</p> |
| 745 | * |
| 746 | * @return a data adapter used for auto completion |
| 747 | */ |
| 748 | public ListAdapter getAdapter() { |
| 749 | return mAdapter; |
| 750 | } |
| 751 | |
| 752 | /** |
| 753 | * <p>Changes the list of data used for auto completion. The provided list |
| 754 | * must be a filterable list adapter.</p> |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 755 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 756 | * <p>The caller is still responsible for managing any resources used by the adapter. |
| 757 | * Notably, when the AutoCompleteTextView is closed or released, the adapter is not notified. |
| 758 | * A common case is the use of {@link android.widget.CursorAdapter}, which |
| 759 | * contains a {@link android.database.Cursor} that must be closed. This can be done |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 760 | * automatically (see |
| 761 | * {@link android.app.Activity#startManagingCursor(android.database.Cursor) |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 762 | * startManagingCursor()}), |
| 763 | * or by manually closing the cursor when the AutoCompleteTextView is dismissed.</p> |
| 764 | * |
| 765 | * @param adapter the adapter holding the auto completion data |
| 766 | * |
| 767 | * @see #getAdapter() |
| 768 | * @see android.widget.Filterable |
| 769 | * @see android.widget.ListAdapter |
| 770 | */ |
| 771 | public <T extends ListAdapter & Filterable> void setAdapter(T adapter) { |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 772 | if (mObserver == null) { |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 773 | mObserver = new PopupDataSetObserver(this); |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 774 | } else if (mAdapter != null) { |
| 775 | mAdapter.unregisterDataSetObserver(mObserver); |
| 776 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 777 | mAdapter = adapter; |
| 778 | if (mAdapter != null) { |
| 779 | //noinspection unchecked |
| 780 | mFilter = ((Filterable) mAdapter).getFilter(); |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 781 | adapter.registerDataSetObserver(mObserver); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 782 | } else { |
| 783 | mFilter = null; |
| 784 | } |
| 785 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 786 | mPopup.setAdapter(mAdapter); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 787 | } |
| 788 | |
| 789 | @Override |
| 790 | public boolean onKeyPreIme(int keyCode, KeyEvent event) { |
Dianne Hackborn | 8d37426 | 2009-09-14 21:21:52 -0700 | [diff] [blame] | 791 | if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing() |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 792 | && !mPopup.isDropDownAlwaysVisible()) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 793 | // special case for the back key, we do not even try to send it |
| 794 | // to the drop down list but instead, consume it immediately |
Romain Guy | 2beee4d | 2010-03-15 17:18:22 -0700 | [diff] [blame] | 795 | if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { |
Jeff Brown | b3ea922 | 2011-01-10 16:26:36 -0800 | [diff] [blame] | 796 | KeyEvent.DispatcherState state = getKeyDispatcherState(); |
| 797 | if (state != null) { |
| 798 | state.startTracking(event, this); |
| 799 | } |
Dianne Hackborn | 8d37426 | 2009-09-14 21:21:52 -0700 | [diff] [blame] | 800 | return true; |
Bjorn Bringert | 4eb3efc | 2009-10-06 09:26:06 +0100 | [diff] [blame] | 801 | } else if (event.getAction() == KeyEvent.ACTION_UP) { |
Jeff Brown | b3ea922 | 2011-01-10 16:26:36 -0800 | [diff] [blame] | 802 | KeyEvent.DispatcherState state = getKeyDispatcherState(); |
| 803 | if (state != null) { |
| 804 | state.handleUpEvent(event); |
| 805 | } |
Bjorn Bringert | 4eb3efc | 2009-10-06 09:26:06 +0100 | [diff] [blame] | 806 | if (event.isTracking() && !event.isCanceled()) { |
| 807 | dismissDropDown(); |
| 808 | return true; |
| 809 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 810 | } |
| 811 | } |
| 812 | return super.onKeyPreIme(keyCode, event); |
| 813 | } |
| 814 | |
| 815 | @Override |
| 816 | public boolean onKeyUp(int keyCode, KeyEvent event) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 817 | boolean consumed = mPopup.onKeyUp(keyCode, event); |
| 818 | if (consumed) { |
| 819 | switch (keyCode) { |
| 820 | // if the list accepts the key events and the key event |
| 821 | // was a click, the text view gets the selected item |
| 822 | // from the drop down as its content |
| 823 | case KeyEvent.KEYCODE_ENTER: |
| 824 | case KeyEvent.KEYCODE_DPAD_CENTER: |
Jeff Brown | 4e6319b | 2010-12-13 10:36:51 -0800 | [diff] [blame] | 825 | case KeyEvent.KEYCODE_TAB: |
| 826 | if (event.hasNoModifiers()) { |
| 827 | performCompletion(); |
| 828 | } |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 829 | return true; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 830 | } |
| 831 | } |
Gilles Debunne | a4a5758 | 2011-02-08 18:21:01 -0800 | [diff] [blame] | 832 | |
| 833 | if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) { |
| 834 | performCompletion(); |
| 835 | return true; |
| 836 | } |
| 837 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 838 | return super.onKeyUp(keyCode, event); |
| 839 | } |
| 840 | |
| 841 | @Override |
| 842 | public boolean onKeyDown(int keyCode, KeyEvent event) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 843 | if (mPopup.onKeyDown(keyCode, event)) { |
| 844 | return true; |
| 845 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 846 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 847 | if (!isPopupShowing()) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 848 | switch(keyCode) { |
| 849 | case KeyEvent.KEYCODE_DPAD_DOWN: |
Jeff Brown | 4e6319b | 2010-12-13 10:36:51 -0800 | [diff] [blame] | 850 | if (event.hasNoModifiers()) { |
| 851 | performValidation(); |
| 852 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 853 | } |
| 854 | } |
| 855 | |
Gilles Debunne | a4a5758 | 2011-02-08 18:21:01 -0800 | [diff] [blame] | 856 | if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) { |
| 857 | return true; |
| 858 | } |
| 859 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 860 | mLastKeyCode = keyCode; |
| 861 | boolean handled = super.onKeyDown(keyCode, event); |
| 862 | mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; |
| 863 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 864 | if (handled && isPopupShowing()) { |
The Android Open Source Project | c39a6e0 | 2009-03-11 12:11:56 -0700 | [diff] [blame] | 865 | clearListSelection(); |
| 866 | } |
| 867 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 868 | return handled; |
| 869 | } |
| 870 | |
| 871 | /** |
| 872 | * Returns <code>true</code> if the amount of text in the field meets |
| 873 | * or exceeds the {@link #getThreshold} requirement. You can override |
| 874 | * this to impose a different standard for when filtering will be |
| 875 | * triggered. |
| 876 | */ |
| 877 | public boolean enoughToFilter() { |
| 878 | if (DEBUG) Log.v(TAG, "Enough to filter: len=" + getText().length() |
| 879 | + " threshold=" + mThreshold); |
| 880 | return getText().length() >= mThreshold; |
| 881 | } |
| 882 | |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 883 | |
| 884 | |
| 885 | /** This is used to watch for edits to the text view. */ |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 886 | private class MyWatcher implements TextWatcher { |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 887 | private boolean mOpenBefore; |
| 888 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 889 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 890 | if (mBlockCompletion) return; |
| 891 | |
| 892 | // when text is changed, inserted or deleted, we attempt to show |
| 893 | // the drop down |
| 894 | mOpenBefore = isPopupShowing(); |
| 895 | if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 896 | } |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 897 | |
| 898 | public void afterTextChanged(Editable s) { |
| 899 | if (mBlockCompletion) return; |
| 900 | |
| 901 | // if the list was open before the keystroke, but closed afterwards, |
| 902 | // then something in the keystroke processing (an input filter perhaps) |
| 903 | // called performCompletion() and we shouldn't do any more processing. |
| 904 | if (DEBUG) { |
| 905 | Log.v(TAG, "after text changed: openBefore=" + mOpenBefore |
| 906 | + " open=" + isPopupShowing()); |
| 907 | } |
| 908 | |
| 909 | if (mOpenBefore && !isPopupShowing()) return; |
| 910 | |
| 911 | refreshAutoCompleteResults(); |
| 912 | } |
| 913 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 914 | public void onTextChanged(CharSequence s, int start, int before, int count) { |
| 915 | } |
| 916 | } |
| 917 | |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 918 | /** |
| 919 | * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead. |
| 920 | * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function. |
| 921 | */ |
| 922 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 923 | void doBeforeTextChanged() { |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 924 | mAutoCompleteTextWatcher.beforeTextChanged(null, 0, 0, 0); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 925 | } |
| 926 | |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 927 | /** |
| 928 | * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead. |
| 929 | * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function. |
| 930 | */ |
| 931 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 932 | void doAfterTextChanged() { |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 933 | mAutoCompleteTextWatcher.afterTextChanged(null); |
| 934 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 935 | |
Ralston Da Silva | ccec37e | 2019-02-05 10:31:33 -0800 | [diff] [blame] | 936 | /** |
| 937 | * Refreshes the auto complete results. You usually shouldn't have to manually refresh the |
| 938 | * AutoCompleteResults as this is done automatically whenever the text changes. However if the |
| 939 | * results are not available and have to be fetched, you can call this function after fetching |
| 940 | * the results. |
| 941 | */ |
| 942 | public final void refreshAutoCompleteResults() { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 943 | // the drop down is shown only when a minimum number of characters |
| 944 | // was typed in the text view |
| 945 | if (enoughToFilter()) { |
| 946 | if (mFilter != null) { |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 947 | mPopupCanBeUpdated = true; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 948 | performFiltering(getText(), mLastKeyCode); |
| 949 | } |
| 950 | } else { |
| 951 | // drop down is automatically dismissed when enough characters |
| 952 | // are deleted from the text view |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 953 | if (!mPopup.isDropDownAlwaysVisible()) { |
| 954 | dismissDropDown(); |
| 955 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 956 | if (mFilter != null) { |
| 957 | mFilter.filter(null); |
| 958 | } |
| 959 | } |
| 960 | } |
| 961 | |
| 962 | /** |
| 963 | * <p>Indicates whether the popup menu is showing.</p> |
| 964 | * |
| 965 | * @return true if the popup menu is showing, false otherwise |
| 966 | */ |
| 967 | public boolean isPopupShowing() { |
| 968 | return mPopup.isShowing(); |
| 969 | } |
| 970 | |
| 971 | /** |
| 972 | * <p>Converts the selected item from the drop down list into a sequence |
| 973 | * of character that can be used in the edit box.</p> |
| 974 | * |
| 975 | * @param selectedItem the item selected by the user for completion |
| 976 | * |
| 977 | * @return a sequence of characters representing the selected suggestion |
| 978 | */ |
| 979 | protected CharSequence convertSelectionToString(Object selectedItem) { |
| 980 | return mFilter.convertResultToString(selectedItem); |
| 981 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 982 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 983 | /** |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 984 | * <p>Clear the list selection. This may only be temporary, as user input will often bring |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 985 | * it back. |
| 986 | */ |
| 987 | public void clearListSelection() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 988 | mPopup.clearListSelection(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 989 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 990 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 991 | /** |
| 992 | * Set the position of the dropdown view selection. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 993 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 994 | * @param position The position to move the selector to. |
| 995 | */ |
| 996 | public void setListSelection(int position) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 997 | mPopup.setSelection(position); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 998 | } |
| 999 | |
| 1000 | /** |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1001 | * Get the position of the dropdown view selection, if there is one. Returns |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1002 | * {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if there is no dropdown or if |
| 1003 | * there is no selection. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1004 | * |
| 1005 | * @return the position of the current selection, if there is one, or |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1006 | * {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if not. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1007 | * |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1008 | * @see ListView#getSelectedItemPosition() |
| 1009 | */ |
| 1010 | public int getListSelection() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1011 | return mPopup.getSelectedItemPosition(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1012 | } |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 1013 | |
| 1014 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1015 | * <p>Starts filtering the content of the drop down list. The filtering |
| 1016 | * pattern is the content of the edit box. Subclasses should override this |
| 1017 | * method to filter with a different pattern, for instance a substring of |
| 1018 | * <code>text</code>.</p> |
| 1019 | * |
| 1020 | * @param text the filtering pattern |
| 1021 | * @param keyCode the last character inserted in the edit box; beware that |
| 1022 | * this will be null when text is being added through a soft input method. |
| 1023 | */ |
| 1024 | @SuppressWarnings({ "UnusedDeclaration" }) |
| 1025 | protected void performFiltering(CharSequence text, int keyCode) { |
| 1026 | mFilter.filter(text, this); |
| 1027 | } |
| 1028 | |
| 1029 | /** |
| 1030 | * <p>Performs the text completion by converting the selected item from |
| 1031 | * the drop down list into a string, replacing the text box's content with |
| 1032 | * this string and finally dismissing the drop down menu.</p> |
| 1033 | */ |
| 1034 | public void performCompletion() { |
| 1035 | performCompletion(null, -1, -1); |
| 1036 | } |
| 1037 | |
| 1038 | @Override |
| 1039 | public void onCommitCompletion(CompletionInfo completion) { |
| 1040 | if (isPopupShowing()) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1041 | mPopup.performItemClick(completion.getPosition()); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1042 | } |
| 1043 | } |
| 1044 | |
| 1045 | private void performCompletion(View selectedView, int position, long id) { |
| 1046 | if (isPopupShowing()) { |
| 1047 | Object selectedItem; |
| 1048 | if (position < 0) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1049 | selectedItem = mPopup.getSelectedItem(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1050 | } else { |
| 1051 | selectedItem = mAdapter.getItem(position); |
| 1052 | } |
| 1053 | if (selectedItem == null) { |
| 1054 | Log.w(TAG, "performCompletion: no selected item"); |
| 1055 | return; |
| 1056 | } |
| 1057 | |
| 1058 | mBlockCompletion = true; |
| 1059 | replaceText(convertSelectionToString(selectedItem)); |
Gilles Debunne | be2c4f9 | 2011-01-17 15:14:32 -0800 | [diff] [blame] | 1060 | mBlockCompletion = false; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1061 | |
| 1062 | if (mItemClickListener != null) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1063 | final ListPopupWindow list = mPopup; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1064 | |
| 1065 | if (selectedView == null || position < 0) { |
| 1066 | selectedView = list.getSelectedView(); |
| 1067 | position = list.getSelectedItemPosition(); |
| 1068 | id = list.getSelectedItemId(); |
| 1069 | } |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1070 | mItemClickListener.onItemClick(list.getListView(), selectedView, position, id); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1071 | } |
| 1072 | } |
| 1073 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1074 | if (mDropDownDismissedOnCompletion && !mPopup.isDropDownAlwaysVisible()) { |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 1075 | dismissDropDown(); |
| 1076 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1077 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1078 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1079 | /** |
| 1080 | * Identifies whether the view is currently performing a text completion, so subclasses |
| 1081 | * can decide whether to respond to text changed events. |
| 1082 | */ |
| 1083 | public boolean isPerformingCompletion() { |
| 1084 | return mBlockCompletion; |
| 1085 | } |
| 1086 | |
| 1087 | /** |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 1088 | * Like {@link #setText(CharSequence)}, except that it can disable filtering. |
| 1089 | * |
| 1090 | * @param filter If <code>false</code>, no filtering will be performed |
| 1091 | * as a result of this call. |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 1092 | */ |
| 1093 | public void setText(CharSequence text, boolean filter) { |
| 1094 | if (filter) { |
| 1095 | setText(text); |
| 1096 | } else { |
| 1097 | mBlockCompletion = true; |
| 1098 | setText(text); |
| 1099 | mBlockCompletion = false; |
| 1100 | } |
| 1101 | } |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 1102 | |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 1103 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1104 | * <p>Performs the text completion by replacing the current text by the |
| 1105 | * selected item. Subclasses should override this method to avoid replacing |
| 1106 | * the whole content of the edit box.</p> |
| 1107 | * |
| 1108 | * @param text the selected suggestion in the drop down list |
| 1109 | */ |
| 1110 | protected void replaceText(CharSequence text) { |
Daisuke Miyakawa | c1d2748 | 2009-05-25 17:37:41 +0900 | [diff] [blame] | 1111 | clearComposingText(); |
| 1112 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1113 | setText(text); |
| 1114 | // make sure we keep the caret at the end of the text view |
| 1115 | Editable spannable = getText(); |
| 1116 | Selection.setSelection(spannable, spannable.length()); |
| 1117 | } |
| 1118 | |
Karl Rosaen | 875d50a | 2009-04-23 19:00:21 -0700 | [diff] [blame] | 1119 | /** {@inheritDoc} */ |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1120 | public void onFilterComplete(int count) { |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1121 | updateDropDownForFilter(count); |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1122 | } |
| 1123 | |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1124 | private void updateDropDownForFilter(int count) { |
Bjorn Bringert | 50145bc | 2009-06-11 12:30:48 +0100 | [diff] [blame] | 1125 | // Not attached to window, don't update drop-down |
| 1126 | if (getWindowVisibility() == View.GONE) return; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1127 | |
| 1128 | /* |
| 1129 | * This checks enoughToFilter() again because filtering requests |
| 1130 | * are asynchronous, so the result may come back after enough text |
| 1131 | * has since been deleted to make it no longer appropriate |
| 1132 | * to filter. |
| 1133 | */ |
| 1134 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1135 | final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible(); |
Gilles Debunne | d513e97 | 2011-09-14 15:00:51 -0700 | [diff] [blame] | 1136 | final boolean enoughToFilter = enoughToFilter(); |
| 1137 | if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter) { |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1138 | if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1139 | showDropDown(); |
| 1140 | } |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1141 | } else if (!dropDownAlwaysVisible && isPopupShowing()) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1142 | dismissDropDown(); |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1143 | // When the filter text is changed, the first update from the adapter may show an empty |
| 1144 | // count (when the query is being performed on the network). Future updates when some |
| 1145 | // content has been retrieved should still be able to update the list. |
| 1146 | mPopupCanBeUpdated = true; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1147 | } |
| 1148 | } |
| 1149 | |
| 1150 | @Override |
| 1151 | public void onWindowFocusChanged(boolean hasWindowFocus) { |
| 1152 | super.onWindowFocusChanged(hasWindowFocus); |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1153 | if (!hasWindowFocus && !mPopup.isDropDownAlwaysVisible()) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1154 | dismissDropDown(); |
| 1155 | } |
| 1156 | } |
| 1157 | |
| 1158 | @Override |
Romain Guy | 43c9cdf | 2010-01-27 13:53:55 -0800 | [diff] [blame] | 1159 | protected void onDisplayHint(int hint) { |
| 1160 | super.onDisplayHint(hint); |
| 1161 | switch (hint) { |
| 1162 | case INVISIBLE: |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1163 | if (!mPopup.isDropDownAlwaysVisible()) { |
Romain Guy | 43c9cdf | 2010-01-27 13:53:55 -0800 | [diff] [blame] | 1164 | dismissDropDown(); |
| 1165 | } |
| 1166 | break; |
| 1167 | } |
| 1168 | } |
| 1169 | |
| 1170 | @Override |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1171 | protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { |
| 1172 | super.onFocusChanged(focused, direction, previouslyFocusedRect); |
Alan Viverette | df68999 | 2014-11-13 12:59:37 -0800 | [diff] [blame] | 1173 | |
Yohei Yukawa | 24df931 | 2016-03-31 17:15:23 -0700 | [diff] [blame] | 1174 | if (isTemporarilyDetached()) { |
Alan Viverette | df68999 | 2014-11-13 12:59:37 -0800 | [diff] [blame] | 1175 | // If we are temporarily in the detach state, then do nothing. |
| 1176 | return; |
| 1177 | } |
| 1178 | |
Evan Millar | 280c753 | 2009-11-11 14:59:22 -0800 | [diff] [blame] | 1179 | // Perform validation if the view is losing focus. |
| 1180 | if (!focused) { |
| 1181 | performValidation(); |
| 1182 | } |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1183 | if (!focused && !mPopup.isDropDownAlwaysVisible()) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1184 | dismissDropDown(); |
| 1185 | } |
| 1186 | } |
| 1187 | |
| 1188 | @Override |
| 1189 | protected void onAttachedToWindow() { |
| 1190 | super.onAttachedToWindow(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1191 | } |
| 1192 | |
| 1193 | @Override |
| 1194 | protected void onDetachedFromWindow() { |
| 1195 | dismissDropDown(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1196 | super.onDetachedFromWindow(); |
| 1197 | } |
| 1198 | |
| 1199 | /** |
| 1200 | * <p>Closes the drop down if present on screen.</p> |
| 1201 | */ |
| 1202 | public void dismissDropDown() { |
Yohei Yukawa | 484d4af | 2018-09-17 16:47:08 -0700 | [diff] [blame] | 1203 | InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1204 | if (imm != null) { |
| 1205 | imm.displayCompletions(this, null); |
| 1206 | } |
| 1207 | mPopup.dismiss(); |
Gilles Debunne | 4a74dbc | 2011-01-23 17:23:31 -0800 | [diff] [blame] | 1208 | mPopupCanBeUpdated = false; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1209 | } |
| 1210 | |
| 1211 | @Override |
Romain Guy | 3e14168 | 2010-03-08 17:44:40 -0800 | [diff] [blame] | 1212 | protected boolean setFrame(final int l, int t, final int r, int b) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1213 | boolean result = super.setFrame(l, t, r, b); |
| 1214 | |
Gilles Debunne | 711734a | 2011-02-07 18:26:11 -0800 | [diff] [blame] | 1215 | if (isPopupShowing()) { |
Romain Guy | 3e14168 | 2010-03-08 17:44:40 -0800 | [diff] [blame] | 1216 | showDropDown(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1217 | } |
| 1218 | |
| 1219 | return result; |
| 1220 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1221 | |
| 1222 | /** |
Satish Sampath | fef8d3e | 2009-07-01 17:48:42 +0100 | [diff] [blame] | 1223 | * Issues a runnable to show the dropdown as soon as possible. |
Satish Sampath | 1b1a6e4 | 2009-07-01 19:06:24 +0100 | [diff] [blame] | 1224 | * |
Mike LeBeau | ffe3ecf | 2009-07-16 18:18:37 -0700 | [diff] [blame] | 1225 | * @hide internal used only by SearchDialog |
Satish Sampath | fef8d3e | 2009-07-01 17:48:42 +0100 | [diff] [blame] | 1226 | */ |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 1227 | @UnsupportedAppUsage |
Satish Sampath | fef8d3e | 2009-07-01 17:48:42 +0100 | [diff] [blame] | 1228 | public void showDropDownAfterLayout() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1229 | mPopup.postShow(); |
Satish Sampath | fef8d3e | 2009-07-01 17:48:42 +0100 | [diff] [blame] | 1230 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1231 | |
Mike LeBeau | ffe3ecf | 2009-07-16 18:18:37 -0700 | [diff] [blame] | 1232 | /** |
| 1233 | * Ensures that the drop down is not obscuring the IME. |
Amith Yamasani | d25eb35 | 2010-03-10 21:09:28 -0800 | [diff] [blame] | 1234 | * @param visible whether the ime should be in front. If false, the ime is pushed to |
| 1235 | * the background. |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1236 | * |
| 1237 | * This method is deprecated. Please use the following methods instead. |
| 1238 | * Use {@link #setInputMethodMode} to ensure that the drop down is not obscuring the IME. |
| 1239 | * Use {@link #showDropDown()} to show the drop down immediately |
| 1240 | * A combination of {@link #isDropDownAlwaysVisible()} and {@link #enoughToFilter()} to decide |
| 1241 | * whether to manually trigger {@link #showDropDown()} or not. |
| 1242 | * |
Mike LeBeau | ffe3ecf | 2009-07-16 18:18:37 -0700 | [diff] [blame] | 1243 | * @hide internal used only here and SearchDialog |
| 1244 | */ |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1245 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768913) |
Amith Yamasani | d25eb35 | 2010-03-10 21:09:28 -0800 | [diff] [blame] | 1246 | public void ensureImeVisible(boolean visible) { |
| 1247 | mPopup.setInputMethodMode(visible |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1248 | ? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED); |
Romain Guy | c27cc01 | 2012-02-15 18:34:37 -0800 | [diff] [blame] | 1249 | if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) { |
| 1250 | showDropDown(); |
| 1251 | } |
Mike LeBeau | ffe3ecf | 2009-07-16 18:18:37 -0700 | [diff] [blame] | 1252 | } |
Satish Sampath | fef8d3e | 2009-07-01 17:48:42 +0100 | [diff] [blame] | 1253 | |
| 1254 | /** |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1255 | * This method is deprecated. Please use {@link #getInputMethodMode()} instead. |
| 1256 | * |
| 1257 | * @hide This API is not being used and can be removed. |
Bjorn Bringert | 003ad48 | 2009-07-28 12:03:29 +0100 | [diff] [blame] | 1258 | */ |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1259 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) |
Bjorn Bringert | 003ad48 | 2009-07-28 12:03:29 +0100 | [diff] [blame] | 1260 | public boolean isInputMethodNotNeeded() { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1261 | return mPopup.getInputMethodMode() == ListPopupWindow.INPUT_METHOD_NOT_NEEDED; |
Bjorn Bringert | 003ad48 | 2009-07-28 12:03:29 +0100 | [diff] [blame] | 1262 | } |
| 1263 | |
| 1264 | /** |
Ralston Da Silva | f954e23 | 2019-03-11 15:11:01 -0700 | [diff] [blame] | 1265 | * The valid input method modes for the {@link AutoCompleteTextView}: |
| 1266 | * |
| 1267 | * {@hide} |
| 1268 | */ |
| 1269 | @IntDef({ListPopupWindow.INPUT_METHOD_FROM_FOCUSABLE, |
| 1270 | ListPopupWindow.INPUT_METHOD_NEEDED, |
| 1271 | ListPopupWindow.INPUT_METHOD_NOT_NEEDED}) |
| 1272 | @Retention(RetentionPolicy.SOURCE) |
| 1273 | public @interface InputMethodMode {} |
| 1274 | |
| 1275 | /** |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1276 | * Returns the input method mode used by the auto complete dropdown. |
| 1277 | */ |
Ralston Da Silva | f954e23 | 2019-03-11 15:11:01 -0700 | [diff] [blame] | 1278 | public @InputMethodMode int getInputMethodMode() { |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1279 | return mPopup.getInputMethodMode(); |
| 1280 | } |
| 1281 | |
| 1282 | /** |
| 1283 | * Use this method to specify when the IME should be displayed. This function can be used to |
| 1284 | * prevent the dropdown from obscuring the IME. |
| 1285 | * |
| 1286 | * @param mode speficies the input method mode. use one of the following values: |
| 1287 | * |
| 1288 | * {@link ListPopupWindow#INPUT_METHOD_FROM_FOCUSABLE} IME Displayed if the auto-complete box is |
| 1289 | * focusable. |
| 1290 | * {@link ListPopupWindow#INPUT_METHOD_NEEDED} Always display the IME. |
| 1291 | * {@link ListPopupWindow#INPUT_METHOD_NOT_NEEDED}. The auto-complete suggestions are always |
| 1292 | * displayed, even if the suggestions cover/hide the input method. |
| 1293 | */ |
Ralston Da Silva | f954e23 | 2019-03-11 15:11:01 -0700 | [diff] [blame] | 1294 | public void setInputMethodMode(@InputMethodMode int mode) { |
Ralston Da Silva | 17d7ce6 | 2019-02-13 12:04:41 -0800 | [diff] [blame] | 1295 | mPopup.setInputMethodMode(mode); |
| 1296 | } |
| 1297 | |
| 1298 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1299 | * <p>Displays the drop down on screen.</p> |
| 1300 | */ |
| 1301 | public void showDropDown() { |
Gilles Debunne | d513e97 | 2011-09-14 15:00:51 -0700 | [diff] [blame] | 1302 | buildImeCompletions(); |
| 1303 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1304 | if (mPopup.getAnchorView() == null) { |
| 1305 | if (mDropDownAnchorId != View.NO_ID) { |
| 1306 | mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId)); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1307 | } else { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1308 | mPopup.setAnchorView(this); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1309 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1310 | } |
Gilles Debunne | 711734a | 2011-02-07 18:26:11 -0800 | [diff] [blame] | 1311 | if (!isPopupShowing()) { |
| 1312 | // Make sure the list does not obscure the IME when shown for the first time. |
| 1313 | mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED); |
Adam Powell | 348e69c | 2011-02-16 16:49:50 -0800 | [diff] [blame] | 1314 | mPopup.setListItemExpandMax(EXPAND_MAX); |
Gilles Debunne | 711734a | 2011-02-07 18:26:11 -0800 | [diff] [blame] | 1315 | } |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1316 | mPopup.show(); |
Adam Powell | 348e69c | 2011-02-16 16:49:50 -0800 | [diff] [blame] | 1317 | mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1318 | } |
Gilles Debunne | d513e97 | 2011-09-14 15:00:51 -0700 | [diff] [blame] | 1319 | |
Mike LeBeau | d4760d7 | 2009-07-22 15:04:27 -0700 | [diff] [blame] | 1320 | /** |
| 1321 | * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is |
| 1322 | * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we |
| 1323 | * ignore outside touch even when the drop down is not set to always visible. |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1324 | * |
Mike LeBeau | d4760d7 | 2009-07-22 15:04:27 -0700 | [diff] [blame] | 1325 | * @hide used only by SearchDialog |
| 1326 | */ |
Mathew Inwood | 978c6e2 | 2018-08-21 15:58:55 +0100 | [diff] [blame] | 1327 | @UnsupportedAppUsage |
Mike LeBeau | d4760d7 | 2009-07-22 15:04:27 -0700 | [diff] [blame] | 1328 | public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) { |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1329 | mPopup.setForceIgnoreOutsideTouch(forceIgnoreOutsideTouch); |
Mike LeBeau | d4760d7 | 2009-07-22 15:04:27 -0700 | [diff] [blame] | 1330 | } |
Gilles Debunne | d513e97 | 2011-09-14 15:00:51 -0700 | [diff] [blame] | 1331 | |
Adam Powell | c3fa630 | 2010-05-18 11:36:27 -0700 | [diff] [blame] | 1332 | private void buildImeCompletions() { |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1333 | final ListAdapter adapter = mAdapter; |
| 1334 | if (adapter != null) { |
Yohei Yukawa | 484d4af | 2018-09-17 16:47:08 -0700 | [diff] [blame] | 1335 | InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1336 | if (imm != null) { |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1337 | final int count = Math.min(adapter.getCount(), 20); |
| 1338 | CompletionInfo[] completions = new CompletionInfo[count]; |
| 1339 | int realCount = 0; |
| 1340 | |
| 1341 | for (int i = 0; i < count; i++) { |
| 1342 | if (adapter.isEnabled(i)) { |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1343 | Object item = adapter.getItem(i); |
| 1344 | long id = adapter.getItemId(i); |
Gilles Debunne | f0d3b7f | 2012-01-18 18:02:46 -0800 | [diff] [blame] | 1345 | completions[realCount] = new CompletionInfo(id, realCount, |
| 1346 | convertSelectionToString(item)); |
| 1347 | realCount++; |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1348 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1349 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1350 | |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1351 | if (realCount != count) { |
| 1352 | CompletionInfo[] tmp = new CompletionInfo[realCount]; |
| 1353 | System.arraycopy(completions, 0, tmp, 0, realCount); |
| 1354 | completions = tmp; |
| 1355 | } |
| 1356 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1357 | imm.displayCompletions(this, completions); |
| 1358 | } |
| 1359 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1360 | } |
| 1361 | |
| 1362 | /** |
| 1363 | * Sets the validator used to perform text validation. |
| 1364 | * |
| 1365 | * @param validator The validator used to validate the text entered in this widget. |
| 1366 | * |
| 1367 | * @see #getValidator() |
| 1368 | * @see #performValidation() |
| 1369 | */ |
| 1370 | public void setValidator(Validator validator) { |
| 1371 | mValidator = validator; |
| 1372 | } |
| 1373 | |
| 1374 | /** |
| 1375 | * Returns the Validator set with {@link #setValidator}, |
| 1376 | * or <code>null</code> if it was not set. |
| 1377 | * |
| 1378 | * @see #setValidator(android.widget.AutoCompleteTextView.Validator) |
| 1379 | * @see #performValidation() |
| 1380 | */ |
| 1381 | public Validator getValidator() { |
| 1382 | return mValidator; |
| 1383 | } |
| 1384 | |
| 1385 | /** |
| 1386 | * If a validator was set on this view and the current string is not valid, |
| 1387 | * ask the validator to fix it. |
| 1388 | * |
| 1389 | * @see #getValidator() |
| 1390 | * @see #setValidator(android.widget.AutoCompleteTextView.Validator) |
| 1391 | */ |
| 1392 | public void performValidation() { |
| 1393 | if (mValidator == null) return; |
| 1394 | |
| 1395 | CharSequence text = getText(); |
| 1396 | |
| 1397 | if (!TextUtils.isEmpty(text) && !mValidator.isValid(text)) { |
| 1398 | setText(mValidator.fixText(text)); |
| 1399 | } |
| 1400 | } |
| 1401 | |
| 1402 | /** |
| 1403 | * Returns the Filter obtained from {@link Filterable#getFilter}, |
| 1404 | * or <code>null</code> if {@link #setAdapter} was not called with |
| 1405 | * a Filterable. |
| 1406 | */ |
| 1407 | protected Filter getFilter() { |
| 1408 | return mFilter; |
| 1409 | } |
| 1410 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1411 | private class DropDownItemClickListener implements AdapterView.OnItemClickListener { |
| 1412 | public void onItemClick(AdapterView parent, View v, int position, long id) { |
| 1413 | performCompletion(v, position, id); |
| 1414 | } |
| 1415 | } |
| 1416 | |
| 1417 | /** |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1418 | * This interface is used to make sure that the text entered in this TextView complies to |
| 1419 | * a certain format. Since there is no foolproof way to prevent the user from leaving |
| 1420 | * this View with an incorrect value in it, all we can do is try to fix it ourselves |
| 1421 | * when this happens. |
| 1422 | */ |
| 1423 | public interface Validator { |
| 1424 | /** |
| 1425 | * Validates the specified text. |
| 1426 | * |
| 1427 | * @return true If the text currently in the text editor is valid. |
| 1428 | * |
| 1429 | * @see #fixText(CharSequence) |
| 1430 | */ |
| 1431 | boolean isValid(CharSequence text); |
| 1432 | |
| 1433 | /** |
| 1434 | * Corrects the specified text to make it valid. |
| 1435 | * |
| 1436 | * @param invalidText A string that doesn't pass validation: isValid(invalidText) |
| 1437 | * returns false |
| 1438 | * |
| 1439 | * @return A string based on invalidText such as invoking isValid() on it returns true. |
| 1440 | * |
| 1441 | * @see #isValid(CharSequence) |
| 1442 | */ |
| 1443 | CharSequence fixText(CharSequence invalidText); |
| 1444 | } |
Aurimas Liutikas | 99441c5 | 2016-10-11 16:48:32 -0700 | [diff] [blame] | 1445 | |
Karl Rosaen | 98e333f | 2009-04-28 10:39:09 -0700 | [diff] [blame] | 1446 | /** |
Adam Powell | 780c491 | 2012-08-30 17:30:05 -0700 | [diff] [blame] | 1447 | * Listener to respond to the AutoCompleteTextView's completion list being dismissed. |
| 1448 | * @see AutoCompleteTextView#setOnDismissListener(OnDismissListener) |
| 1449 | */ |
| 1450 | public interface OnDismissListener { |
| 1451 | /** |
| 1452 | * This method will be invoked whenever the AutoCompleteTextView's list |
| 1453 | * of completion options has been dismissed and is no longer available |
| 1454 | * for user interaction. |
| 1455 | */ |
| 1456 | void onDismiss(); |
| 1457 | } |
| 1458 | |
| 1459 | /** |
Karl Rosaen | 98e333f | 2009-04-28 10:39:09 -0700 | [diff] [blame] | 1460 | * Allows us a private hook into the on click event without preventing users from setting |
| 1461 | * their own click listener. |
| 1462 | */ |
| 1463 | private class PassThroughClickListener implements OnClickListener { |
| 1464 | |
| 1465 | private View.OnClickListener mWrapped; |
| 1466 | |
| 1467 | /** {@inheritDoc} */ |
| 1468 | public void onClick(View v) { |
| 1469 | onClickImpl(); |
| 1470 | |
| 1471 | if (mWrapped != null) mWrapped.onClick(v); |
| 1472 | } |
| 1473 | } |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 1474 | |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 1475 | /** |
| 1476 | * Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView. |
| 1477 | * <p> |
| 1478 | * This way, if adapter has a longer life span than the View, we won't leak the View, instead |
| 1479 | * we will just leak a small Observer with 1 field. |
| 1480 | */ |
| 1481 | private static class PopupDataSetObserver extends DataSetObserver { |
| 1482 | private final WeakReference<AutoCompleteTextView> mViewReference; |
| 1483 | |
| 1484 | private PopupDataSetObserver(AutoCompleteTextView view) { |
| 1485 | mViewReference = new WeakReference<AutoCompleteTextView>(view); |
| 1486 | } |
| 1487 | |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 1488 | @Override |
| 1489 | public void onChanged() { |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 1490 | final AutoCompleteTextView textView = mViewReference.get(); |
| 1491 | if (textView != null && textView.mAdapter != null) { |
Romain Guy | 4f43ae0 | 2010-03-17 10:31:15 -0700 | [diff] [blame] | 1492 | // If the popup is not showing already, showing it will cause |
| 1493 | // the list of data set observers attached to the adapter to |
| 1494 | // change. We can't do it from here, because we are in the middle |
Gilles Debunne | be2c4f9 | 2011-01-17 15:14:32 -0800 | [diff] [blame] | 1495 | // of iterating through the list of observers. |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 1496 | textView.post(updateRunnable); |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 1497 | } |
| 1498 | } |
Yigit Boyar | 6490644 | 2014-08-25 13:27:40 -0700 | [diff] [blame] | 1499 | |
| 1500 | private final Runnable updateRunnable = new Runnable() { |
| 1501 | @Override |
| 1502 | public void run() { |
| 1503 | final AutoCompleteTextView textView = mViewReference.get(); |
| 1504 | if (textView == null) { |
| 1505 | return; |
| 1506 | } |
| 1507 | final ListAdapter adapter = textView.mAdapter; |
| 1508 | if (adapter == null) { |
| 1509 | return; |
| 1510 | } |
| 1511 | textView.updateDropDownForFilter(adapter.getCount()); |
| 1512 | } |
| 1513 | }; |
Romain Guy | 6a67810 | 2010-03-16 13:49:31 -0700 | [diff] [blame] | 1514 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1515 | } |