I have an app with two activities, and sometimes, I need to switch activity and at the same time open up the search input in the actionbar of the activity that's just been resumed. Everything works fine, except that I can't get the keyboard to come up. The relevant bits of my code are below (NB: the boolean startsearch is set true
as a result of switching activities if the search input is required):
public class MyActivity extends Activity {
private InputMethodManager imm;
public boolean startsearch;
private MenuItem DestinationTxt;
private SearchView mySearchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// various initialisation, and then:
startsearch = false;
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_menu, menu);
DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
// more menu create stuff appears here
}
@Override
public void onResume() {
super.onResume();
if (startsearch) {
DestinationTxt.expandActionView();
imm.showSoftInput(mySearchView, 0);
}
}
}
and the relevant bit of the action_menu.xml is
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/actionbar_search"
android:orderInCategory="1"
android:showAsAction="always|withText|collapseActionView"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/earth_2508858_search_en"
android:inputType="textPostalAddress"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"></item>
</menu>
As I said, this mostly works, because the action bar search does get the focus when the activity resumes. But the keyboard doesn't appear, even though (as you can see from the code), I've explicitly requested it. Can anyone tell me what I'm doing wrong, and what I need to do to get the keyboard to come up?
I've now been able to figure this out. By looking at the code for InputMethodManager.showSoftInput(View, int)
, I worked out that my request to bring up the keyboard was being ignored because the view I was passing wasn't the InputMethodManager's active view.
To solve my problem, I added two new fields to the MyActivity
class, namely:
private EditText search_edit_text;
private boolean mySearchView_editflag;
The search_edit_text
variable will be the view inside the SearchView mySearchView
which is the view that actually gets the focus and receives the input from the keyboard. The mySearchView_editflag
will normally be false, but it will be true
when the app is waiting for the right time to bring up the keyboard.
To get hold of the search_edit_text
EditText object I used the following function
public static EditText GetEditText(ViewGroup vg) {
for(int i=0; i< vg.getChildCount(); i++) {
View v = vg.getChildAt(i);
if (v instanceof EditText) {
return (EditText)v;
} else if (v instanceof ViewGroup) {
EditText et = GetEditText((ViewGroup)v);
if (et != null) return et;
}
}
return null;
}
and altered my onCreateOptionsMenu(Menu)
function to include the following
DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
search_edit_text = GetEditText(mySearchView);
mySearchView_editflag = false;
This initializes the search_edit_text
and mySearchView_editflag
variables. My onResume()
method was altered to
@Override
public void onResume() {
super.onResume();
if (startsearch) {
DestinationTxt.expandActionView();
mySearchView_editflag = true;
}
}
and I included code which calls the following method at high frequency:
public void CheckStatus() {
if (mySearchView_editflag && imm.isActive(search_edit_text)) {
imm.showSoftInput(search_edit_text, 0);
mySearchView_editflag=false;
}
}
This app now works as I want it to, because following the activity switch when search input in the actionbar is required, the app now waits until imm.isActive(search_edit_text)
is true (which means the EditText
object is receiving input) before calling imm.showSoftInput(search_edit_text, 0)
to make sure that the keyboard is visible.
To help me work all this out, I used InputMethodManager.showSoftInput(View, int, ResultReceiver)
instead of InputMethodManager.showSoftInput(View, int)
, so instead of
imm.showSoftInput(search_edit_text, 0);
I had
ImmResultsReceiver irr = new ImmResultsReceiver();
imm.showSoftInput(search_edit_text, 0, irr);
where ImmResultsReceiver
is the class
public class ImmResultsReceiver extends ResultReceiver {
public ImmResultsReceiver() { super(null); }
@Override
protected void onReceiveResult (int resultCode, Bundle resultData) {
String descrip;
switch(resultCode) {
case InputMethodManager.RESULT_UNCHANGED_SHOWN: descrip = "RESULT_UNCHANGED_SHOWN"; break;
case InputMethodManager.RESULT_UNCHANGED_HIDDEN: descrip = "RESULT_UNCHANGED_HIDDEN"; break;
case InputMethodManager.RESULT_SHOWN: descrip = "RESULT_SHOWN"; break;
case InputMethodManager.RESULT_HIDDEN: descrip = "RESULT_HIDDEN"; break;
default:descrip="InputMethodManager("+resultCode+")"; break;
}
Log.d("MyLog", "ImmResultsReceiver,"+descrip+","+(resultData == null?"":"resultData.size()="+resultData.size()));
}
}
If the ImmResultsReceiver.onReceiveResult(...)
method is never called, it means that the call to InputMethodManager.showSoftInput(...)
has been ignored because the view that's passed to InputMethodManager.showSoftInput(...)
isn't the InputMethodManager's active view.