I launch the Android Sharesheet with an ACTION_SEND intent to share an image. After the user selects the X (Twitter) app, I need to know whether the post was completed or canceled.
The relevant code is:
var chosenComponent: ComponentName? = null val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { chosenComponent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { intent?.getParcelableExtra( Intent.EXTRA_CHOSEN_COMPONENT, ComponentName::class.java ) } else { @Suppress("DEPRECATION") intent?.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT) } } } val launcher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> Log.d("ShareResult", "resultCode=${result.resultCode}") Log.d("ShareResult", "component=$chosenComponent") }
The share intent is created as follows:
val shareIntent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_STREAM, imageUri) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) type = "image/jpeg" } val callbackIntent = Intent(SHARE_ACTION).setPackage(packageName) val pendingIntent = PendingIntent.getBroadcast( this, 0, callbackIntent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) launcher.launch( Intent.createChooser( shareIntent, null, pendingIntent.intentSender ) )
Environment:
compileSdk: 36
targetSdk: 36
minSdk: 26
Device: Pixel 7a
X app: 12.9.1-release.0
Selected activity:
com.twitter.android/com.x.android.lib.ComposerActivity
The X app appears to have recently undergone a significant internal migration. On the affected version, the previously used activity:
com.twitter.composer.ComposerActivity
is disabled, while the new activity:
com.x.android.lib.ComposerActivity
is enabled and handles the share intent.
Because both the activity implementation and its package namespace changed around the time this behavior started, I suspect this may be related to a recent major internal change in the X Android app. However, I cannot determine whether returning RESULT_CANCELED is an intentional behavior change or an unintended regression.
The chooser callback correctly reports the selected component:
com.twitter.android/com.x.android.lib.ComposerActivity
However, the activity result is always:
ActivityResult{resultCode=RESULT_CANCELED, data=null}
This happens in both cases:
The user successfully publishes the post.
The user cancels the composer without publishing.
Previous versions of the X app returned RESULT_OK after a successful post, but the current version appears to return RESULT_CANCELED in both cases.
I understand that the chooser IntentSender only reports which target was selected, not whether the operation inside the target app succeeded. The ACTION_SEND documentation also specifies no output contract.
My questions are:
Is a receiving app handling ACTION_SEND required to call setResult(RESULT_OK) when the operation succeeds?
Is there any standard Android API that can distinguish a successful share/post from cancellation?
If the receiving app does not provide a meaningful result code, is selecting the share target the only signal available to the sending app?
I would prefer not to treat selecting X as a successful post, because the user may still cancel the composer.
> I launch the Android Sharesheet with an ACTION_SEND intent to share an image.
You do so using ActivityResultContracts.StartActivityForResult. As you noted, ACTION_SEND is documented to have no output, which means it is not designed to work with StartActivityForResult.
> Is a receiving app handling ACTION_SEND required to call setResult(RESULT_OK) when the operation succeeds?
Yes. And, since they are not supposed to do that for ACTION_SEND, few will do so. If X used to do so, arguably that was a bug on their part.
> Is there any standard Android API that can distinguish a successful share/post from cancellation?
No.
CommonsWare