Like in this question (accepted answer), I'm trying to launch voice recognition from one of my app's widgets. I succesfully managed to open dialog that requests voice input with this code inside onUpdate()
method of the Widget:
// this intent points to activity that should handle results, doesn't work
Intent activityIntent = new Intent(SoulissApp.getAppContext(), WrapperActivity.class );
//doesn't work as well
//activityIntent.setComponent(new ComponentName("it.angelic.soulissclient", "it.angelic.soulissclient.WrapperActivity"));
// this intent wraps results activity intent
PendingIntent resultsPendingIntent = PendingIntent.getActivity(SoulissApp.getAppContext(), 0, activityIntent, 0);
// this intent calls the speech recognition
Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speech recognition demo");
voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, resultsPendingIntent);
Bundle fakeBun = new Bundle();
fakeBun.putChar("fake", 'f');
voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, fakeBun);
// this intent wraps voice recognition intent, works
PendingIntent pendingInt = PendingIntent.getActivity(context, 0, voiceIntent, 0);
updateViews.setOnClickPendingIntent(R.id.button1, pendingInt);
The speech recognition works, but at the end of the recognition process, my resultsPendingIntent
is not called. Why?
From sys log, I read this:
...I/ActivityManager﹕ START u0 {cmp=it.angelic.soulissclient/.SoulissWidgetVoice (has extras)} from uid 10152 on display 0......
while I'd expect something like:
...I/ActivityManager﹕ START u0 {cmp=it.angelic.soulissclient/.WrapperActivity(has extras)}...
because .WrapperActivity
is pending Intent while SoulissWidgetVoice
is the widget class. Note that WrapperActivity
itself can be correctly launched from other activities and it's a Theme.NoDisplay
basic activity:
<activity
android:name=".WrapperActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoDisplay"/>
This is fully functional, and it's based off the ListView in the Android SDK. It's not particularly for a widget, but I'm sure you can modify it so that it works for a widget.
Create an activity called SearchActivity:
// CustomSearch (View) & ISearch (Interface) are objects that I created and are irrelevant
public class SearchActivity extends AppCompatActivity implements ISearch
{
// Variables
private CustomSearch mSearchView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
mSearchView = (CustomSearch)findViewById(R.id.search);
mSearchView.setPendingComponentName(getComponentName());
mSearchView.setSearchListener(this);
}
@Override
protected void onNewIntent(Intent intent)
{
if (Intent.ACTION_SEARCH.equals(intent.getAction()))
{
String query = intent.getStringExtra(SearchManager.QUERY);
Log.i("SEARCH >", "You said: " + query);
}
}
}
Add activity to the AndroidManifest.xml
<activity
android:name=".activities.SearchActivity"
android:label="@string/app_name"
android:theme="@style/CustomTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
</activity>
In your custom Widget/View:
buttonVoice.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// Get activity from either SearchableInfo or ComponentName
ComponentName searchActivity = mComponentName;
// Wrap component in intent
Intent queryIntent = new Intent(Intent.ACTION_SEARCH);
queryIntent.setComponent(searchActivity);
// Wrap query intent in pending intent
PendingIntent pending = PendingIntent.getActivity(getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT);
// Create bundle now because if we wrap it in pending intent, it becomes immutable
Bundle queryExtras = new Bundle();
// Create voice intent
Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZER_SPEECH);
voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak");
voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity
voiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Wrap the pending intent & bundle inside the voice intent
voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending);
voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras);
// Start the voice search
getContext().startActivity(voiceIntent);
}
}