2

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?

Daverix
  • 399
  • 2
  • 16

2 Answers2

3

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.

j__m
  • 9,392
  • 1
  • 32
  • 56
  • I will try this and set you answer as the accepted answer if it works. :) – Daverix Dec 13 '13 at 23:39
  • I was using method from [Daverix answer](http://stackoverflow.com/a/12727542/1105473) but it looked quite slow. So I tried to start Activity directly from click, and achieved it with your answer, but it doesn't look any faster. Is it 'normal'? Could I expect better? – Eloar Jan 07 '15 at 20:52
  • If your app has been removed from memory, Daverix's answer will require it to be loaded back into memory, whereas this answer will allow a tap to directly launch the destination app without ever loading yours, which is potentially significantly faster. However, if the device has plenty of memory, this difference isn't going to matter. The main factors affecting response time are going to be what the launcher is doing and what the other app is doing, neither of which you have any control over. – j__m Jan 07 '15 at 22:26
2

I solved this by using a broadcast intent to my own AppWidgetProvider. I have my own Action that I check for in onReceive. I then set the fillInIntent with parameters for the package name, class name and data id. Using this in the onReceive method I can create a new intent that looks exactly like the intent in my ListActivity.

In the Service:

Intent intent = new Intent();
intent.putExtra(StreamsWidgetProvider.BROADCAST_PARAM_ITEM_ID, item.getId());
AccountType at = item.getAccountType();
intent.putExtra(StreamsWidgetProvider.BROADCAST_PARAM_CLASS_NAME, at.getViewStreamItemActivity());
intent.putExtra(StreamsWidgetProvider.BROADCAST_PARAM_PACKAGE_NAME, at.getPackageName());

rv.setOnClickFillInIntent(R.id.streamItemRowId, intent);

In the AppWidgetProvider:

public static final String ACTION_START_ACTIVITY = "startActivity";
public static final String BROADCAST_PARAM_ITEM_ID = "intentId";
public static final String BROADCAST_PARAM_PACKAGE_NAME = "intentPackage";
public static final String BROADCAST_PARAM_CLASS_NAME = "intentClassName";

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

        ...

        Intent intent = new Intent(context, StreamsWidgetProvider.class);
        intent.setAction(ACTION_START_ACTIVITY);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
        views.setPendingIntentTemplate(R.id.streamItemsList, pendingIntent);

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

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

@Override
public void onReceive(Context context, Intent intent) {
    if(ACTION_START_ACTIVITY.equals(intent.getAction())) {
        long itemId = intent.getLongExtra(BROADCAST_PARAM_ITEM_ID, 0);
        String packageName = intent.getStringExtra(BROADCAST_PARAM_PACKAGE_NAME);
        String className = intent.getStringExtra(BROADCAST_PARAM_CLASS_NAME);

        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(ContentUris.withAppendedId(StreamItems.CONTENT_URI, itemId));
        i.setComponent(new ComponentName(packageName, className));
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        context.startActivity(i);
    }

    super.onReceive(context, intent);
}
Daverix
  • 399
  • 2
  • 16