Providing a manual input method for 4.9+

Along with the new and cleaner class names in the Scandit Barcode Scanner 4.9 the new API no longer contains a default manual input method that can be displayed to let the user enter the barcode through the use of the keyboard. This adjustment was made because adding your own search bar is very simple and was oftentimes necessary to nicely integrate it into the app around the scanner and customize it accordingly.

This guide will show you how to add a basic search bar to the BarcodePicker on Android 3.0 and higher. You should adjust the code from this guide to make the search bar match your own needs and your app's look and feel.

Make use of SearchView

The simplest way of adding a search is by using the SearchView that is provided by Android itself and for which there exists an extensive tutorial at http://developer.android.com/training/search/index.html. The main limitation of this method is that the search results have to be opened in their own Activity which may not be what you want to do.

Implement your own search

The alternative is to implement your own version of a search. In the following sections we will show one way of doing this.

Start with an EditText

The basic building block for a search will be an EditText which we define as a class variable.

private EditText mSearchText;

We want to start a search as soon as the user presses return. For this we add the following listener:

mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
Log.e("ScanditSDK", "searching for " + textView.getText());
closeSearchBar();
return true;
}
return false;
}
});

Integrating the Search

In this example we will show how to integrate the search into an ActionBar which has become a standard UI pattern for most Android apps. In case your app is not showing an ActionBar you can always add the EditText somewhere else in your apps view hierarchy like on top of the BarcodePicker (which is a RelativeLayout that you can add views to as usual).

There are essentially two options how to display the search, either we always display an active EditText in the ActionBar or we have a button that shows (and hides) the EditText which potentially makes space for more buttons on the ActionBar. The latter is what we will show but the example can easily be changed to show the search all the time.

Continuing our action bar search example we first have to add a new action to the bar which we do in the menu.xml of our project:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
<item android:id="@+id/action_search"
android:title="@string/action_search"
android:icon="@drawable/ic_action_search"
yourapp:showAsAction="always" />
(...)
</menu>

We add a new layout file (under res/layout/) called search_bar.xml which contains the EditText that we later set as the ActionBar's custom view and use as the search bar.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/searchText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"/>
</LinearLayout>

We need some more class variables at this point. A boolean to save the state of the search bar, whether it is shown or not. Two drawables for the two different icons that are used for the search action depending on whether it should indicate that it shows or hides the search. We set the drawables in the Activity's onCreate method. We also need to save the search action menu item such that we are able to change its icon.

private boolean mSearchOpened;
private Drawable mIconOpenSearch;
private Drawable mIconCloseSearch;
private MenuItem mSearchAction;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
mIconOpenSearch = getResources().getDrawable(R.drawable.action_open_search);
mIconCloseSearch = getResources().getDrawable(R.drawable.action_close_search);
}

We add the behavior for the search action in onOptionsItemSelected to call functions to open or close the search bar depending on its current state.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
(...)
case R.id.action_search:
if (mSearchOpened) {
closeSearchBar();
} else {
openSearchBar();
}
return true;
}
}

In onPrepareOptionsMenu we set mSearchAction to the search action menu item.

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
mSearchAction = menu.findItem(R.id.action_search);
return super.onPrepareOptionsMenu(menu);
}

At this point we are only missing the functions to open and close the search bar:

private void openSearchBar() {
// Add our search bar containing layout as a custom view to the ActionBar.
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(R.layout.search_bar);
// Get a reference to the EditText and listen for the return key.
mSearchText = (EditText) actionBar.getCustomView().findViewById(R.id.searchText);
mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
Log.e("ScanditSDK", "searching for " + textView.getText());
closeSearchBar();
return true;
}
return false;
}
});
mSearchText.setText(queryText);
mSearchText.requestFocus();
// Make sure that the keyboard is shown.
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mSearchText, InputMethodManager.SHOW_FORCED);
// Change the search state.
mSearchOpened = true;
// Change search icon to indicate that it closes the search.
mSearchAction.setIcon(mIconCloseSearch);
// We want to leave the search if the user taps on the barcode scanner.
mPicker.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
closeSearchBar();
mPicker.setOnTouchListener(null);
return true;
}
});
}
private void closeSearchBar() {
// Hide the keyboard.
InputMethodManager imm = (InputMethodManager)
MainActivity.this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchText.getWindowToken(), 0);
// Remove the search bar from the ActionBar.
getSupportActionBar().setDisplayShowCustomEnabled(false);
// Change the search state.
mSearchOpened = false;
// Change search icon to indicate that it opens the search.
mSearchAction.setIcon(mIconOpenSearch);
}

Further improvements

You can further improve this search by saving the search string and the search bar state in onSaveInstanceState and restore them in onCreate to make sure that the search stays the same even when changing the device's rotation.