How to implement Voice search to SearchView - android

I want to add voice search function to my application. I'm populating a SearchView in SherlockActivity. But I can't find a solution to add voice search function to SearchView object.
Can you please give an advice, what do I need to do?
Code below :
public class MainActivity extends SherlockActivity {
private SlidingMenu slidingMenu;
private SlidingMenu slidingMenuRight;
private String mFilterArrays[];
public long lastScrollTime=0; /** En son kaydırma ne zaman yapıldı*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public boolean onCreateOptionsMenu(Menu menu) {
//Create the search view
SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
searchView.setQueryHint("Search...");
menu.add("Search")
.setIcon(R.drawable.ic_search_inverse)
.setActionView(searchView)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
return true;
}
}
Mainfest
<activity
android:name="com.paea.bcp.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.paea.bcp.MainActivity" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>

In your res/xml folder, you should have a searchable file (usually called searchable.xml).
Within the <searchable /> element in that file, you should add this attribute:
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
There are other voice-related attributes (currently voicePromptText, voiceLanguageModel and voiceLanguage) which are all described here.

You can check out the documentation here
Update: If your SearchActivity is the same one, you can override onNewIntent and handle the Search intent there. Also make your activity as singleTop, that way only one instance of the activity will stay on top.
Hope this helps and please do notify if you find a solution.
Cheers!

In case you have a SearchView and not a SearchActivity you can do these two steps to solve such problem:
Declare searchable settings in the manifest.xml inside activity's tags like this:
<meta-data android:name="android.app.searchable" android:resource="#xml/searchable" />
Then associate searchable settings with the SearchView in your activity class (i.e. in onCreateOptionsMenu() methods) like this:
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) findViewById(R.id.search);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
For more information see docs.

Related

Search interface starting new activities on search android

I am learning to work with the search bar. After the user hits search, it starts 2 new activities and these new activities no longer have a search bar. It also does not update the UI. I am looking to do a search and post the results all in the same activity, if possible. I am using Genymotion emmulator.
Main Activity
public class MainActivity extends Activity {
protected LibraryDataSource mDataSource;
protected ArrayList<String> mBookTitles;
protected ArrayList<Integer> mBookPages;
private EditText mEditText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDataSource = new LibraryDataSource(MainActivity.this);
mBookTitles = new ArrayList<>();
mBookPages = new ArrayList<>();
Book book1 = new Book("Harry potter", 15);
Book book2 = new Book("Far Cry", 25);
Book book3 = new Book("Jumpman", 35);
List<Book> books = new ArrayList<>();
books.add(book1);
books.add(book2);
books.add(book3);
mDataSource.open();
mDataSource.deleteAll();
mDataSource.insertBook(books);
mEditText = (EditText) findViewById(R.id.title_type);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.search) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Android Mainfest
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchBookActivity" />
</activity>
<activity android:name=".SearchBookActivity">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
</application>
SearchBookActivity
public class SearchBookActivity extends Activity {
LibraryDataSource mDataSource;
private EditText mEditText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.title_type);
mDataSource = new LibraryDataSource(SearchBookActivity.this);
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
//use the query to search your data somehow
Log.i("Search bar", query);
mDataSource.open();
mEditText.setText(mDataSource.searchKeyString(query));
}
}
}
I would use both <meta-data> tags together in the same activity where I want to centralise the Search feature. Although you could have more than one activity that supports search. Material Design apps show that having only one Search UI, Fragment or an Activity, is more effective and best practices for app production.
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchBookActivity" />
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
The daily case is searching a collection of data in a collection of data. Grids, Lists, etc.
You could have only one search Activity in your app that would get called each time you an Intent with action Search is started. This means from your app and from others. That's should for instance add permissions to your activity making sure that is not available to other apps unless is its function.
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.activity.SearchBookActivity" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
The above code will bring the SearchBookActivity when an Intent with android.intent.action.SEARCH is started. Then you should already be showing the Search View layout which will get the focus.
Another implementation would be to use a Fragment which doesn't require to listen to SEARCH actions or define any default search activity or permission.
Many apps do not require such a feature and use ListFragments with support of searching in ListView or RecyclerViews.
Either way, whether you use an Activity or a Fragment you would need to inflate the menu:
//From a Fragment
#Override
public void onCreateOptionsMenu(final Menu menu, MenuInflater inflater )
{
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_search, menu);
}
//From an Activity use public boolean onCreateOptionsMenu(Menu menu) in an Actiivty
with menu_search.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/search"
android:title="#string/search_label"
android:icon="#drawable/ic_actionbar_search"
app:actionViewClass="android.widget.SearchView"
android:actionViewClass="android.widget.SearchView"
app:showAsAction="always"/>
</menu>
Finally but not least. You could remove this code from the MainActivity. In the main activity you just need a menu item with a search icon.
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
Hope you implement your Search!! Check out Material Design.

Prevent activity to reload when clicking on SearchView

I have an activity with the new Toolbar. In this toolbar i have only one icon... my SearchView icon. When i click on that icon it opens an EditText in the Toolbar and im able to write what im looking for. The problem is that when i click on Search icon, the content of my Activity (FrameLayout with fragment) is reloaded.
EDIT:
plus: when click on icon, it reloads the activity and open EditText, after that the Activity SearchResult is called, and if i press the back button in that activity i return to the MainActivity and the searchview is still opened.
How to prevent that?
Thats my Manifest part of search (MainActivity has the icon):
<meta-data
android:name="android.app.default_searchable"
android:value=".activity.SearchResult_" />
<activity
android:name=".activity.MainActivity_"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"
android:screenOrientation="portrait" >
</activity>
<activity
android:name=".activity.SearchResult_"
android:label="#string/title_activity_search_result"
android:screenOrientation="portrait" >
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
Thast my OnCreateOptionsMenu:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchManager searchManager = (SearchManager) MainActivity.this.getSystemService(Context.SEARCH_SERVICE);
SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener()
{
public boolean onQueryTextChange(String newText)
{
Log.d("Query", newText);
return true;
}
public boolean onQueryTextSubmit(String query)
{
Log.d("Search", query);
SearchResult_.intent(MainActivity.this).extra("query", query).start();
return true;
}
};
SearchView searchView = null;
if (searchItem != null) {
searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
}
if (searchView != null) {
searchView.setSearchableInfo(searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
}
return super.onCreateOptionsMenu(menu);
}
I know I am late to the thread, but here is the proper solution. The way the SearchView default behavior works is that it will automatically send an ACTION.SEARCH intent to the searchable activity declared in your manifest. Upon sending, it will create a new instance of that activity, so that the onCreate() method can be called and the intent can be handled.
In order to work around this behavior, simply declare the launchMode for the searchable activity as 'SingleTop'. android:launchMode="singleTop"
According to Android documentation for "singleTop"
(https://developer.android.com/guide/components/activities/tasks-and-back-stack):
"If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance through a call to its onNewIntent() method, rather than creating a new instance of the activity." If you declare your searchable activity as 'singleTop', make sure you override onNewIntent() and handle the ACTION.SEARCH intent data accordingly.
In your onQueryTextSubmit method do:
searchView.setQuery (query, false);
You cant. unfortunately everyone has the same exact issue. searchViews always call the query when it is opened. no way to avoid it. I have seen some people have a boolean called first and set it to true. then only do logic if it is false. then on the first query call set it to false. not a good way but it should work
I don't know if that it is a bad practice, but I fix it like this:
#Override
protected void onResume() {
super.onResume();
if (searchView != null) {
if (searchView.getQuery().length() <= 0) {
searchView.setQuery("", false);
}
}
}

How to clear search result?

I have implemented search function using SearchManager and SearchView in the action bar. The same activity that shows the search view performs the search and shows the search result. This is working fine, and I can get the search query from the onNewIntent() without a problem.
When the user clicks the back button to get out of the search mode, I need to redisplay all items. How do I accomplish this? I tried intercepting OnDismiss and OnCancel of the search manager as well as the OnClose of the search view. Nothing ever gets called. Code below:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) this.getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
//Try to detect end of search session. None of the listeners getting called.
searchManager.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel() {//...}
});
searchManager.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss() {//...}
});
searchView.setOnCloseListener(new OnCloseListener() {
#Override
public boolean onClose() {
return false;
}
});
return true;
}
The manifest file entry for the activity is like this:
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop">
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I was facing the same problem, and I found the solution which is quite simple. If you are using the searchWidget (like me) you simply need to do this:
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
// Put your code here to clear and display the results
return false;
}
});
Because actually what are the user is closing is the SearchView, not the SearchManager. I've just test it and it works like a charm!
Hope this works for you.
Regards

How to reset a search using android SearchManager

I have one Activity with a fragment to list some data. I've already implemented the search using the SearchView (the nice looking search field on action bar).
The search is working fine, user input the data, press the search button and the results are filtered as expected.
My problem is that I can't "reset" the search back to all results. I already tried setting the Dismiss and Cancel listenners on the searchManager object but the onDismiss and oncancel methods are never being called.
Here is my action on the manifest:
<activity
android:name=".ClientesActivity"
android:label="#string/title_activity_clientes"
android:parentActivityName=".MenuPrincipalActivity"
android:launchMode="singleTop" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="MenuPrincipalActivity" />
<meta-data android:name="android.app.searchable"
android:resource="#xml/cliente_searchable" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
The methods on the ClientesActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
clientesService = new ClientesService(getBaseContext());
setContentView(R.layout.activity_clientes);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, ClienteFragment.newInstance(), ClienteFragment.class.getSimpleName())
.commit();
}
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if(Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
clientesService.findByNameLike(query);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.clientes, menu);
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(true);
return true;
}
It's not showing the Listenners because I rolled back the changes after nothing worked.
But basically o added the listenners before the 'return true' on the onCreateOptionsMenu method.
It was nothing fancy at first, just annonymous class overriding the interface with onDismiss method implemented, tried to put some logs there and the method was never called.
Take a look at android.widget.SearchView#setOnQueryTextFocusChangeListener. As far as I can tell the hasFocus will be true when the searchview is displayed and will not be called again with false until the user hits the upstack/back arrow to close the search. Oddly, I never see android.widget.SearchView#setOnCloseListener called
Alternately, implement an onOptionsItemSelected and call android.app.Activity#onSearchRequested() to trigger the search dialog in order to have those registered callback methods utilized.
#Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
onSearchRequested();//delegate upstream
break;
default:
return super.onOptionsItemSelected(item);
}
}
It's not very clear in the Invoking the search dialog documentation. I don't see it declared in the documentation. But it seems if you use just the search widget, the SearchManager callbacks are not triggered.

NullPointerException in Android code

The error is:
java.lang.NullPointerException.onCreateOptionsMenu(AddMyMarketsActivity.java:44)
My code is:
41 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
42 SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
43 SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
44 searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
Log.i("searchView", "set searchable configuration for searchView ");
What could be the problem with my code?
If you're using androids support libary to display your action bar, be sure you use the right actionViewClass in your SearchView declaration.
Should be app:actionViewClass="android.support.v7.widget.SearchView".
After that you can use as replacement for your code trying to get the ActionView:
MenuItem searchItem = menu.findItem(R.id.search_view);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
Be sure to call getMenuInfalter().inflate(...) before calling this.
More information: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView
I had the same error and it was removed by changing:
android:actionViewClass="android.widget.SearchView"
to
app:actionViewClass="android.widget.SearchView"
from menu.xml file
i.e change android: to app:
I'm describing the whole procedure of adding search view to action bar.This snippets of code worked for me.
Add search view in menu:add the following item in the menu layout of the activity in which you require search view.
<item
android:id="#+id/search"
android:title="#string/search_title"
android:icon="#drawable/ic_action_search"
app:showAsAction="collapseActionView|ifRoom"
app:actionViewClass="android.support.v7.widget.SearchView"/>
Note: menu layout file should contain following schema.
xmlns:app="http://schemas.android.com/apk/res-auto"
Create a Searchable Configuration:
create a file searchable.xml in the directory res/xml.
copy the following code into it.
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/app_name"
android:hint="#string/search_hint" />
Modify onCreateOptionsMenu() method:
In the onCreateOptionsMenu() method of your activity, associate the searchable configuration with the SearchView by calling setSearchableInfo(SearchableInfo):
Your onCreateOptionsMenu should look like this.
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_display_cards, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
//SearchView searchView =
// (SearchView) menu.findItem(R.id.search).getActionView();
MenuItem mSearchMenuItem = menu.findItem(R.id.search);
SearchView searchView =
(SearchView)MenuItemCompat.getActionView(mSearchMenuItem);
searchView.setSearchableInfo(searchManager.getSearchableInfo(
new ComponentName(getApplicationContext(),
SearchResultsActivity.class)));
return true;
}
Make an activity SearchResultsActivity to show the results of your search.
In the manifest file ,add the following
<activity
android:name=".SearchResultsActivity"
android:label="#string/title_activity_search_results" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable"
android:value=".SearchResultsActivity"/>
</activity>
Your SearchResultsActivity should implement the following methods
#Override
protected void onNewIntent(Intent intent) {
...
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
//use the query to search your data and show it in
//SearchResultsActivity
}
}
Note:You should call the following from onCreate method of SearchResultsActivity
handleIntent(getIntent());

Categories

Resources