28

I am making an application in Android in which I have to take screenshot of one of my activities and mail it as attachment.

I want to take screenshot of the current page and then share it via email, Bluetooth, Twitter or Facebook.

My code is as follows:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.menuselected1, menu);
  return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

  switch (item.getItemId()) {
    case R.id.ScreenShot:

    try {
        takeScreenShot(this);
    }
    catch (Exception e) {
        System.out.println(e);
    }

    return true;

    default:
    return super.onOptionsItemSelected(item);
  }
}

private static void savePic(Bitmap b, String strFileName) {
  FileOutputStream fos = null;
  try {
      fos = new FileOutputStream(strFileName);
      if (null != fos) {
        b.compress(Bitmap.CompressFormat.PNG, 90, fos);
        System.out.println("b is:"+b);
        fos.flush();
        fos.close();
      }
  } catch (FileNotFoundException e) {
          e.printStackTrace();
  } catch (IOException e) {
          e.printStackTrace();
  }
}

public static void shoot(Activity a,String b) {
  //savePic(takeScreenShot(a), "sdcard/xx.png");
  savePic(takeScreenShot(a), b);
}

private static Bitmap takeScreenShot(Activity activity) {
  View view = activity.getWindow().getDecorView();
  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, 25, 320, 455);
  Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height
                                 - statusBarHeight);
  view.destroyDrawingCache();
  return b;
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121

5 Answers5

37

Try this for taking screenshot of current Activity:

Android 2.2 :

private static Bitmap takeScreenShot(Activity activity)
{
    View view = activity.getWindow().getDecorView();
    view.setDrawingCacheEnabled(true);
    view.buildDrawingCache();
    Bitmap b1 = view.getDrawingCache();
    Rect frame = new Rect();
    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
    int statusBarHeight = frame.top;

    DisplayMetrics displaymetrics = new DisplayMetrics(); 
    mContext.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);

    int width = displaymetrics.widthPixels;
    int height = displaymetrics.heightPixels;

    Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height  - statusBarHeight);
    view.destroyDrawingCache();
    return b;
}
private static void savePic(Bitmap b, String strFileName)
{
    FileOutputStream fos = null;
    try
    {
        fos = new FileOutputStream(strFileName);
        if (null != fos)
        {
            b.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.flush();
            fos.close();
        }
    }
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}
ρяσѕρєя K
  • 132,198
  • 53
  • 198
  • 213
  • 1
    i am working on android2.2 and i used your code but it is not showing anything means i want to know where the image is getting stored in phone –  Apr 24 '12 at 11:37
  • It's advised to wrap your output stream with a buffered stream. – Vaiden Sep 04 '13 at 20:38
  • 1
    This is for only rooted devices, is it will work for unrooted devices? – Hanuman Apr 07 '15 at 06:54
16

If by "screenshot of current page" you mean "screenshot of one of my activities", you can arrange to render your Views to a bitmap-backed Canvas, then save an image from the bitmap.

If by "screenshot of current page" you mean "screenshot of somebody else's activity", that is not supported by the Android SDK, for obvious privacy and security reasons. There are various techniques that rooted device users can use to take screenshots.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    I want that to take screenshot of my activity –  Apr 24 '12 at 11:17
  • Why not just use DDMS in Eclipse with the phone being connected? I know it's not a "code solution", but your question does sound a bit peculiar. – Michell Bak Apr 24 '12 at 11:18
6

1. Create the share button

I wanted mine in the action bar so I created a share_menu.xml file:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/share_item"
        app:showAsAction="always|withText"
        android:title="Share"
        android:icon="@drawable/share_icon"
        android:actionProviderClass=
            "android.widget.ShareActionProvider" />
</menu>

This adds a button in the action bar with my share_icon and the text.

2. Add the sharing menu to your activity (or fragment)

I did this inside a fragment so I added the code below to my fragment file. If you are inside an activity then you override public boolean onCreateOptionsMenu(Menu menu) instead.

@Override
public void onCreateOptionsMenu(
        Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.share_menu, menu);
}

if you are doing this with a fragment then in onCreate() you have to add:

setHasOptionsMenu(true);

3. Set up button action/callback/onclick

This is what is going to kick off the sharing.

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.share_item){
            Bitmap bm = screenShot(this.getView());
            File file = saveBitmap(bm, "mantis_image.png");
            Log.i("chase", "filepath: "+file.getAbsolutePath());
            Uri uri = Uri.fromFile(new File(file.getAbsolutePath()));
            Intent shareIntent = new Intent();
            shareIntent.setAction(Intent.ACTION_SEND);
            shareIntent.putExtra(Intent.EXTRA_TEXT, "Check out my app.");
            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
            shareIntent.setType("image/*");
            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(Intent.createChooser(shareIntent, "share via"));
        }
        return super.onOptionsItemSelected(item);
    }

Notice this calls two magic methods:

screenShot():

private Bitmap screenShot(View view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    return bitmap;
}

private static File saveBitmap(Bitmap bm, String fileName){
    final String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Screenshots";
    File dir = new File(path);
    if(!dir.exists())
        dir.mkdirs();
    File file = new File(dir, fileName);
    try {
        FileOutputStream fOut = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.PNG, 90, fOut);
        fOut.flush();
        fOut.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return file;
}

Important

To your AndroidManifest.xml, you have to add:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

or the screenshot won't be saved, and gmail will think you are trying to attach an empty file.

Also, a lot of SO answers say to use "*/*" for shareIntent.setType() but this creates an issue with facebook sharing, so it's best to leave it as "image/*".

Chase Roberts
  • 9,082
  • 13
  • 73
  • 131
  • this is not working in marshmallow. Any idea on how to fix this in marshmallow. For kitkat, it is working perfectly. – Varsha Vijayvargiya Aug 08 '16 at 03:33
  • @VarshaVijayvargiya, I didn't try but there are permissions, please pay attention you must ask permissions in run time in android M. – AsfK Jan 16 '17 at 08:52
0

Kotlin complete solution Code with permission check :

1- Use this nice library to take screen shot with java / Kotlin / Rx functionality, add library dependency : InstaCapture github link

 implementation "com.github.tarek360:instacapture:2.0.1"

2- Must check permission for compatibility on all android versions:

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) { // Needs permission so request it
            DeviceUtil.showAlertMsg(this, GeneralDicModel.shareMsgScreenShot!!)
            requestPermissions(
                arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
            )   //callback  result to onRequestPermissionsResult
        } else { //Has got the permission before or doesn't need
            screenShotAndShareIt()
        }

3- Check permission result :

 override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<out String>,
    grantResults: IntArray
) {
    when (requestCode) {
        PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                screenShotAndShareIt()
            } else {
                //  toast("Permission must be granted in order to save scrrenshot file")
            }
        }
    }
}

4- Func call for take Screenshot & Share it by intent :

 fun screenShotAndShareIt() {
    Instacapture.capture(this, object : SimpleScreenCapturingListener() {
    override fun onCaptureComplete(bitmap: Bitmap) {
    val state = Environment.getExternalStorageState()
            if (Environment.MEDIA_MOUNTED == state) {
                val path: String = Environment.getExternalStorageDirectory().toString()  
                val picDir = File(path.plus("/myPic"))
                if (!picDir.exists()) {
                    picDir.mkdir()
                }
                var bitmapScreenShot = bitmap
                val fileName = "screenshot" + ".jpg"
                val picFile = File(picDir.path.plus("/" + fileName))
                try {
                    picFile.createNewFile()
                    val picOut = FileOutputStream(picFile)
                    bitmapScreenShot =
                        Bitmap.createBitmap(bitmapScreenShot, 0, 0, bitmapScreenShot.width, bitmapScreenShot.height)
                    val saved: Boolean = bitmapScreenShot.compress(Bitmap.CompressFormat.JPEG, 100, picOut)
                    if (saved) {
                        Log.i(
                            TAG,
                            "ScreenShotAndShareIt : Image saved to your device Pictures " + "directory! + ${picFile.absolutePath}"
                        )
                    } else {
                        Log.i(TAG, "ScreenShotAndShareIt Error on Save! + ${picFile.absolutePath}")
                    }
                    picOut.close()

                    // share via intent
                    val intent: Intent = Intent(android.content.Intent.ACTION_SEND)
                    intent.type = "image/jpeg"
                    intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(picFile.absolutePath))
                    startActivity(Intent.createChooser(intent, "Sharing"))
                } catch (e: Exception) {
                    Log.i(TAG, "ScreenShotAndShareIt Error catch : " + e.printStackTrace())
                }
            } else {
                //Error
                Log.i(TAG, "ScreenShotAndShareIt Error Environment.MEDIA_MOUNTED == state : " )
            }
 }
 })

5- Declare this variable :

val PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 100

6- Do not forget to Add this permissions to AndroidManifest.xml:

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Hamed Jaliliani
  • 2,789
  • 24
  • 31
-2

This is how I captured the screen and shared it. Take a look if you are interested.

public Bitmap takeScreenshot() {
  View rootView = findViewById(android.R.id.content).getRootView();
  rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
 }

And the method that saves the bitmap image to external storage:

public void saveBitmap(Bitmap bitmap) {
  File imagePath = new File(Environment.getExternalStorageDirectory() +       "/screenshot.png");
  FileOutputStream fos;
  try {
  fos = new FileOutputStream(imagePath);
  bitmap.compress(CompressFormat.JPEG, 100, fos);
 fos.flush();
 fos.close();
 } catch (FileNotFoundException e) {
Log.e("GREC", e.getMessage(), e);
} catch (IOException e) {
Log.e("GREC", e.getMessage(), e);
}}

see more in : https://www.youtube.com/watch?v=LRCRNvzamwY&feature=youtu.be