Android pending intent not being called within wid

2019-04-17 01:07发布

问题:

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"/>

回答1:

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);
    }
}