package com.forfan.bigbang.component.activity.screen; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; 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.Build; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.support.annotation.RequiresApi; import android.util.DisplayMetrics; import android.view.WindowManager; import com.forfan.bigbang.R; import com.forfan.bigbang.util.LogUtil; import com.forfan.bigbang.util.ToastUtil; import com.forfan.bigbang.util.ViewUtil; import com.forfan.bigbang.view.MarkSizeView; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; public class ScreenCapture { private static final String TAG = "ScreenCaptureActivity"; public static final String MESSAGE = "message"; public static final String FILE_NAME = "temp_file"; private SimpleDateFormat dateFormat = null; private String strDate = null; private String pathImage = null; private String nameImage = null; private MediaProjection mMediaProjection = null; private VirtualDisplay mVirtualDisplay = null; public static int mResultCode = 0; public static Intent mResultData = null; public static MediaProjectionManager mMediaProjectionManager1 = null; private WindowManager mWindowManager1 = null; private int windowWidth = 0; private int windowHeight = 0; private ImageReader mImageReader = null; private DisplayMetrics metrics = null; private int mScreenDensity = 0; private int mScreenWidth = 0; Handler handler = new Handler(Looper.getMainLooper()); private Rect mRect; private MarkSizeView.GraphicPath mGraphicPath; private ScreenCaptureActivity activity; @TargetApi(Build.VERSION_CODES.KITKAT) public ScreenCapture(ScreenCaptureActivity activity, Intent intent, int resultCode , Rect mRect, MarkSizeView.GraphicPath mGraphicPath){ this.activity=activity; mResultData=intent; mResultCode=resultCode; this.mRect = mRect; this.mGraphicPath = mGraphicPath; this.mScreenWidth = ViewUtil.getScreenWidth(activity); try { createVirtualEnvironment(); } catch (Exception e) { e.printStackTrace(); } } @TargetApi(Build.VERSION_CODES.KITKAT) public void toCapture() { try { handler.postDelayed(new Runnable() { public void run() { LogUtil.d(TAG, "before startVirtual"); startVirtual(); LogUtil.d(TAG, "after startVirtual"); } }, 10); handler.postDelayed(new Runnable() { public void run() { //capture the screen try { LogUtil.d(TAG, "before startCapture"); startCapture(); LogUtil.d(TAG, "after startCapture"); } catch (Exception e) { e.printStackTrace(); sendBroadcastCaptureFail(); } } }, 100); } catch (Exception e) { e.printStackTrace(); } catch (Error e) { e.printStackTrace(); } } private void sendBroadcastCaptureFail() { ToastUtil.show(R.string.screen_capture_fail); activity.finish(); } @RequiresApi(api = Build.VERSION_CODES.KITKAT) private void createVirtualEnvironment() { dateFormat = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss"); strDate = dateFormat.format(new java.util.Date()); pathImage = Environment.getExternalStorageDirectory().getPath() + "/Pictures/"; nameImage = pathImage + strDate + ".png"; mMediaProjectionManager1 = (MediaProjectionManager) activity.getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE); mWindowManager1 = (WindowManager) activity.getApplication().getSystemService(Context.WINDOW_SERVICE); windowWidth = ViewUtil.getScreenWidth(activity); windowHeight = ViewUtil.getSceenHeight(activity); metrics = new DisplayMetrics(); mWindowManager1.getDefaultDisplay().getMetrics(metrics); mScreenDensity = metrics.densityDpi; mImageReader = ImageReader.newInstance(windowWidth, windowHeight, 0x1, 2); //ImageFormat.RGB_565 LogUtil.d(TAG, "prepared the virtual environment"); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void startVirtual() { if (mMediaProjection != null) { LogUtil.d(TAG, "want to display virtual"); virtualDisplay(); } else { LogUtil.d(TAG, "want to build mediaprojection and display virtual"); setUpMediaProjection(); virtualDisplay(); } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void setUpMediaProjection() { try { mMediaProjection = mMediaProjectionManager1.getMediaProjection(mResultCode, mResultData); } catch (Exception e) { e.printStackTrace(); LogUtil.d(TAG, "mMediaProjection defined"); } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void virtualDisplay() { try { mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", windowWidth, windowHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); LogUtil.d(TAG, "virtual displayed"); } catch (Exception e) { e.printStackTrace(); } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void startCapture() throws Exception { strDate = dateFormat.format(new java.util.Date()); nameImage = pathImage + strDate + ".png"; Image image = mImageReader.acquireLatestImage(); if (image==null){ LogUtil.d(TAG, "image==null,restart"); handler.post(new Runnable() { @Override public void run() { toCapture(); } }); return; } int width = image.getWidth(); int height = image.getHeight(); final Image.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); image.close(); LogUtil.d(TAG, "image data captured"); if (width!=mScreenWidth ||rowPadding !=0){ int[] pixel=new int[width + rowPadding / pixelStride]; bitmap.getPixels(pixel,0,width + rowPadding / pixelStride,0,0,width + rowPadding / pixelStride,1); int leftPadding=0; int rightPadding=width + rowPadding / pixelStride; for (int i=0;i<pixel.length;i++){ if (pixel[i]!=0){ leftPadding=i; break; } } for (int i=pixel.length-1;i>=0;i--){ if (pixel[i]!=0){ rightPadding=i; break; } } width=Math.min(width,mScreenWidth); if (rightPadding-leftPadding>width){ rightPadding= width; } bitmap=Bitmap.createBitmap(bitmap,leftPadding, 0, rightPadding-leftPadding, height); } LogUtil.d(TAG, "bitmap cuted first"); if (mGraphicPath!=null){ mRect=new Rect(mGraphicPath.getLeft(),mGraphicPath.getTop(),mGraphicPath.getRight(),mGraphicPath.getBottom()); } if (mRect != null) { if (mRect.left < 0) mRect.left = 0; if (mRect.right < 0) mRect.right = 0; if (mRect.top < 0) mRect.top = 0; if (mRect.bottom < 0) mRect.bottom = 0; int cut_width = Math.abs(mRect.left - mRect.right); int cut_height = Math.abs(mRect.top - mRect.bottom); if (cut_width > 0 && cut_height > 0) { Bitmap cutBitmap = Bitmap.createBitmap(bitmap, mRect.left, mRect.top, cut_width, cut_height); LogUtil.d(TAG, "bitmap cuted second"); if (mGraphicPath!=null){ // 准备画笔 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setColor(Color.WHITE); Bitmap temp = Bitmap.createBitmap(cut_width, cut_height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(temp); Path path = new Path(); if (mGraphicPath.size() > 1) { path.moveTo((float) ((mGraphicPath.pathX.get(0)-mRect.left)), (float) ((mGraphicPath.pathY.get(0)- mRect.top))); for (int i = 1; i < mGraphicPath.size(); i++) { path.lineTo((float) ((mGraphicPath.pathX.get(i)-mRect.left)), (float) ((mGraphicPath.pathY.get(i)- mRect.top))); } } else { return; } canvas.drawPath(path, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); // 关键代码,关于Xfermode和SRC_IN请自行查阅 canvas.drawBitmap(cutBitmap, 0 , 0, paint); LogUtil.d(TAG, "bitmap cuted third"); saveCutBitmap(temp); }else { saveCutBitmap(cutBitmap); } } } else { saveCutBitmap(bitmap); } bitmap.recycle();//自由选择是否进行回收 } private void saveCutBitmap(Bitmap cutBitmap) { File localFile = new File(activity.getFilesDir(), "temp.png"); String fileName=localFile.getAbsolutePath(); try { if (!localFile.exists()) { localFile.createNewFile(); LogUtil.d(TAG,"image file created"); } FileOutputStream fileOutputStream = new FileOutputStream(localFile); if (fileOutputStream != null) { cutBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream); fileOutputStream.flush(); fileOutputStream.close(); } } catch (IOException e) { sendBroadcastCaptureFail(); return; } Intent newIntent = new Intent(activity, CaptureResultActivity.class); newIntent.putExtra(ScreenCapture.MESSAGE, "保存成功"); newIntent.putExtra(ScreenCapture.FILE_NAME,fileName ); activity.startActivity(newIntent); activity.finish(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void tearDownMediaProjection() { if (mMediaProjection != null) { mMediaProjection.stop(); mMediaProjection = null; } LogUtil.d(TAG, "mMediaProjection undefined"); } @TargetApi(Build.VERSION_CODES.KITKAT) private void stopVirtual() { if (mVirtualDisplay == null) { return; } mVirtualDisplay.release(); mVirtualDisplay = null; LogUtil.d(TAG, "virtual display stopped"); } public void onDestroy() { stopVirtual(); tearDownMediaProjection(); LogUtil.d(TAG, "application destroy"); } }