本文是根据 @goodbranch 的《Android 5.0及以上实现屏幕截图 》,进行修改过之后,整理出来的。因作者未回复私信,加之在不 root 的前提下用代码实现截屏着实不易,为了让更多的人少走弯路,故编写此文。如有冒犯,请及时提醒,以便删除此文。 地址 : http://blog.csdn.net/consumer11/article/details/51967340
import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.Image; import android.media.ImageReader; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.os.Handler; import android.util.DisplayMetrics; import android.view.Surface; import android.view.WindowManager;
public class ScreenShot {
private static WindowManager windowManager; private static int screenDensity; private static int screenWidth; private static int screenHeight; private static MediaProjection mediaProjection; private static VirtualDisplay virtualDisplay; private static ImageReader imageReader; public static Surface surface; public static void setUpMediaProjection(Activity activity, Intent scIntent) { if (scIntent == null) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); activity.startActivity(intent); } else { mediaProjection = getMediaProjectionManager(activity).getMediaProjection(Activity.RESULT_OK, scIntent); } } public static void getWH(Activity activity) { DisplayMetrics metrics = new DisplayMetrics(); windowManager = (WindowManager) activity.getSystemService(activity.WINDOW_SERVICE); windowManager.getDefaultDisplay().getMetrics(metrics); screenDensity = metrics.densityDpi; screenWidth = metrics.widthPixels; screenHeight = metrics.heightPixels; } public static void createImageReader() { imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1); } public static void beginScreenShot(final Activity activity, final Intent intent) { Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { beginVirtual(activity, intent); } }, 0); handler.postDelayed(new Runnable() { @Override public void run() { beginCapture(activity, intent); } }, 150); } private static void beginVirtual(Activity activity, Intent intent) { if (null != mediaProjection) { virtualDisplay(); } else { setUpMediaProjection(activity, intent); virtualDisplay(); } } private static void virtualDisplay() { surface = imageReader.getSurface(); virtualDisplay = mediaProjection.createVirtualDisplay("screen-mirror", screenWidth, screenHeight, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null); } private static MediaProjectionManager getMediaProjectionManager(Activity activity) { return (MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE); } private static void beginCapture(Activity activity, Intent intent) { Image acquireLatestImage = null; try { acquireLatestImage = imageReader.acquireLatestImage(); } catch (IllegalStateException e) { if (null != acquireLatestImage) { acquireLatestImage.close(); acquireLatestImage = null; acquireLatestImage = imageReader.acquireLatestImage(); } } if (acquireLatestImage == null) { beginScreenShot(activity, intent); } else { SaveTask saveTask = new SaveTask(); AsyncTaskCompat.executeParallel(saveTask, acquireLatestImage); new Handler().postDelayed(new Runnable() { @Override public void run() { releaseVirtual(); stopMediaProjection(); } }, 1000); } } private static void releaseVirtual() { if (null != virtualDisplay) { virtualDisplay.release(); virtualDisplay = null; } } private static void stopMediaProjection() { if (null != mediaProjection) { mediaProjection.stop(); mediaProjection = null; } } }import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale;
import android.graphics.Bitmap; import android.media.Image; import android.media.Image.Plane; import android.os.AsyncTask; import android.os.Environment;
public class SaveTask extends AsyncTask<Image, Void, Bitmap> {
@Override protected Bitmap doInBackground(Image... args) { if (null == args || 1 > args.length || null == args[0]) { return null; } Image image = args[0]; int width; int height; try { width = image.getWidth(); height = image.getHeight(); } catch (IllegalStateException e) { return null; } final Plane[] planes = image.getPlanes(); final ByteBuffer buffer = planes[0].getBuffer(); // 每个像素的间距 int pixelStride = planes[0].getPixelStride(); // 总的间距 int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * width; Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(buffer); bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); image.close(); File fileImage = null; if (null != bitmap) { FileOutputStream fos = null; try { fileImage = new File(createFile()); if (!fileImage.exists()) { fileImage.createNewFile(); fos = new FileOutputStream(fileImage); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); } } catch (IOException e) { fileImage = null; } finally { if (null != fos) { try { fos.close(); } catch (IOException e) { } } if (null != bitmap && !bitmap.isRecycled()) { bitmap.recycle(); bitmap = null; } } } if (null != fileImage) { return bitmap; } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (ScreenShot.surface.isValid()) { ScreenShot.surface.release(); } } // 输出目录 private String createFile() { String outDir = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US); String date = simpleDateFormat.format(new Date()); return outDir + date + ".png"; } }import android.os.AsyncTask;
public final class AsyncTaskCompat {
@SafeVarargs public static <Params, Progress, Result> AsyncTask<Params, Progress, Result> executeParallel( AsyncTask<Params, Progress, Result> task, Params... params) { if (task == null) { throw new IllegalArgumentException("task can not be null"); } AsyncTaskCompatHoneycomb.executeParallel(task, params); return task; } private AsyncTaskCompat() { } }import android.os.AsyncTask;
class AsyncTaskCompatHoneycomb {
@SafeVarargs static <Params, Progress, Result> void executeParallel(AsyncTask<Params, Progress, Result> task, Params... params) { task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } }⑴ 定义一个常量
int PERMISSION_CODE = 999;⑵ 写一个检查权限的方法,在程序初始化时调用
@SuppressLint({ "NewApi", "InlinedApi" }) private boolean checkPermission(Activity activity) { if (Settings.canDrawOverlays(activity)) { return true; } Toast.makeText(activity, "请开启【允许在其他应用的上层显示】权限!", Toast.LENGTH_LONG).show(); Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.getPackageName())); activity.startActivityForResult(intent, PERMISSION_CODE); return false; } checkPermission(MainActivity.this); // 调用⑶ 在MainActivity的onActivityResult(int requestCode, int resultCode, Intent data) 方法中检查回调
if (PERMISSION_CODE == resultCode) { if (!Settings.canDrawOverlays(this)) { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("提示").setMessage("授权失败,无法使用程序").setCancelable(false) .setNegativeButton("退出程序", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { System.exit(0); } }) .create().show(); } else { Toast.makeText(MainActivity.this, "授权成功!", Toast.LENGTH_SHORT).show(); requestCapturePermission(); } }