Search code examples
androidsearchautocompletekeyboardsearchview

Unusual keyboard behaviour when testing app on physical device


I have setup search as a menu item in the app bar (actionView is a searchView)

Behavior 1: works as expected in virtual device (Pixel 3 API 31, AS Chipmunk).

Typing from the keyboard and pressing the keyboard action key, submits the search query as expected. The search is performed and results returned as expected.

Pixel 3 API 31 emulator Android Studio Chipmunk 2021.2.1

Behaviour 2: works as expected in virtual device (Pixel 3 API 31, AS Chipmunk). Tapping a auto-complete suggestion and then pressing search key on keyboard does the same thing and works as expected.

Pixel 3 API 31 emulator Android Studio Chipmunk 2021.2.1

However testing on a real device (OPPO Reno 5G, API level 31):

  • Only behaviour 1 works as expected
  • Behaviour 2 returns nothing, but does NOT crash the app.

The only thing that's different is that on the OPPO real device the keyboard shows the row of number keys aswell.

The activity in the AndroidManifest is:

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable"/>


        </activity>

The searchable configuration is:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="search food name">

</searchable>

The app menu is defined in xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/search_box"
        android:icon="@drawable/ic_outline_search_24"
        android:title="Search"
        app:actionViewClass="android.widget.SearchView"
        app:showAsAction="ifRoom|withText" />
</menu>

And, the search is implemented in MainActivity's onCreateOptionsMenu() method:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.appbar_menu, menu);

        // associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.search_box).getActionView();
        MenuItem searchMenuItem = menu.findItem(R.id.search_box);

        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));



        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                doSearch(s);
                hideKeyboard(MainActivity.this);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });

    return super.onCreateOptionsMenu(menu);
    }

Solution

  • So in the stress of it all, I overlooked the method SearchView.getQuery();

    If a search interface is implemented in the Action Bar - that is, if the SearchView is the action view of a menu item, then:

    • pressing the search key on the soft keyboard automatically triggers
      OnQueryTextListener.onQueryTextSubmit(String s), passing into it the query string s
    • But, if the user selects an auto suggestion from the keyboard's suggestion bar, that String will appear in the SearchView's textfield but pressing the keyboard search action key will not submit the query, so:

    It is better to use SearchView.getQuery() - which returns the String in the textfield, rather than relying on just the action key on the keyboard.

    So my modified code, which works exactly as planned is:

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.appbar_menu, menu);
    
            // associate searchable configuration with the SearchView
            SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
            SearchView searchView = (SearchView) menu.findItem(R.id.search_box).getActionView();
            MenuItem searchMenuItem = menu.findItem(R.id.search_box);
    
            searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    
    
    
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String s) {
                    String query = (searchView.getQuery()).toString();
                    doSearch(query);
                    hideKeyboard(MainActivity.this);
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String s) {
                    return false;
                }
            });
    
        return super.onCreateOptionsMenu(menu);
        }