Today I was stuck with yet another Android related problem, I was creating a edit text with auto completion that always shows the drop down to help the user remember the last choices.
So the ultimate requirement is to on activity open show list of all items in the auto completion adapter in a drop-down, which should be simple right?
The obvious choice is to use AutoCompleteTextView, which provides the feature of listing possible choices after inputting certain amount of characters, however I knew that it wouldn’t show the listing before inputting certain amount of characters.
First thing to do was of course to open the documentation which didn’t appear to contain any helpful information, however I threw together the activity with one of these view with a dummy adapter and tested how it works normally.
Normally it takes two matching characters to get the drop down to appear, and there is actually a option to set the threshold, so I decided to set it to 0 and checked what would happen if I focused the field
Judging from the documentation of setThreshold I know that if the threshold is set under one, the threshold is actually being set to minimum of one.
thresholdis less than or equals 0, a threshold of 1 is applied.
No luck.. You have to input at least one character to make the popup appear. I think its time to browse through the source..
First thing I noticed was that the AutoCompleteTextView has reference to the ListPopupWindow which is ultimately used to show the actual popup that lists the possible options
I looked for the conditions which needs to be fulfilled in order for the popup to be shown and found out that there is actually a flag on the ListPopupWindow, isDropDownAlwaysVisible, which also has a setter, setDropDownAlwaysVisible, so I was sure I was onto something!
Unfortunately the setDropDownAlwaysVisible setter had a @hide javadoc annotation, which removes the method from public with the following comment
Only used by AutoCompleteTextView under special conditions.
So I decided to find out those conditions, but there was only single method call to this setter within AutoCompleteTextView which was just a delegate setter which too had a @hide javadoc annotation, but this time the comment declared that it was pending API council approval, which meant this was a dead end.
This basically meant that I needed to hook on the onFocusChanged by either subclassing or setting a listener and within that hook make the popup visible.
Luckily there was public showDropDown method within AutoCompleteTextView which meant that subclassing wouldn’t be necessary and this could be a matter of a simple View.OnFocusChangeListener, the day was saved!
So I created a View.OnFocusChangeListener and implemented its onFocusChange callback that calls showDropDown on focus
Unfortunately it turns out that the onFocusChange may be called even if the window containing isn’t necessarily visible, so this is fixed with matter of checking the fact, right?
So I added a check if getWindowVisiblity of the view that the onFocusChange listener passes as parameter is visible, but as it turns out after orientation change the View.OnFocusChangeListener is triggered before the window is visible, okay.. we have a problem here..
I thought to myself, okay.. so if we add a callback to the view so I’ll know when the containing view is visible, right? Unfortunately the View doesn’t provide an API or a mechanism to do attach a callback to the onAttachedToWindow method, so I had to scrape that idea..
After swallowing my pride that this couldn’t be implemented using a listener, I decided to give it a try to subclass the AutoCompleteTextView and override nessaccary methods such as onFocusChanged and onAttachedToWindow
I ended up creating a little helper method showDropDownIfFocused that checks whether enoughToFilter, isFocused and getWindowVisibility matches the conditions and if so, call the showDropDown method of AutoCompleteTextView and calling this from onFocusChanged and onAttachedToWindow
I also override enoughToFilter method to make sure that I could set minimum threshold to zero using a special flag of my new InstantAutoCompleteTextView
Below you can see the final result of the progress.
The final source code can be obtained as gist here
If you have better ideas of how the problem could be solved, feel free to comment below.
Thanks for reading