0

I've looked at all relevant similar post and not one answers my question.

My program sets up a ShareActionProvider to take a screenshot of the current view and share it with any app that can interact with .png images.

Problem: The shared screenshot is always the previous screenshot meaning that I have to click the share button in the action bar twice to get a screenshot of the current page or fragment view. I want the user to be able to just press the button once. Additionally, is it possible to not have screenshot taken when the activity is first created but wait until the share button is pressed.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);

    // Find the MenuItem that we know has the ShareActionProvider
    MenuItem shareItem = menu.findItem(R.id.menu_item_share);

    // Get its ShareActionProvider
    mShareActionProvider = (ShareActionProvider) shareItem.getActionProvider();

    setShareIntent(getDefaultScreenshotShareIntent());

    mShareActionProvider.setOnShareTargetSelectedListener(MainActivity.this);

    // Return true so Android will know we want to display the menu
    return true;
}

public boolean onShareTargetSelected (ShareActionProvider source, Intent intent) {

    setShareIntent(getDefaultScreenshotShareIntent());

    return false;
}

// Call to update the share intent
// Connect the dots: give the ShareActionProvider its Share Intent
private void setShareIntent(Intent shareIntent) {
    if (mShareActionProvider != null) {
        mShareActionProvider.setShareIntent(shareIntent);
    }
}

private Uri saveScreenShotDirectoryLocation() {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, "Some Title");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            values);

    return uri;
}

private void screenShotHandler(Uri uri) {
    Bitmap screenShot = takeScreenShot(MainActivity.this);

    OutputStream outstream;
    try {
        outstream = getContentResolver().openOutputStream(uri);
        screenShot.compress(Bitmap.CompressFormat.PNG, 100, outstream);
        outstream.flush();
        outstream.close();
    } catch (Exception e) {
        System.err.println(e.toString());
    }
}

private Intent getDefaultScreenshotShareIntent() {

    Uri uri = saveScreenShotDirectoryLocation();

    Intent intent = new Intent(Intent.ACTION_SEND);

    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    intent.setType("image/png");

    long currenttime = System.currentTimeMillis();

    intent.putExtra(Intent.EXTRA_SUBJECT, "Some Title" + currenttime);

    File path = Environment.getDataDirectory();
    long usablePartitionSpace = path.getUsableSpace();

    if (usablePartitionSpace >= SCREENSHOT_FILE_SIZE_IN_BYTES ) {
        screenShotHandler(uri);
        intent.putExtra(Intent.EXTRA_STREAM, uri);
    } else {
        Toast.makeText(this, "Not enough freespace for screenshot", Toast.LENGTH_SHORT).show();
    }

    intent.putExtra(Intent.EXTRA_TEXT, "Some Title");

    File file = new File(uri.getPath());
    file.delete();

    return intent;
}

private static Bitmap takeScreenShot(Activity activity)
{
    View view = activity.getWindow().getDecorView();
    //View view = (View) MainActivity.viewPager.getChildAt(MainActivity.viewPager.getCurrentItem());
    view.setDrawingCacheEnabled(true);
    view.buildDrawingCache();
    Bitmap b1 = view.getDrawingCache();
    Rect frame = new Rect();
    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
    int statusBarHeight = frame.top;
    int width = activity.getWindowManager().getDefaultDisplay().getWidth();
    int height = activity.getWindowManager().getDefaultDisplay().getHeight();

    Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height  - statusBarHeight);
    view.destroyDrawingCache();
    return b;
}

My edited code:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);

    // Find the MenuItem that we know has the ShareActionProvider
    MenuItem shareItem = menu.findItem(R.id.menu_item_share);

    // Get its ShareActionProvider
    mShareActionProvider = (ShareActionProvider) shareItem.getActionProvider();

    Uri uri = saveScreenShotDirectoryLocation();
    screenShotHandler(uri);

    mShareActionProvider.setOnShareTargetSelectedListener(MainActivity.this);

    // Return true so Android will know we want to display the menu
    return true;
}

public boolean onShareTargetSelected (ShareActionProvider source, Intent intent) {

    Uri uri = saveScreenShotDirectoryLocation();
    screenShotHandler(uri);
    setShareIntent(getDefaultScreenshotShareIntent());

    return false;
}

private void screenShotHandler(Uri uri) {

    File path = Environment.getDataDirectory();
    long usablePartitionSpace = path.getUsableSpace();

   // if (usablePartitionSpace >= SCREENSHOT_FILE_SIZE_IN_BYTES ) {

        Bitmap screenShot = takeScreenShot(MainActivity.this);

        OutputStream outstream;
        try {
            outstream = getContentResolver().openOutputStream(uri);
            screenShot.compress(Bitmap.CompressFormat.PNG, 100, outstream);
            outstream.flush();
            outstream.close();
        } catch (Exception e) {
            System.err.println(e.toString());
        }
   // } else {
  //      Toast.makeText(this, "Not enough freespace for screenshot", Toast.LENGTH_SHORT).show();
  //  }
    setShareIntent(getDefaultScreenshotShareIntent());
}

 private Intent getDefaultScreenshotShareIntent() {

    Uri uri = saveScreenShotDirectoryLocation();

    Intent intent = new Intent(Intent.ACTION_SEND);

    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    intent.setType("image/png");

    long currenttime = System.currentTimeMillis();

    intent.putExtra(Intent.EXTRA_SUBJECT, "Some Title" + currenttime);

    File path = Environment.getDataDirectory();
    long usablePartitionSpace = path.getUsableSpace();

   // if (usablePartitionSpace >= SCREENSHOT_FILE_SIZE_IN_BYTES ) {
        intent.putExtra(Intent.EXTRA_STREAM, uri);
    //}

    intent.putExtra(Intent.EXTRA_TEXT, "Some Title");

    return intent;
}

Answer: Then perhaps ShareActionProvider is not the right tool. Have an action bar item that takes the screenshot, then just use Intent.createChooser() and startActivity() to let the user share the screenshot.

1 Answers1

0

Call setShareIntent() when you take the screenshot (e.g., somewhere in and around screenShotHandler()). Right now, you are calling setShareIntent() after the user has already chosen what to do, based on the previous Intent (onShareTargetSelected()).

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • thank you for the quick reply. I tried this but now the file doesn't persist long enough to be sent as an attachment. I get a "Couldn't send attachment" error now – LousDColeman Feb 28 '15 at 14:28
  • @user3211265: That is because, for some reason, you are deleting the file in `getDefaultScreenshotShareIntent()`, and therefore the file will not exist when the `Intent` is used. – CommonsWare Feb 28 '15 at 14:32
  • oh no it's commented out. I kept it there as a reference from an earlier edit. Unless you are referring to something other than file.delete(); – LousDColeman Feb 28 '15 at 14:33
  • @user3211265: It wasn't when I wrote the comment. Now, delete `onShareTargetSelected()`, as you do want to be re-resetting the `Intent` there. – CommonsWare Feb 28 '15 at 14:37
  • delete onShareTargetSelected() or include the file.delete() in the onShareTargetSelected? I've tried both and the screenshot still doesn't persist to be carried to the intent. – LousDColeman Feb 28 '15 at 14:55
  • @user3211265: "delete onShareTargetSelected() or include the file.delete() in the onShareTargetSelected?" -- both, I guess. I have never used `insert()` to come up with a `Uri` before, and so it's possible that there's something odd with how that flow works. I would write the PNG to a file, then use `MediaScannerConnection` and `scanFile()` to get the file indexed. But the big thing is to only call `setShareIntent()` when the content changes; it feels as though you are trying to perhaps take the screenshot as part of the use of `ShareActionProvider`, which is unlikely to work out well. – CommonsWare Feb 28 '15 at 15:16
  • @user3211265: [Here is a sample project](https://github.com/commonsguy/cw-omnibus/tree/master/ActionBar/ShareNative) of mine that is a bit reminiscent of yours. In my case, the stuff to be shared is the text in an `EditText`, and I update the share `Intent` when that text changes. – CommonsWare Feb 28 '15 at 15:17
  • Doing it this way makes the UI extremely sluggish – LousDColeman Mar 01 '15 at 00:21
  • @user3211265: Then perhaps `ShareActionProvider` is not the right tool. Have an action bar item that takes the screenshot, then just use `Intent.createChooser()` and `startActivity()` to let the user share the screenshot. – CommonsWare Mar 01 '15 at 00:23
  • Yea that sounds like a great idea – LousDColeman Mar 01 '15 at 00:36
  • however I did find an example that might work using the shareactionprovider. Since the onShareTargetSelected doesn't allow the intent to be modified while the method is implemented. Making a custom ShareActionProvider class will allow me to return true in the onShareTargetSelected method. This will allow me to take a screenshot and update the intent when the share button is clicked. According to http://www.reigndesign.com/blog/customizing-individual-share-services-in-a-shareactionprovider-on-android/ . The only problem is he uses the support library v7 shareactionprovider. – LousDColeman Mar 01 '15 at 00:53
  • The problem with that is I can't import TintManager, this is the only error. Any idea on how to solve this? the support library share action provider class is here https://github.com/android/platform_frameworks_support/blob/master/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java. And the line is 29 and 189 – LousDColeman Mar 01 '15 at 00:57
  • @user3211265: `TintManager` is in [the same repo](https://github.com/android/platform_frameworks_support/blob/master/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java). – CommonsWare Mar 01 '15 at 12:21
  • Yea just copying the TintManager class requires somehow acquiring all the resource files that TintManager uses. I'll revisit this method at a later date because I want the ability of remembering frequent share apps in the list and the ordering. But for now the solution you proposed works great. Thanks for your help! – LousDColeman Mar 02 '15 at 06:49