2

I have a problem (2 problems to be exact) with launching intents from a Notification.

My current situation is that I have a family of apk that all can use a remote service launched by the first of them. The service creates an Notification and when clicked the opens back the application that launched the service. This works ok.

I wanted to improve that so when there is more than one application from the family installed, instead of just going to the apk that launched the service an chooser Intent would appear and the user would be able to choose the apk to come back to.

I managed to do this.

   ArrayList<String> myApps = Lists.newArrayList(
          "com.myapp1",
          "com.myapp2",
          "com.myapp3",
          "com.myapp4"
   );

   List<Intent> targetedIntents = new ArrayList<Intent>();

   Intent baseIntent = new Intent(Intent.ACTION_MAIN, null);
   baseIntent.addCategory("android.intent.category.LAUNCHER");

   final PackageManager packageManager = getApplicationContext().getPackageManager();
   List<ResolveInfo> list = packageManager.queryIntentActivities(baseIntent, 0);

   for (ResolveInfo resolveInfo : list) {
          String packageName  = resolveInfo.activityInfo.packageName;
          if (packageName != null && myApps.contains(packageName)) {

                 Intent targetedIntent = new Intent();
                 targetedIntent.setPackage(packageName);
                 targetedIntent.setClassName(packageName, resolveInfo.activityInfo.name);
                 targetedIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

                 targetedIntents.add(targetedIntent);
          }
   }

   Intent intent = Intent.createChooser(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=whatever")), "Select app to return to");
   intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[]{}));

   PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, intent.getFlags());
   notification.setLatestEventInfo(this, notificationTitle, notificationMessage, contentIntent);

This works mostly as it should. The chooser appears and the selected option launches the desired apk.

But I came across 2 problems:

I. When I create the intent chooser with only the intents that interest me, the chooser is empty with the message "no application can perform this action"

     intent = Intent.createChooser(targetedIntents.get(0), "Select app to return to");
     intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[]{}));

But if I put an existing apk there first (such as google play) everything works and my options show along with the google play option.

     intent = Intent.createChooser(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=whatever")), "Select app to return to");
     intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[]{}));

This is something I can live with, but it would be better if onlye the proper apks were there.

II. When I click the apk from the list, instead of coming back from the background (if the apk was already running there) it restarts it. I have the proper flags set.

    Intent targetedIntent = new Intent();
    targetedIntent.setPackage(packageName);
    targetedIntent.setClassName(packageName, resolveInfo.activityInfo.name);
    targetedIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

Before using the chooser I launched only one intent and it resummed the background apk normally.

    intent = new Intent(this, MainActivity.class);
    intent.setAction("android.intent.action.MAIN");
    intent.addCategory("android.intent.category.LAUNCHER");

Not sure what I am doing wrong here that the apk restarts insted of resuming.

Community
  • 1
  • 1
darkhie
  • 263
  • 1
  • 15

1 Answers1

2

For the first problem (chooser issue), the reason you are getting the error "no application can perform this action" is because the Intent you are passing to getChooser() doesn't have an ACTION in it that Android can use to search for applications that can handle the Intent. getChooser will use the ACTION, CATEGORY and DATA in the Intent to search for suitable applications. It will then use package and component names to filter this list. In your case, because you've only provided the package and component names (but haven't specified ACTION), Android can't find any suitable applications. I'm not sure there's a way around this, since you want to build a list with different packages. You may just need to create your own chooser dialog (which is probably the correct thing to do here anyway, as you don't really get any advantages using the Android chooser because you've already decided what the list should contain).


For the second problem (if application is in background, it gets restarted) you need to use the following flags:

targetedIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

Specifying Intent.FLAG_ACTIVITY_NEW_TASK when launching the root activity of a task will bring an already existing task to the foreground.

NOTE: If you want to just bring the existing task to the foreground (in whatever state it happens to be), then just use Intent.FLAG_ACTIVITY_NEW_TASK and remove the other 2 flags.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • The solution for the second for the second problem works ok. I have a question about building my own dialog for the chooser (I figured that was the only resonable solution here): how would I go about that, since the chooser is launched from the pendingIntent ? (I cannot just launch a dialog from nowhere) – darkhie Oct 21 '13 at 13:49
  • From your notification you can launch an activity that looks like a dialog. Search StackOverflow and you will find examples. – David Wasser Oct 21 '13 at 14:08