Как сделать снимок экрана и поделиться им программно

Я делаю приложение на Android, в котором должен снимать снимок одного из моих действий и отправлять его в виде вложения.

Я хочу снять снимок экрана с текущей страницы, а затем поделиться ею по электронной почте, Bluetooth, Twitter или Facebook.

Мой код выглядит следующим образом:

@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;
}

Ответ 1

Попробуйте сделать снимок экрана текущей активности:

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();
    }
}

Ответ 2

Если "снимок экрана текущей страницы" означает "снимок экрана одного из моих действий", вы можете сделать Views растровым Canvas затем сохраните изображение из растрового изображения.

Если "снимок экрана текущей страницы" означает "снимок экрана с кем-то другого", который не поддерживается Android SDK, для обеспечения конфиденциальности и безопасности. Существуют различные методы, которые корневые пользователи устройств могут использовать для скриншотов.

Ответ 3

1. Создайте кнопку совместного доступа

Мне понадобилось мое в панели действий, поэтому я создал файл share_menu.xml:

<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>

Это добавляет кнопку в панели действий с моим share_icon и текстом.

2. Добавьте меню совместного доступа в свою активность (или фрагмент)

Я сделал это внутри фрагмента, поэтому я добавил код ниже в файл фрагмента. Если вы находитесь внутри действия, тогда вместо этого вы переопределяете public boolean onCreateOptionsMenu(Menu menu).

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

если вы делаете это с фрагментом, а затем в onCreate() вы должны добавить:

setHasOptionsMenu(true);

3. Настроить действие кнопки/обратный вызов /onclick

Это то, что собирается начать обмен.

@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);
    }

Обратите внимание, что это вызывает два волшебных метода:

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;
}

Внимание!

К вашему AndroidManifest.xml нужно добавить:

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

или скриншот не будет сохранен, и gmail подумает, что вы пытаетесь прикрепить пустой файл.

Кроме того, многие ответы SO говорят, что использовать "*/*" для shareIntent.setType(), но это создает проблему с совместным использованием facebook, поэтому лучше оставить его как "image/*".

Ответ 4

Вот как я захватил экран и поделился им. Посмотрите, если вы заинтересованы.

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

И метод, который сохраняет растровое изображение во внешнее хранилище:

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);
}}

см. больше в: https://www.youtube.com/watch?v=LRCRNvzamwY&feature=youtu.be

Ответ 5

Kotlin полный код решения с проверкой разрешения:

1- Используйте эту симпатичную библиотеку, чтобы сделать снимок экрана с функциональностью java/Kotlin/Rx, добавьте зависимость от библиотеки: ссылка InstaCapture на github

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

2- Необходимо проверить разрешение на совместимость на всех версиях Android:

     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- Проверьте результат разрешения:

 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 призывает сделать снимок экрана и поделиться им намеренно:

 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- Объявите эту переменную:

val PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 100

6- Не забудьте добавить эти разрешения в AndroidManifest.xml:

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