36

I would like to use new version of Intent.createChooser method which uses IntentSender.

Documentation states only that I can grab it from PendingIntent instance. In my case it seems that PendingIntent won't have any other use.

Is there another way to obtain IntentSender or do I need create PendingIntent?

pixel
  • 24,905
  • 36
  • 149
  • 251

2 Answers2

67

The chooser target intent is not a PendingIntent. For instance, in the following snippet, I am declaring intent for ACTION_SEND, with type text/plain, and this is the my target intent for the Intent.createChooser. Then I am creating another Intent, receiver, and a handler, the PendingIntent, which will invoke onReceive of my BroadcastReceiver after the user picks something from the chooser.

// Set up the broadcast receiver (preferably as a class member)
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
     @Override
     public void onReceive(Context context, Intent intent) {
         // Unregister self right away
         context.unregisterReceiver(this);

         // Component will hold the package info of the app the user chose
         ComponentName component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_CHOSEN_COMPONENT);
         // Do something with component
     }
}


Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
intent.setType("text/plain");

// Use custom action only for your app to receive the broadcast
final String shareAction = "com.yourdomain.share.SHARE_ACTION";
Intent receiver = new Intent(shareAction);
receiver.putExtra("test", "test");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
Intent chooser = Intent.createChooser(intent, "test", pendingIntent.getIntentSender());

// Before firing chooser activity, register the receiver with our custom action from above so that we receive the chosen app
context.registerReceiver(broadcastReceiver, new IntentFilter(SHARE_ACTION));

startActivity(chooser);

Edit:

The information, in the case of the BroadcastReceiver is embedded in the intent you get as parameter. After you selected one of the option, retrieve the Bundle's extras and using the key Intent.EXTRA_CHOSEN_COMPONENT, you should be able to find what the user picked.

Try adding as simple Log.d to onReceive

for (String key : intent.getExtras().keySet()) {
    Log.d(getClass().getSimpleName(), " " + intent.getExtras().get(key));
}

In my example I got

ComponentInfo{org.telegram.messenger/org.telegram.ui.LaunchActivity}

for Telegram and

ComponentInfo{com.google.android.apps.inbox/com.google.android.apps.bigtop.activities.ComposeMessageActivity}

for InBox

James
  • 4,573
  • 29
  • 32
Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • 1
    Ok and how to get info what choice was taken by user? Documentation states `The caller may optionally supply an IntentSender to receive a callback when the user makes a choice. This can be useful if the calling application wants to remember the last chosen target and surface it as a more prominent or one-touch affordance elsewhere in the UI for next time.` – pixel Jun 10 '15 at 06:59
  • 10
    don't forget to add your broadcast register class to your manifest – Shinta S Dec 15 '15 at 23:48
  • 6
    Is there any code sample that I can take a look how to do this? My broadcast receiver doesn't receive anything. – Migore Mar 06 '16 at 22:17
  • 3
    My broadcast receiver also isn't working. Could you please show how you hooked up the broadcast receiver? I am registering it in my activity but am not sure what to use for the intent filter. – clocksmith Sep 02 '16 at 21:00
  • 5
    what we do , when api level is bellow than 22 – shekhar pande Apr 27 '17 at 13:46
  • Can we see `BroadcastTest.class` implementation? – Starwave Aug 23 '19 at 02:12
  • not receiving the broadcast in Android 9.0. It is working in 7.0 – Usman Rana Jan 28 '20 at 10:27
  • Not receiving test extra parameter in onReceive – sgallego Apr 23 '20 at 14:44
  • 4
    1. this createChooser available on API >= 22 2. the approach doesn't work for me. onReceive is called immidiately when chooser opens and not calling when select some app from chooser. – kissed Apr 30 '20 at 13:17
  • I improved the example code snippet to include also the setup of a broadcast receiver – Nimrod Dayan Jul 28 '20 at 10:41
  • use this to receive broadcast context.registerReceiver(receiver, new IntentFilter(shareAction)); – Mohit Dholakia Sep 02 '20 at 12:54
  • You'll probably also want to unregister the broadcastReceiver in `onResume()` or else if the user hits the back button when the share sheet appears then does an action to create another broadcastReceiver, you'll end up with multiple. – James Jan 21 '22 at 23:46
  • 2
    Also note, your `PendingIntent` flag should be `if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE else PendingIntent.FLAG_UPDATE_CURRENT` – James Jan 21 '22 at 23:49
  • @ShintaS how do you add your broadcast register class to your manifest ? Thanks – toto_tata May 25 '22 at 11:09
  • 1
    onReceive is called, but component is always null for me. Tried on different OS versions – Aleksandr Urzhumtcev Nov 24 '22 at 17:43
  • 1
    @AleksandrUrzhumtcev use PendingIntent.FLAG_MUTABLE instead of PendingIntent.FLAG_IMMUTABLE as James as mentioned in his comment. – Usman Rana Feb 10 '23 at 11:06
0

Another way to do it.

    /**
     * Receiver to record the chosen component when sharing an Intent.
     */
    static class TargetChosenReceiver extends BroadcastReceiver {
        private static final String EXTRA_RECEIVER_TOKEN = "receiver_token";
        private static final Object LOCK = new Object();

        private static String sTargetChosenReceiveAction;
        private static TargetChosenReceiver sLastRegisteredReceiver;

        static boolean isSupported() {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
        }

        @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
        static void sendChooserIntent(Activity activity, Intent sharingIntent) {
            synchronized (LOCK) {
                if (sTargetChosenReceiveAction == null) {
                    sTargetChosenReceiveAction = activity.getPackageName() + "/"
                            + TargetChosenReceiver.class.getName() + "_ACTION";
                }
                Context context = activity.getApplicationContext();
                if (sLastRegisteredReceiver != null) {
                    context.unregisterReceiver(sLastRegisteredReceiver);
                }
                sLastRegisteredReceiver = new TargetChosenReceiver();
                context.registerReceiver(
                        sLastRegisteredReceiver, new IntentFilter(sTargetChosenReceiveAction));
            }

            Intent intent = new Intent(sTargetChosenReceiveAction);
            intent.setPackage(activity.getPackageName());
            intent.putExtra(EXTRA_RECEIVER_TOKEN, sLastRegisteredReceiver.hashCode());
            final PendingIntent callback = PendingIntent.getBroadcast(activity, 0, intent,
                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
            Intent chooserIntent = Intent.createChooser(sharingIntent,
                    activity.getString(R.string.share_link_chooser_title),
                    callback.getIntentSender());
            activity.startActivity(chooserIntent);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            synchronized (LOCK) {
                if (sLastRegisteredReceiver != this) return;
                context.getApplicationContext().unregisterReceiver(sLastRegisteredReceiver);
                sLastRegisteredReceiver = null;
            }
            if (!intent.hasExtra(EXTRA_RECEIVER_TOKEN)
                    || intent.getIntExtra(EXTRA_RECEIVER_TOKEN, 0) != this.hashCode()) {
                return;
            }

            ComponentName target = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT);
            if (target != null) {
                setLastShareComponentName(context, target);
            }
        }
    }
phnmnn
  • 12,813
  • 11
  • 47
  • 64