4

I'm developing a drawing application and I want to allow user to share his drawings within email, social networks, etc. I know, there is a ShareActionProvider class, but there is a one big problem with it.

Content of my application updates rapidly, so I'm not able to call setShareIntent() every time user starts or ends drawing. It's obvious, that intent should be created when user press on share button. But, unfortunately, there is no on click listeners or something like that. And that is a problem.

Any solutions?

Dmitry Zaytsev
  • 23,650
  • 14
  • 92
  • 146

4 Answers4

4

Add an action bar to your application.

Then you can add a "Share" icon in the action bar:

<item android:id="@+id/action_share"
  android:icon="@android:drawable/ic_menu_share" ... />

and

public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
    case R.id.action_share:
      Intent intent = new Intent(Intent.ACTION_SEND);
      intent.setType("image/jpeg");
      intent.putExtra(Intent.EXTRA_SUBJECT, "Subject text");
      intent.putExtra(Intent.EXTRA_TEXT, "Detailed description");
      intent.putExtra(Intent.EXTRA_STREAM, getPubliclyAccessibleUriOfAnImage());
      startActivity(Intent.createChooser(intent, "Share my dynamic image"));
      return true;

Using a MENU item could be another solution, but it is not very trendy.

Nicolas Raoul
  • 58,567
  • 58
  • 222
  • 373
2

This answer has no solution, I rate this task impossible without fully rolling your own.

I totally agree, it should pull the data using a listener when it's required, but at the same time it works this way because it shows only the apps that can handle the intent.

It means that you have to provide the intent before being able to share it, to let the <intent-filter>s do their thing and filter the incompatible activities. The problem comes when the filter contains a <data> element which filters the Uri and MimeType.

Let's try to work around this.

Use OnShareTargetSelectedListener

@hannes arch was on to something, but the answer is missing from the answer which would be doSomeStuff's implementation.

Ah it returns boolean, let's update the intent and do a startActivity(intent) and return true to signify we handled it. It turns out that ShareActivityChooserModelPolicy ignores the return value of onShareTargetSelected, so we can't use that.

Doing so kind of works, but it'll open to of the same activities with different content (the original intent and the modified one). Not so kind to the user.

Extend ShareActionProvider

and replicate logic needed for ShareActivityChooserModelPolicy and return the value returned from the listener. This way our return true would work. Instead it doesn't. We lose the ability to have history of selected apps.

Extend ShareActionProvider take 2

I tried and tried, there's just no possible way to extends this class, even with nasty reflection and setAccessible calls. It's too rigid.

Copy ShareActionProvider

and related classes. Nope, it won't work it has some Android internal class depedencies.

Closing words

I just wonder what

the behavior is extensible and extensions of ShareActionProvider can perform different behaviors and ranking based on the history file (if appropriate).

means from https://developer.android.com/guide/topics/ui/actionbar.html

Community
  • 1
  • 1
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
1

This is my way

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.mymenu, menu);

    MenuItem actionItem = menu.findItem(R.id.mymenu_item);
    ShareActionProvider actionProvider = (ShareActionProvider) actionItem.getActionProvider();
    actionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);       actionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {

    public boolean onShareTargetSelected(ShareActionProvider source,
                Intent intent) {
            doSomeStuff();//TODO
            return false;
    }} );
    actionProvider.setShareIntent(createShareIntent());

    MenuItem overflowItem = menu.findItem(R.id.mymenu_item);
    ShareActionProvider overflowProvider = (ShareActionProvider) overflowItem.getActionProvider();
    overflowProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
    overflowProvider.onPerformDefaultAction();
    overflowProvider.setShareIntent(createShareIntent());

    return super.onCreateOptionsMenu(menu);
}
hannes ach
  • 16,247
  • 7
  • 61
  • 84
0

I hit a similar issue with a android.support.v7.app.ActionBarActivity derivative (though I think this approach should work for any activity) and I overrode onPrepareOptionsMenu and got the effect you are after:

private ShareActionProvider actionProvider;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.mymenu, menu);

    // get the share menu item
    MenuItem actionItem = menu.findItem(R.id.share_menu_item);
    actionProvider = (ShareActionProvider) actionItem.getActionProvider();

    return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if (actionProvider != null) {
        actionProvider.setShareIntent(createShareIntent());
    }
    return super.onPrepareOptionsMenu(menu);
}

private Intent createShareIntent() {
    // ripped from @nicolas-raoul answer
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setType("image/jpeg");
    intent.putExtra(Intent.EXTRA_SUBJECT, "Subject text");
    intent.putExtra(Intent.EXTRA_TEXT, "Detailed description");
    intent.putExtra(Intent.EXTRA_STREAM, getPubliclyAccessibleUriOfAnImage());
    return intent;
}

See also: Android setShareIntent within fragment

Community
  • 1
  • 1
John Cummings
  • 1,949
  • 3
  • 22
  • 38