Search code examples
androidandroid-intentandroid-appwidgetandroid-pendingintentappwidgetprovider

AppWidget setFillInIntent can't handle data set in setData or componentName?


I want to launch different applications from my app widget. The widget is a list of items and clicking an item should open an app like Google Plus. When pressing an item in the list nothing happens. When I remove setData and setComponentName it pops up a dialog asking what app to use. Is it not possible to merge data and componentname with the PendingIntent on appWidget collections?

My AppWidgetProvider looks like this:

public class StreamsWidgetProvider extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {

    final int N = appWidgetIds.length;

        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];

            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);

            ...

            //set service for list view
            Intent listIntent = new Intent(context, StreamsWidgetService.class);
            listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
            views.setRemoteAdapter(R.id.streamItemsList, listIntent);

            ...

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
            views.setPendingIntentTemplate(R.id.streamItemsList, pendingIntent);
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }

        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
}

}

And the StreamsWidgetService looks like this:

public class StreamsWidgetService extends RemoteViewsService {
    private static final String TAG = "StreamsWidgetService";

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return new StreamItemWidgetFactory(intent);
    }

    private class StreamItemWidgetFactory implements RemoteViewsService.RemoteViewsFactory {
        @Override
        public RemoteViews getViewAt(int position) {
            StreamItem item = mItems.get(position);

            RemoteViews rv = new RemoteViews(getPackageName(), R.layout.widget_item);
            ...

            Intent intent = new Intent();
            intent.setData(ContentUris.withAppendedId(StreamItems.CONTENT_URI, item.getId()));

            AccountType at = item.getAccountType();
            intent.setComponent(new ComponentName(at.getPackageName(), at.getViewStreamItemActivity()));
            rv.setOnClickFillInIntent(R.id.streamItemRowId, intent);
            Log.d(TAG, "FillIntent set for " + item.getId() + " at position " + position + " with data " + intent.getDataString() + " and component " + intent.getComponent().toString());

            return rv;
        }

        ...
    }
}

When using a normal activity without fillIntent this works:

final AccountType at = item.getAccountType();
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(ContentUris.withAppendedId(StreamItems.CONTENT_URI, item.getId()));
intent.setClassName(at.getPackageName(), at.getViewStreamItemActivity());
startActivity(intent);

How do I solve this? What is it that I'm doing wrong?


Solution

  • The PendingIntent does not allow the component to be filled-in unless you specifically request it.

    PendingIntent pendingIntent = PendingIntent.getActivity(context,
        0, intent, Intent.FILL_IN_COMPONENT);
    

    Note that this is different from the way the other FILL_IN_* flags work.