blob: 8d9ae58be2908b0062ffd4690badfdbd857706ba [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.widget;
18
Tor Norbye7b9c9122013-05-30 16:48:33 -070019import android.annotation.DrawableRes;
Ralston Da Silvaf954e232019-03-11 15:11:01 -070020import android.annotation.IntDef;
Artur Satayevad9254c2019-12-10 17:47:54 +000021import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Alan Viveretteda6b2f62015-08-12 11:26:15 -040023import android.content.res.Resources.Theme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.res.TypedArray;
Romain Guy6a678102010-03-16 13:49:31 -070025import android.database.DataSetObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.graphics.Rect;
27import android.graphics.drawable.Drawable;
Mathew Inwood8c854f82018-09-14 12:35:36 +010028import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.text.Editable;
30import android.text.Selection;
31import android.text.TextUtils;
32import android.text.TextWatcher;
33import android.util.AttributeSet;
34import android.util.Log;
Alan Viveretteda6b2f62015-08-12 11:26:15 -040035import android.view.ContextThemeWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.view.KeyEvent;
37import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.view.View;
Alan Viveretteda6b2f62015-08-12 11:26:15 -040039import android.view.ViewGroup.LayoutParams;
Romain Guy374aaaed32009-07-14 15:11:59 -070040import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.view.inputmethod.CompletionInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.view.inputmethod.EditorInfo;
Adam Powellc3fa6302010-05-18 11:36:27 -070043import android.view.inputmethod.InputMethodManager;
Ashley Rose55f9f922019-01-28 19:29:36 -050044import android.view.inspector.InspectableProperty;
Aurimas Liutikas99441c52016-10-11 16:48:32 -070045
Gilles Debunne688df792011-09-14 15:52:03 -070046import com.android.internal.R;
Aurimas Liutikas99441c52016-10-11 16:48:32 -070047
Ralston Da Silvaf954e232019-03-11 15:11:01 -070048import java.lang.annotation.Retention;
49import java.lang.annotation.RetentionPolicy;
Yigit Boyar64906442014-08-25 13:27:40 -070050import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
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&lt;String&gt; adapter = new ArrayAdapter&lt;String&gt;(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 Main4c359b72012-07-24 15:51:27 -070088 * <p>See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a>
89 * guide.</p>
Scott Main41ec6532010-08-19 16:57:07 -070090 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 * @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 Guye29f0642009-06-23 21:27:02 -070097 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
Alan Viverette40ce0702014-08-28 15:27:04 -070098 * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
99 * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 */
101public class AutoCompleteTextView extends EditText implements Filter.FilterListener {
102 static final boolean DEBUG = false;
103 static final String TAG = "AutoCompleteTextView";
104
Adam Powell348e69c2011-02-16 16:49:50 -0800105 static final int EXPAND_MAX = 3;
106
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400107 /** Context used to inflate the popup window or dialog. */
108 private final Context mPopupContext;
109
Mathew Inwood978c6e22018-08-21 15:58:55 +0100110 @UnsupportedAppUsage
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400111 private final ListPopupWindow mPopup;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100112 @UnsupportedAppUsage
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400113 private final PassThroughClickListener mPassThroughClickListener;
114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 private CharSequence mHintText;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100116 @UnsupportedAppUsage
Adam Powellc3fa6302010-05-18 11:36:27 -0700117 private TextView mHintView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 private int mHintResource;
119
120 private ListAdapter mAdapter;
121 private Filter mFilter;
122 private int mThreshold;
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 private int mDropDownAnchorId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
126 private AdapterView.OnItemClickListener mItemClickListener;
127 private AdapterView.OnItemSelectedListener mItemSelectedListener;
128
Karl Rosaen875d50a2009-04-23 19:00:21 -0700129 private boolean mDropDownDismissedOnCompletion = true;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800132 private MyWatcher mAutoCompleteTextWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
134 private Validator mValidator = null;
135
Gilles Debunnebe2c4f92011-01-17 15:14:32 -0800136 // Set to true when text is set directly and no filtering shall be performed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private boolean mBlockCompletion;
138
Gilles Debunne4a74dbc2011-01-23 17:23:31 -0800139 // 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 Inwood978c6e22018-08-21 15:58:55 +0100143 @UnsupportedAppUsage
Romain Guy6a678102010-03-16 13:49:31 -0700144 private PopupDataSetObserver mObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400146 /**
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 Project9066cfe2009-03-03 19:31:44 -0800152 public AutoCompleteTextView(Context context) {
153 this(context, null);
154 }
155
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400156 /**
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 Project9066cfe2009-03-03 19:31:44 -0800164 public AutoCompleteTextView(Context context, AttributeSet attrs) {
Alan Viverettef023c252014-08-28 13:55:18 -0700165 this(context, attrs, R.attr.autoCompleteTextViewStyle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 }
167
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400168 /**
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 Viverette617feb92013-09-09 18:09:13 -0700180 public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
181 this(context, attrs, defStyleAttr, 0);
182 }
183
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400184 /**
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 Viverette617feb92013-09-09 18:09:13 -0700200 public AutoCompleteTextView(
201 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400202 this(context, attrs, defStyleAttr, defStyleRes, null);
203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400205 /**
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 Project9066cfe2009-03-03 19:31:44 -0800230
Alan Viverettef023c252014-08-28 13:55:18 -0700231 final TypedArray a = context.obtainStyledAttributes(
232 attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800233 saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
234 attrs, a, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400236 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 Liutikasab324cf2019-02-07 16:46:38 -0800253 saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
254 attrs, a, defStyleAttr, defStyleRes);
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400255 } 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 Viverettef023c252014-08-28 13:55:18 -0700298 mThreshold = a.getInt(R.styleable.AutoCompleteTextView_completionThreshold, 2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400300 a.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
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 Viveretteda6b2f62015-08-12 11:26:15 -0400305 if ((inputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
307 setRawInputType(inputType);
308 }
309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 setFocusable(true);
311
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800312 mAutoCompleteTextWatcher = new MyWatcher();
313 addTextChangedListener(mAutoCompleteTextWatcher);
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400314
Karl Rosaen98e333f2009-04-28 10:39:09 -0700315 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 Yamasanid25eb352010-03-10 21:09:28 -0800328 // If the dropdown is showing, bring the keyboard to the front
329 // when the user touches the text field.
Gilles Debunne711734a2011-02-07 18:26:11 -0800330 if (isPopupShowing()) {
Amith Yamasanid25eb352010-03-10 21:09:28 -0800331 ensureImeVisible(true);
Karl Rosaen98e333f2009-04-28 10:39:09 -0700332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
334
335 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 * <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 Debunne5c49d112012-04-30 16:44:14 -0700342 * @see #getCompletionHint()
343 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 * @attr ref android.R.styleable#AutoCompleteTextView_completionHint
345 */
346 public void setCompletionHint(CharSequence hint) {
347 mHintText = hint;
Adam Powellc3fa6302010-05-18 11:36:27 -0700348 if (hint != null) {
349 if (mHintView == null) {
Alan Viveretteda6b2f62015-08-12 11:26:15 -0400350 final TextView hintView = (TextView) LayoutInflater.from(mPopupContext).inflate(
351 mHintResource, null).findViewById(R.id.text1);
Adam Powellc3fa6302010-05-18 11:36:27 -0700352 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 Project9066cfe2009-03-03 19:31:44 -0800362 }
Gilles Debunne5c49d112012-04-30 16:44:14 -0700363
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 Rose55f9f922019-01-28 19:29:36 -0500373 @InspectableProperty
Gilles Debunne5c49d112012-04-30 16:44:14 -0700374 public CharSequence getCompletionHint() {
375 return mHintText;
376 }
377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 /**
Ashley Rose55f9f922019-01-28 19:29:36 -0500379 * 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 Liutikas99441c52016-10-11 16:48:32 -0700384 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 * @return the width for the drop down list
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700386 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700387 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500389 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 public int getDropDownWidth() {
Adam Powellc3fa6302010-05-18 11:36:27 -0700391 return mPopup.getWidth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 /**
Ashley Rose55f9f922019-01-28 19:29:36 -0500395 * 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 Liutikas99441c52016-10-11 16:48:32 -0700400 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 * @param width the width to use
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700402 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700403 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 */
405 public void setDropDownWidth(int width) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700406 mPopup.setWidth(width);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
Romain Guye29f0642009-06-23 21:27:02 -0700408
409 /**
Ashley Rose55f9f922019-01-28 19:29:36 -0500410 * <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 Guye29f0642009-06-23 21:27:02 -0700415 *
416 * @return the height for the drop down list
417 *
418 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
419 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500420 @InspectableProperty
Romain Guye29f0642009-06-23 21:27:02 -0700421 public int getDropDownHeight() {
Adam Powellc3fa6302010-05-18 11:36:27 -0700422 return mPopup.getHeight();
Romain Guye29f0642009-06-23 21:27:02 -0700423 }
424
425 /**
Ashley Rose55f9f922019-01-28 19:29:36 -0500426 * 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 Guye29f0642009-06-23 21:27:02 -0700431 *
432 * @param height the height to use
433 *
434 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
435 */
436 public void setDropDownHeight(int height) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700437 mPopup.setHeight(height);
Romain Guye29f0642009-06-23 21:27:02 -0700438 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 /**
441 * <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700442 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 * @return the view's id, or {@link View#NO_ID} if none specified
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700444 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700445 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 */
447 public int getDropDownAnchor() {
448 return mDropDownAnchorId;
449 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 /**
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 Liutikas99441c52016-10-11 16:48:32 -0700455 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 * @param id the id to anchor the drop down list view to
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700457 *
458 * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 */
460 public void setDropDownAnchor(int id) {
461 mDropDownAnchorId = id;
Adam Powellc3fa6302010-05-18 11:36:27 -0700462 mPopup.setAnchorView(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700464
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700465 /**
466 * <p>Gets the background of the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700467 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700468 * @return the background drawable
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700469 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700470 * @attr ref android.R.styleable#PopupWindow_popupBackground
471 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500472 @InspectableProperty(name = "popupBackground")
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700473 public Drawable getDropDownBackground() {
474 return mPopup.getBackground();
475 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700476
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700477 /**
478 * <p>Sets the background of the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700479 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700480 * @param d the drawable to set as the background
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700481 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700482 * @attr ref android.R.styleable#PopupWindow_popupBackground
483 */
484 public void setDropDownBackgroundDrawable(Drawable d) {
485 mPopup.setBackgroundDrawable(d);
486 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700487
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700488 /**
489 * <p>Sets the background of the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700490 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700491 * @param id the id of the drawable to set as the background
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700492 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700493 * @attr ref android.R.styleable#PopupWindow_popupBackground
494 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700495 public void setDropDownBackgroundResource(@DrawableRes int id) {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800496 mPopup.setBackgroundDrawable(getContext().getDrawable(id));
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700497 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700498
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700499 /**
500 * <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700501 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700502 * @param offset the vertical offset
Alan Viverette40ce0702014-08-28 15:27:04 -0700503 *
504 * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700505 */
506 public void setDropDownVerticalOffset(int offset) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700507 mPopup.setVerticalOffset(offset);
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700508 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700509
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700510 /**
511 * <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700512 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700513 * @return the vertical offset
Alan Viverette40ce0702014-08-28 15:27:04 -0700514 *
515 * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700516 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500517 @InspectableProperty
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700518 public int getDropDownVerticalOffset() {
Adam Powellc3fa6302010-05-18 11:36:27 -0700519 return mPopup.getVerticalOffset();
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700520 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700521
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700522 /**
523 * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700524 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700525 * @param offset the horizontal offset
Alan Viverette40ce0702014-08-28 15:27:04 -0700526 *
527 * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700528 */
529 public void setDropDownHorizontalOffset(int offset) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700530 mPopup.setHorizontalOffset(offset);
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700531 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700532
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700533 /**
534 * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700535 *
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700536 * @return the horizontal offset
Alan Viverette40ce0702014-08-28 15:27:04 -0700537 *
538 * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700539 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500540 @InspectableProperty
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700541 public int getDropDownHorizontalOffset() {
Adam Powellc3fa6302010-05-18 11:36:27 -0700542 return mPopup.getHorizontalOffset();
The Android Open Source Project7b0b1ed2009-03-18 22:20:26 -0700543 }
The Android Open Source Project8f080ec2009-04-29 13:34:51 -0700544
The Android Open Source Projectbff13892009-04-29 13:41:02 -0700545 /**
Karl Rosaen875d50a2009-04-23 19:00:21 -0700546 * <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 Inwood8c854f82018-09-14 12:35:36 +0100557 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Karl Rosaen875d50a2009-04-23 19:00:21 -0700558 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 Rosaen875d50a2009-04-23 19:00:21 -0700573
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 Powellc3fa6302010-05-18 11:36:27 -0700580 return mPopup.isDropDownAlwaysVisible();
Karl Rosaen875d50a2009-04-23 19:00:21 -0700581 }
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 Inwood978c6e22018-08-21 15:58:55 +0100596 @UnsupportedAppUsage
Karl Rosaen875d50a2009-04-23 19:00:21 -0700597 public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700598 mPopup.setDropDownAlwaysVisible(dropDownAlwaysVisible);
Karl Rosaen875d50a2009-04-23 19:00:21 -0700599 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700600
Karl Rosaen875d50a2009-04-23 19:00:21 -0700601 /**
602 * Checks whether the drop-down is dismissed when a suggestion is clicked.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700603 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700604 * @hide Pending API council approval
605 */
606 public boolean isDropDownDismissedOnCompletion() {
607 return mDropDownDismissedOnCompletion;
608 }
Romain Guy6a678102010-03-16 13:49:31 -0700609
Karl Rosaen875d50a2009-04-23 19:00:21 -0700610 /**
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700611 * Sets whether the drop-down is dismissed when a suggestion is clicked. This is
Karl Rosaen875d50a2009-04-23 19:00:21 -0700612 * true by default.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700613 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700614 * @param dropDownDismissedOnCompletion Whether to dismiss the drop-down.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700615 *
Karl Rosaen875d50a2009-04-23 19:00:21 -0700616 * @hide Pending API council approval
617 */
Mathew Inwood978c6e22018-08-21 15:58:55 +0100618 @UnsupportedAppUsage
Karl Rosaen875d50a2009-04-23 19:00:21 -0700619 public void setDropDownDismissedOnCompletion(boolean dropDownDismissedOnCompletion) {
620 mDropDownDismissedOnCompletion = dropDownDismissedOnCompletion;
621 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 /**
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 Debunne5c49d112012-04-30 16:44:14 -0700630 *
631 * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500633 @InspectableProperty(name = "completionThreshold")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 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 Powell780c4912012-08-30 17:30:05 -0700727 * 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 Project9066cfe2009-03-03 19:31:44 -0800744 * <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 Liutikas99441c52016-10-11 16:48:32 -0700755 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 * <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 Liutikas99441c52016-10-11 16:48:32 -0700760 * automatically (see
761 * {@link android.app.Activity#startManagingCursor(android.database.Cursor)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 * 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 Guy6a678102010-03-16 13:49:31 -0700772 if (mObserver == null) {
Yigit Boyar64906442014-08-25 13:27:40 -0700773 mObserver = new PopupDataSetObserver(this);
Romain Guy6a678102010-03-16 13:49:31 -0700774 } else if (mAdapter != null) {
775 mAdapter.unregisterDataSetObserver(mObserver);
776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 mAdapter = adapter;
778 if (mAdapter != null) {
779 //noinspection unchecked
780 mFilter = ((Filterable) mAdapter).getFilter();
Romain Guy6a678102010-03-16 13:49:31 -0700781 adapter.registerDataSetObserver(mObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 } else {
783 mFilter = null;
784 }
785
Adam Powellc3fa6302010-05-18 11:36:27 -0700786 mPopup.setAdapter(mAdapter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788
789 @Override
790 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
Dianne Hackborn8d374262009-09-14 21:21:52 -0700791 if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()
Adam Powellc3fa6302010-05-18 11:36:27 -0700792 && !mPopup.isDropDownAlwaysVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 // 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 Guy2beee4d2010-03-15 17:18:22 -0700795 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
Jeff Brownb3ea9222011-01-10 16:26:36 -0800796 KeyEvent.DispatcherState state = getKeyDispatcherState();
797 if (state != null) {
798 state.startTracking(event, this);
799 }
Dianne Hackborn8d374262009-09-14 21:21:52 -0700800 return true;
Bjorn Bringert4eb3efc2009-10-06 09:26:06 +0100801 } else if (event.getAction() == KeyEvent.ACTION_UP) {
Jeff Brownb3ea9222011-01-10 16:26:36 -0800802 KeyEvent.DispatcherState state = getKeyDispatcherState();
803 if (state != null) {
804 state.handleUpEvent(event);
805 }
Bjorn Bringert4eb3efc2009-10-06 09:26:06 +0100806 if (event.isTracking() && !event.isCanceled()) {
807 dismissDropDown();
808 return true;
809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
811 }
812 return super.onKeyPreIme(keyCode, event);
813 }
814
815 @Override
816 public boolean onKeyUp(int keyCode, KeyEvent event) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700817 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 Brown4e6319b2010-12-13 10:36:51 -0800825 case KeyEvent.KEYCODE_TAB:
826 if (event.hasNoModifiers()) {
827 performCompletion();
828 }
Adam Powellc3fa6302010-05-18 11:36:27 -0700829 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831 }
Gilles Debunnea4a57582011-02-08 18:21:01 -0800832
833 if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) {
834 performCompletion();
835 return true;
836 }
837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 return super.onKeyUp(keyCode, event);
839 }
840
841 @Override
842 public boolean onKeyDown(int keyCode, KeyEvent event) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700843 if (mPopup.onKeyDown(keyCode, event)) {
844 return true;
845 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700846
Adam Powellc3fa6302010-05-18 11:36:27 -0700847 if (!isPopupShowing()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 switch(keyCode) {
849 case KeyEvent.KEYCODE_DPAD_DOWN:
Jeff Brown4e6319b2010-12-13 10:36:51 -0800850 if (event.hasNoModifiers()) {
851 performValidation();
852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854 }
855
Gilles Debunnea4a57582011-02-08 18:21:01 -0800856 if (isPopupShowing() && keyCode == KeyEvent.KEYCODE_TAB && event.hasNoModifiers()) {
857 return true;
858 }
859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 mLastKeyCode = keyCode;
861 boolean handled = super.onKeyDown(keyCode, event);
862 mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
863
Adam Powellc3fa6302010-05-18 11:36:27 -0700864 if (handled && isPopupShowing()) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700865 clearListSelection();
866 }
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 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 Silvaccec37e2019-02-05 10:31:33 -0800883
884
885 /** This is used to watch for edits to the text view. */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 private class MyWatcher implements TextWatcher {
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800887 private boolean mOpenBefore;
888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800890 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 Project9066cfe2009-03-03 19:31:44 -0800896 }
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800897
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 Project9066cfe2009-03-03 19:31:44 -0800914 public void onTextChanged(CharSequence s, int start, int before, int count) {
915 }
916 }
917
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800918 /**
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 Project9066cfe2009-03-03 19:31:44 -0800923 void doBeforeTextChanged() {
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800924 mAutoCompleteTextWatcher.beforeTextChanged(null, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
926
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800927 /**
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 Project9066cfe2009-03-03 19:31:44 -0800932 void doAfterTextChanged() {
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800933 mAutoCompleteTextWatcher.afterTextChanged(null);
934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935
Ralston Da Silvaccec37e2019-02-05 10:31:33 -0800936 /**
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 Project9066cfe2009-03-03 19:31:44 -0800943 // 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 Debunne4a74dbc2011-01-23 17:23:31 -0800947 mPopupCanBeUpdated = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 performFiltering(getText(), mLastKeyCode);
949 }
950 } else {
951 // drop down is automatically dismissed when enough characters
952 // are deleted from the text view
Gilles Debunne4a74dbc2011-01-23 17:23:31 -0800953 if (!mPopup.isDropDownAlwaysVisible()) {
954 dismissDropDown();
955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 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 Liutikas99441c52016-10-11 16:48:32 -0700982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 /**
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700984 * <p>Clear the list selection. This may only be temporary, as user input will often bring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 * it back.
986 */
987 public void clearListSelection() {
Adam Powellc3fa6302010-05-18 11:36:27 -0700988 mPopup.clearListSelection();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 /**
992 * Set the position of the dropdown view selection.
Aurimas Liutikas99441c52016-10-11 16:48:32 -0700993 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 * @param position The position to move the selector to.
995 */
996 public void setListSelection(int position) {
Adam Powellc3fa6302010-05-18 11:36:27 -0700997 mPopup.setSelection(position);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
999
1000 /**
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001001 * Get the position of the dropdown view selection, if there is one. Returns
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 * {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if there is no dropdown or if
1003 * there is no selection.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001004 *
1005 * @return the position of the current selection, if there is one, or
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 * {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if not.
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001007 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 * @see ListView#getSelectedItemPosition()
1009 */
1010 public int getListSelection() {
Adam Powellc3fa6302010-05-18 11:36:27 -07001011 return mPopup.getSelectedItemPosition();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 }
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07001013
1014 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 * <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 Powellc3fa6302010-05-18 11:36:27 -07001041 mPopup.performItemClick(completion.getPosition());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 }
1043 }
1044
1045 private void performCompletion(View selectedView, int position, long id) {
1046 if (isPopupShowing()) {
1047 Object selectedItem;
1048 if (position < 0) {
Adam Powellc3fa6302010-05-18 11:36:27 -07001049 selectedItem = mPopup.getSelectedItem();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 } 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 Debunnebe2c4f92011-01-17 15:14:32 -08001060 mBlockCompletion = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061
1062 if (mItemClickListener != null) {
Adam Powellc3fa6302010-05-18 11:36:27 -07001063 final ListPopupWindow list = mPopup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064
1065 if (selectedView == null || position < 0) {
1066 selectedView = list.getSelectedView();
1067 position = list.getSelectedItemPosition();
1068 id = list.getSelectedItemId();
1069 }
Adam Powellc3fa6302010-05-18 11:36:27 -07001070 mItemClickListener.onItemClick(list.getListView(), selectedView, position, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 }
1072 }
1073
Adam Powellc3fa6302010-05-18 11:36:27 -07001074 if (mDropDownDismissedOnCompletion && !mPopup.isDropDownAlwaysVisible()) {
Karl Rosaen875d50a2009-04-23 19:00:21 -07001075 dismissDropDown();
1076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 /**
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 Rosaen875d50a2009-04-23 19:00:21 -07001088 * 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 Rosaen875d50a2009-04-23 19:00:21 -07001092 */
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 Guy6a678102010-03-16 13:49:31 -07001102
Karl Rosaen875d50a2009-04-23 19:00:21 -07001103 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 * <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 Miyakawac1d27482009-05-25 17:37:41 +09001111 clearComposingText();
1112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 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 Rosaen875d50a2009-04-23 19:00:21 -07001119 /** {@inheritDoc} */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 public void onFilterComplete(int count) {
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001121 updateDropDownForFilter(count);
Romain Guy4f43ae02010-03-17 10:31:15 -07001122 }
1123
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001124 private void updateDropDownForFilter(int count) {
Bjorn Bringert50145bc2009-06-11 12:30:48 +01001125 // Not attached to window, don't update drop-down
1126 if (getWindowVisibility() == View.GONE) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127
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 Powellc3fa6302010-05-18 11:36:27 -07001135 final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
Gilles Debunned513e972011-09-14 15:00:51 -07001136 final boolean enoughToFilter = enoughToFilter();
1137 if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter) {
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001138 if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 showDropDown();
1140 }
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001141 } else if (!dropDownAlwaysVisible && isPopupShowing()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 dismissDropDown();
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001143 // 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 Project9066cfe2009-03-03 19:31:44 -08001147 }
1148 }
1149
1150 @Override
1151 public void onWindowFocusChanged(boolean hasWindowFocus) {
1152 super.onWindowFocusChanged(hasWindowFocus);
Adam Powellc3fa6302010-05-18 11:36:27 -07001153 if (!hasWindowFocus && !mPopup.isDropDownAlwaysVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 dismissDropDown();
1155 }
1156 }
1157
1158 @Override
Romain Guy43c9cdf2010-01-27 13:53:55 -08001159 protected void onDisplayHint(int hint) {
1160 super.onDisplayHint(hint);
1161 switch (hint) {
1162 case INVISIBLE:
Adam Powellc3fa6302010-05-18 11:36:27 -07001163 if (!mPopup.isDropDownAlwaysVisible()) {
Romain Guy43c9cdf2010-01-27 13:53:55 -08001164 dismissDropDown();
1165 }
1166 break;
1167 }
1168 }
1169
1170 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1172 super.onFocusChanged(focused, direction, previouslyFocusedRect);
Alan Viverettedf689992014-11-13 12:59:37 -08001173
Yohei Yukawa24df9312016-03-31 17:15:23 -07001174 if (isTemporarilyDetached()) {
Alan Viverettedf689992014-11-13 12:59:37 -08001175 // If we are temporarily in the detach state, then do nothing.
1176 return;
1177 }
1178
Evan Millar280c7532009-11-11 14:59:22 -08001179 // Perform validation if the view is losing focus.
1180 if (!focused) {
1181 performValidation();
1182 }
Adam Powellc3fa6302010-05-18 11:36:27 -07001183 if (!focused && !mPopup.isDropDownAlwaysVisible()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 dismissDropDown();
1185 }
1186 }
1187
1188 @Override
1189 protected void onAttachedToWindow() {
1190 super.onAttachedToWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
1192
1193 @Override
1194 protected void onDetachedFromWindow() {
1195 dismissDropDown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 super.onDetachedFromWindow();
1197 }
1198
1199 /**
1200 * <p>Closes the drop down if present on screen.</p>
1201 */
1202 public void dismissDropDown() {
Yohei Yukawa484d4af2018-09-17 16:47:08 -07001203 InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 if (imm != null) {
1205 imm.displayCompletions(this, null);
1206 }
1207 mPopup.dismiss();
Gilles Debunne4a74dbc2011-01-23 17:23:31 -08001208 mPopupCanBeUpdated = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 }
1210
1211 @Override
Romain Guy3e141682010-03-08 17:44:40 -08001212 protected boolean setFrame(final int l, int t, final int r, int b) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 boolean result = super.setFrame(l, t, r, b);
1214
Gilles Debunne711734a2011-02-07 18:26:11 -08001215 if (isPopupShowing()) {
Romain Guy3e141682010-03-08 17:44:40 -08001216 showDropDown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 }
1218
1219 return result;
1220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221
1222 /**
Satish Sampathfef8d3e2009-07-01 17:48:42 +01001223 * Issues a runnable to show the dropdown as soon as possible.
Satish Sampath1b1a6e42009-07-01 19:06:24 +01001224 *
Mike LeBeauffe3ecf2009-07-16 18:18:37 -07001225 * @hide internal used only by SearchDialog
Satish Sampathfef8d3e2009-07-01 17:48:42 +01001226 */
Mathew Inwood978c6e22018-08-21 15:58:55 +01001227 @UnsupportedAppUsage
Satish Sampathfef8d3e2009-07-01 17:48:42 +01001228 public void showDropDownAfterLayout() {
Adam Powellc3fa6302010-05-18 11:36:27 -07001229 mPopup.postShow();
Satish Sampathfef8d3e2009-07-01 17:48:42 +01001230 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001231
Mike LeBeauffe3ecf2009-07-16 18:18:37 -07001232 /**
1233 * Ensures that the drop down is not obscuring the IME.
Amith Yamasanid25eb352010-03-10 21:09:28 -08001234 * @param visible whether the ime should be in front. If false, the ime is pushed to
1235 * the background.
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001236 *
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 LeBeauffe3ecf2009-07-16 18:18:37 -07001243 * @hide internal used only here and SearchDialog
1244 */
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001245 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768913)
Amith Yamasanid25eb352010-03-10 21:09:28 -08001246 public void ensureImeVisible(boolean visible) {
1247 mPopup.setInputMethodMode(visible
Adam Powellc3fa6302010-05-18 11:36:27 -07001248 ? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
Romain Guyc27cc012012-02-15 18:34:37 -08001249 if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) {
1250 showDropDown();
1251 }
Mike LeBeauffe3ecf2009-07-16 18:18:37 -07001252 }
Satish Sampathfef8d3e2009-07-01 17:48:42 +01001253
1254 /**
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001255 * This method is deprecated. Please use {@link #getInputMethodMode()} instead.
1256 *
1257 * @hide This API is not being used and can be removed.
Bjorn Bringert003ad482009-07-28 12:03:29 +01001258 */
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001259 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Bjorn Bringert003ad482009-07-28 12:03:29 +01001260 public boolean isInputMethodNotNeeded() {
Adam Powellc3fa6302010-05-18 11:36:27 -07001261 return mPopup.getInputMethodMode() == ListPopupWindow.INPUT_METHOD_NOT_NEEDED;
Bjorn Bringert003ad482009-07-28 12:03:29 +01001262 }
1263
1264 /**
Ralston Da Silvaf954e232019-03-11 15:11:01 -07001265 * 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 Silva17d7ce62019-02-13 12:04:41 -08001276 * Returns the input method mode used by the auto complete dropdown.
1277 */
Ralston Da Silvaf954e232019-03-11 15:11:01 -07001278 public @InputMethodMode int getInputMethodMode() {
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001279 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 Silvaf954e232019-03-11 15:11:01 -07001294 public void setInputMethodMode(@InputMethodMode int mode) {
Ralston Da Silva17d7ce62019-02-13 12:04:41 -08001295 mPopup.setInputMethodMode(mode);
1296 }
1297
1298 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 * <p>Displays the drop down on screen.</p>
1300 */
1301 public void showDropDown() {
Gilles Debunned513e972011-09-14 15:00:51 -07001302 buildImeCompletions();
1303
Adam Powellc3fa6302010-05-18 11:36:27 -07001304 if (mPopup.getAnchorView() == null) {
1305 if (mDropDownAnchorId != View.NO_ID) {
1306 mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 } else {
Adam Powellc3fa6302010-05-18 11:36:27 -07001308 mPopup.setAnchorView(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 }
Gilles Debunne711734a2011-02-07 18:26:11 -08001311 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 Powell348e69c2011-02-16 16:49:50 -08001314 mPopup.setListItemExpandMax(EXPAND_MAX);
Gilles Debunne711734a2011-02-07 18:26:11 -08001315 }
Adam Powellc3fa6302010-05-18 11:36:27 -07001316 mPopup.show();
Adam Powell348e69c2011-02-16 16:49:50 -08001317 mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 }
Gilles Debunned513e972011-09-14 15:00:51 -07001319
Mike LeBeaud4760d72009-07-22 15:04:27 -07001320 /**
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 Liutikas99441c52016-10-11 16:48:32 -07001324 *
Mike LeBeaud4760d72009-07-22 15:04:27 -07001325 * @hide used only by SearchDialog
1326 */
Mathew Inwood978c6e22018-08-21 15:58:55 +01001327 @UnsupportedAppUsage
Mike LeBeaud4760d72009-07-22 15:04:27 -07001328 public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
Adam Powellc3fa6302010-05-18 11:36:27 -07001329 mPopup.setForceIgnoreOutsideTouch(forceIgnoreOutsideTouch);
Mike LeBeaud4760d72009-07-22 15:04:27 -07001330 }
Gilles Debunned513e972011-09-14 15:00:51 -07001331
Adam Powellc3fa6302010-05-18 11:36:27 -07001332 private void buildImeCompletions() {
Romain Guy4f43ae02010-03-17 10:31:15 -07001333 final ListAdapter adapter = mAdapter;
1334 if (adapter != null) {
Yohei Yukawa484d4af2018-09-17 16:47:08 -07001335 InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 if (imm != null) {
Romain Guy4f43ae02010-03-17 10:31:15 -07001337 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 Guy4f43ae02010-03-17 10:31:15 -07001343 Object item = adapter.getItem(i);
1344 long id = adapter.getItemId(i);
Gilles Debunnef0d3b7f2012-01-18 18:02:46 -08001345 completions[realCount] = new CompletionInfo(id, realCount,
1346 convertSelectionToString(item));
1347 realCount++;
Romain Guy4f43ae02010-03-17 10:31:15 -07001348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 }
Aurimas Liutikas99441c52016-10-11 16:48:32 -07001350
Romain Guy4f43ae02010-03-17 10:31:15 -07001351 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 Project9066cfe2009-03-03 19:31:44 -08001357 imm.displayCompletions(this, completions);
1358 }
1359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 }
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 Project9066cfe2009-03-03 19:31:44 -08001411 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 Project9066cfe2009-03-03 19:31:44 -08001418 * 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 Liutikas99441c52016-10-11 16:48:32 -07001445
Karl Rosaen98e333f2009-04-28 10:39:09 -07001446 /**
Adam Powell780c4912012-08-30 17:30:05 -07001447 * 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 Rosaen98e333f2009-04-28 10:39:09 -07001460 * 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 Guy6a678102010-03-16 13:49:31 -07001474
Yigit Boyar64906442014-08-25 13:27:40 -07001475 /**
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 Guy6a678102010-03-16 13:49:31 -07001488 @Override
1489 public void onChanged() {
Yigit Boyar64906442014-08-25 13:27:40 -07001490 final AutoCompleteTextView textView = mViewReference.get();
1491 if (textView != null && textView.mAdapter != null) {
Romain Guy4f43ae02010-03-17 10:31:15 -07001492 // 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 Debunnebe2c4f92011-01-17 15:14:32 -08001495 // of iterating through the list of observers.
Yigit Boyar64906442014-08-25 13:27:40 -07001496 textView.post(updateRunnable);
Romain Guy6a678102010-03-16 13:49:31 -07001497 }
1498 }
Yigit Boyar64906442014-08-25 13:27:40 -07001499
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 Guy6a678102010-03-16 13:49:31 -07001514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515}