Search intent not received by current activity - android

I am implementing an activity where I want to add a search bar. I want the current activity to receive the intent back. I followed couple of examples available and have added following code in my application:
AndroidManifest.xml
<activity
android:name=".search.BrowseCategory"
android:launchMode="singleTop"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
I added following in the AndroidManifest.xml under application tag:
<meta-data
android:name="android.app.default_searchable"
android:value=".search.BrowseCategory" />
Now in my BrowseCategory activity:
#Override
protected void onNewIntent(Intent intent) {
Log.d(getPackageName(), "Search intent received!");
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
// Do work using string
doSearch(query);
}
}
private void doSearch(String query) {...}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_filter, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.search:
startSearch("", false, null, false);
break;
}
return true;
}
Search Menu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/search"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="ifRoom"
android:title="#string/search"/>
</menu>
Searchable XML
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/search"
android:hint="#string/search" >
</searchable>
With this, I am getting a search field in my action bar. However, my onNewIntent in BrowseCategory activity is not getting call on pressing enter or search icon in soft keyboard. Can someone please help me with this issue? What am I missing here? Thanks a lot!

After searching more, I found a solution to my problem.
Keeping everything else same as I have posted above, I just updated my onCreateOptionsMenu(Menu menu) method in the Searchable activity (BrowseCategory in my case) with the code provided below:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_filter, menu);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();
search.setIconifiedByDefault(false);
search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
search.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String query) {
doSearch(query);
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
});
}
return true;
}
OnQueryTextListener is the key here! Adding this listeners triggers my search and now even pressing "Search" or "Go" on soft keyboard calls onNewIntent. About the later issue, reading from one of the answers in Cannot get searchview in actionbar to work I believe setting right SearchableInfo to searchview is important. Setting this is now triggering onNewIntent. If anyone knows more about it, please provide explanation. I will update if I find more on this too.

In BrowseCategory activity:
add this block
#Override
protected void onNewIntent(Intent intent) {
if (ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED.equals(intent.getAction())) {
//handles suggestion clicked query
String displayName = getDisplayNameForContact(intent);
resultText.setText(displayName);
}
//this else if is called when you will press Search Icon or Go (on soft keyboard)
else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// handles a search query
String query = intent.getStringExtra(SearchManager.QUERY);
resultText.setText("should search for query: '" + query + "'...");
}
}
Before click
After click

Related

onQueryTextChanged Method in the searchView method goes backwards without filtering/publishing search results

I have a strange issue with onQueryTextChanged method with SearchView in android. My problem is that when specific text e.g: "Al a" has been entered (i.e. right after entering in letter 'a' in the search Field) the searchView closes by itself. But if I enter in "Al A" i.e. capitalizing 'a' there is no issue. Similarly the same issue persists with "Al b", "Al c",.....etc etc. At first I thought it had something to do with escape sequences but that's not true. I am clueless, please help.
private void search(SearchView searchView) {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
System.out.println("text entered="+newText);
if (condition!= null) {
if (newText.length()!=0) { //if newText is not empty
} else {
isFiltersActive = false;
}
ListAdapter.getFilter().filter(newText);
} else
isFiltersActive = false;
return true;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
}
});
}
onQueryTextSubmit:
Called when the user submits the query. This could be due to a key
press on the keyboard or due to pressing a submit button. The listener
can override the standard behavior by returning true to indicate that
it has handled the submit request. Otherwise return false to let the
SearchView handle the submission by launching any associated intent.
Return true from onQueryTextSubmit function.
To Check whether String is empty or not, Use
TextUtils.isEmpty() Returns true if the string is null or 0-length.

Android : Search functionality with hint

Everybody,
I want to implement search on my app. I've been doing research here and there and some of it I can't really grasp. Android Search Listview using Filter is one of the very helpful example.
I want to implement a search functionality that give out a hint when I start searching. Also, when I clicked on the hint, it will move to the intended page.
For example, the hint is 'apple'. When I clicked on the hint it will directed me to the page of apple.
Is that possible?
Any site or tutorial that you can recommend for me?
Thanks!
I suggest you to use Material SearchView it worked for me.
MaterialSearchView searchView = (MaterialSearchView) findViewById(R.id.search_view);
searchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
//Do some magic
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
//Do some magic
return false;
}
});
searchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() {
#Override
public void onSearchViewShown() {
//Do some magic
}
#Override
public void onSearchViewClosed() {
//Do some magic
}
});
https://github.com/Shahroz16/material-searchview

Is there an advantage to using an Intent over an event listener launch in a search request?

I've looked over SO and cannot find a simple answer. Is there an advantage to using an Intent over an event listener on the search box for sending the text to the query event?
SearchView searchView =
(SearchView) MenuItemCompat.getActionView(searchMenuItem);
if(searchView != null){
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
#Override
public boolean onQueryTextSubmit(String s) {
Toast.makeText(getApplicationContext(),
"String entered is " + s, Toast.LENGTH_SHORT).show();
return true;
}
#Override
public boolean onQueryTextChange(String s) {
return false;
}
});
}
Versus using:
private void handleIntent(Intent intent){
if(Intent.ACTION_SEARCH.equals(intent.getAction())){
String query = intent.getStringExtra(SearchManager.QUERY);
Log.d(LOG_TAG, "QUERY: " + query);
new FetchArtistTask().execute(query);
}
}
Advantages of Intent:
The Intent can be directed to other Activities besides one with SearchView;
You can have single Activity handle search requests from multiple other Activities;
You can make full use of different Activity start modes and task stack while handling the Intent;
In addition to using SearchView the search Intent can triggered outside of Activities (e.g. in Dialogs and PopupWindows) by using The Search Dialog, making searching experience in your application more unified;
You can make a search Intent yourself to send from Service, when user clicks Notification/appwidget etc.
Advantages of listener:
Can be used to filter suggestion list as user types.
These two approaches aren't mutually exclusive, so you may just use both.

Execute Searches While Typing

I have a working searchable Activity that queries a remote database upon submitting input in the ActionBar's android.support.v7.widget.SearchView (entering "Go" on the soft keyboard). This works fine, but I would ultimately like to query the database each time the SearchView's text changes via adding or removing a character. My initialization code of the SearchView is below.
SearchFragment.java (child fragment of the searchable Activity mentioned above)
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_search, menu);
// Get the searchable.xml data about the search configuration
final SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
SearchableInfo searchInfo = searchManager.getSearchableInfo(getActivity().getComponentName());
// Associate searchable configuration with the SearchView
mSearchView = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
mSearchView.setSearchableInfo(searchInfo);
mSearchView.requestFocus();
mSearchView.onActionViewExpanded();
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
mSearchListAdapter.clear();
return false;
}
#Override
public boolean onQueryTextChange(String query) {
mSearchListAdapter.clear();
// Execute search ...
return false;
}
});
}
I imagine the work needs to be done within the onQueryTextChange(String query) method above, but I'm not sure what needs to be called. I thought of invoking the SearchManager's startSearch instance method, but that doesn't appear to be best practice. Does anyone have any experience with type-to-search and would be willing to share an efficient solution?
UPDATE:
MainActivity.java (the searchable Activity)
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// Handle the search for a particular musical object
final SearchFragment searchFragment = (SearchFragment) getFragmentManager().findFragmentByTag(SearchFragment.TAG);
String query = intent.getStringExtra(SearchManager.QUERY);
mWebService.searchTracks(query, new Callback<Pager>() {
#Override
public void success(Pager results, Response response) {
Log.d(TAG, "Search response received.");
searchFragment.updateItems(results);
}
#Override
public void failure(RetrofitError retrofitError) {
Log.e(TAG, "Search response failed: " + retrofitError.toString());
}
});
The above search interface design is what's recommended by the Android team at Google.
So far, the only solution that I have come across after reading through several pages of documentation is simply sending an intent with the Intent.ACTION_SEARCH action and the current query from the SearchView to start the searchable Activity whenever the SearchView's text changes. Keep in mind that this probably isn't the best practice in terms of the SearchManager design, but it works. I'll revisit this approach at a later date and report back here if I come across anything new.
#Override
public boolean onQueryTextChange(String query) {
mSearchListAdapter.clear();
if (!query.isEmpty()) {
Intent searchIntent = new Intent(getActivity(), MainActivity.class);
searchIntent.setAction(Intent.ACTION_SEARCH);
searchIntent.putExtra(SearchManager.QUERY, query);
startActivity(searchIntent);
}
return false;
}
A TextWatcher should be what you are looking for. It also offers for executing code before or after the text has changed.
http://developer.android.com/reference/android/text/TextWatcher.html
When an object of a type is attached to an Editable, its methods will be called when the text is changed.
This is the perfect solution for the issue you are looking for.
See this this will help you...
Android Action Bar SearchView as Autocomplete?
In case you're still looking for a better solution:
I just found this answer to a similar question, which uses
searchView.setOnQueryTextListener(this);
which is exactly what you want.

How to Navigate a Google Glass GDK Immersion Application using Voice Command only?

How would I go about coding a voice trigger to navigate Google Glass Cards?
This is how I see it happening:
1) "Ok Glass, Start My Program"
2) Application begins and shows the first card
3) User can say "Next Card" to move to the next card
(somewhat the equivalent of swiping forward when in the timeline)
4) User can say "Previous Card" to go back
The cards that I need to display are simple text and images, I'm wondering if I can setup a listener of some type to listen for voice commands while the card is being shown.
I've researched Glass voice command nearest match from given list but wasn't able to run the code, although I do have all the libraries.
side note: It's important that the user still see the card when using the voice command. Also his hands are busy so tap/swipe isn't an option.
Any ideas on how to control the timeline within my Immersion app using only voice control? would be greatly appreciated!
I am tracking https://code.google.com/p/google-glass-api/issues/detail?id=273 as well.
My ongoing research made me look back at Google Glass Developer to use Google's suggested way of listening to gestures: https://developers.google.com/glass/develop/gdk/input/touch#detecting_gestures_with_a_gesture_detector
How can we activate these gestures with voice commands?
Android just beta-released wearable devices upgrade for android http://developer.android.com/wear/notifications/remote-input.html, Is there a way we can use this to answer my question? it still feels like we are still 1-step away since we can call on the service but not have it "sleep" and "wake up" as a background service when we talk.
this thing define in onCreate method
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
// mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, true);
sr = SpeechRecognizer.createSpeechRecognizer(context);
sr.setRecognitionListener(new listener(context));
// intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,context.getPackageName());
sr.startListening(intent);
Log.i("111111","11111111"+"in");
This listener class simply add in your class
class listener implements RecognitionListener
{
Context context1;
public listener(Context context)
{
//Log.i("onError startListening","enter"+"nam");
context1=context;
}
public void onReadyForSpeech(Bundle params)
{
//Log.d(TAG, "onReadyForSpeech");
}
public void onBeginningOfSpeech()
{
//Log.d(TAG, "onBeginningOfSpeech");
}
public void onRmsChanged(float rmsdB)
{
//Log.d(TAG, "onRmsChanged");
}
public void onBufferReceived(byte[] buffer)
{
//Log.d(TAG, "onBufferReceived");
}
public void onEndOfSpeech()
{
//Log.d(TAG, "onEndofSpeech");
sr.startListening(intent);
}
public void onError(int error)
{
//Log.d(TAG, "error " + error);
//7 -No recognition result matched.
//9 - vInsufficient permissions
//6 - No speech input
//8 RecognitionService busy.
//5 Other client side errors.
//3 Audio recording error.
// mText.setText("error " + error);
if(error==6 || error==7 || error==4 || error==1 || error==2 || error==5 || error==3 || error==8 || error==9 )
{
sr.startListening(intent);
//Log.i("onError startListening","onError startListening"+error);
}
}
public void onResults(Bundle results)
{
//Log.v(TAG,"onResults" + results);
ArrayList data = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
for (int i = 0; i < data.size(); i++)
{
//Log.d(TAG, "result " + data.get(i));
//str += data.get(i);
//Toast.makeText(context1, "results: "+data.get(0).toString(), Toast.LENGTH_LONG).show();
//Log.v("my", "output"+"results: "+data.get(0).toString());
//sr.startListening(intent);
}
}
public void onPartialResults(Bundle partialResults)
{
//Log.d(TAG, "onPartialResults");
}
public void onEvent(int eventType, Bundle params)
{
//Log.d(TAG, "onEvent " + eventType);
}
}
I'm writing out the entire code in detail since it took me such a long time to get this working.. perhaps it'll save someone else valuable time.
This code is the implementation of Google Contextual Voice Commands as described on Google Developers here: Contextual voice commands
ContextualMenuActivity.java
package com.drace.contextualvoicecommands;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import com.drace.contextualvoicecommands.R;
import com.google.android.glass.view.WindowUtils;
public class ContextualMenuActivity extends Activity {
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Requests a voice menu on this activity. As for any other
// window feature, be sure to request this before
// setContentView() is called
getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
// Pass through to super to setup touch menu.
return super.onCreatePanelMenu(featureId, menu);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
switch (item.getItemId()) {
case R.id.dogs_menu_item:
// handle top-level dogs menu item
break;
case R.id.cats_menu_item:
// handle top-level cats menu item
break;
case R.id.lab_menu_item:
// handle second-level labrador menu item
break;
case R.id.golden_menu_item:
// handle second-level golden menu item
break;
case R.id.calico_menu_item:
// handle second-level calico menu item
break;
case R.id.cheshire_menu_item:
// handle second-level cheshire menu item
break;
default:
return true;
}
return true;
}
// Good practice to pass through to super if not handled
return super.onMenuItemSelected(featureId, item);
}
}
activity_main.xml (layout)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/coming_soon"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/voice_command_test"
android:textSize="22sp"
android:layout_marginRight="40px"
android:layout_marginTop="30px"
android:layout_marginLeft="210px" />
</RelativeLayout>
strings.xml
<resources>
<string name="app_name">Contextual voice commands</string>
<string name="voice_start_command">Voice commands</string>
<string name="voice_command_test">Say "Okay, Glass"</string>
<string name="show_me_dogs">Dogs</string>
<string name="labrador">labrador</string>
<string name="golden">golden</string>
<string name="show_me_cats">Cats</string>
<string name="cheshire">cheshire</string>
<string name="calico">calico</string>
</resources>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drace.contextualvoicecommands"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="com.drace.contextualvoicecommands.ContextualMenuActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data
android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/voice_trigger_start" />
</activity>
</application>
</manifest>
It's been Tested and works great under Google Glass XE22 !
You can try the snippet here: https://github.com/pscholl/glass_snippets/tree/master/hotword_detection.
You may want to try the contextual voice commands available in the GDK. While it does temporarily cover the screen with a menu, it allows voice-only input.
https://developers.google.com/glass/develop/gdk/voice
I did something very similar for one of my applications. It doesn't require the ok glass screen at all, but the user does need to know the commands ahead of time. I explained a bit of it and provided links on this question: Check out my answer here: Glass GDk : Contextual voice commands without the "Ok Glass"
I hope this helps!

Categories

Resources