ScreenCapture класс - это ключевой код для работы с кадрированием и снимком экрана.
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){
// prepare paint
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));
// The key code
canvas.drawBitmap(cutBitmap, 0 , 0, paint);
LogUtil.d(TAG, "bitmap cuted third");
saveCutBitmap(temp);
}else {
saveCutBitmap(cutBitmap);
}
}
} else {
saveCutBitmap(bitmap);
}
bitmap.recycle();//free choose whether to 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, "save success");
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");
}
}
MarkSizeView используется для выбора области, которую вы выбираете, и показывает виртуальный край. (Это частичный код), возможно, вы можете использовать этот метод onTouchEvent
для рисования выбранной области.
public class MarkSizeView extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()){
return false;
}
int x= (int) event.getX();
int y= (int) event.getY();
if (isMarkRect) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isUp = false;
isAdjustMode = false;
isMoveMode = false;
isButtonClicked = false;
isValid = false;
adjustNum = 0;
downX = x;
downY = y;
if (mOnClickListener != null) {
mOnClickListener.onTouch();
}
if (isAreaContainPoint(confirmArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onConfirm(markedArea);
}
} else if (isAreaContainPoint(cancelArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onCancel();
isValid = false;
startX = startY = endX = endY = 0;
adjustMark(0, 0);
}
} else if (isAreaContainPoint(ltVer,x, y)) {
isAdjustMode = true;
adjustNum = 1;
} else if (isAreaContainPoint(rtVer,x, y)) {
isAdjustMode = true;
adjustNum = 2;
} else if (isAreaContainPoint(lbVer,x, y)) {
isAdjustMode = true;
adjustNum = 3;
} else if (isAreaContainPoint(rbVer,x, y)) {
isAdjustMode = true;
adjustNum = 4;
} else if (markedArea.contains(x, y)) {
isMoveMode = true;
} else {
isMoveMode = false;
startX = (int) event.getX();
startY = (int) event.getY();
endX = startX;
endY = startY;
}
break;
case MotionEvent.ACTION_MOVE:
if (isButtonClicked) {
break;
}
adjustMark(x, y);
break;
case MotionEvent.ACTION_UP:
isUp = true;
if (isButtonClicked) {
break;
}
adjustMark(x, y);
startX = markedArea.left;
startY = markedArea.top;
endX = markedArea.right;
endY = markedArea.bottom;
if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5) {
//Displayed in the inner bottom of the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
} else if (endY > getHeight() - confirmBitmap.getHeight() * 3) {
//Displayed on top of the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
} else {
//Displayed below the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
}
if (cancelArea.left<0){
int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
}
if (!isValid) {
if (mOnClickListener != null) {
mOnClickListener.onCancel();
}
}
break;
case MotionEvent.ACTION_CANCEL:
isUp = true;
break;
}
}else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isUp = false;
isAdjustMode = false;
isMoveMode = false;
isButtonClicked = false;
isValid = false;
adjustNum = 0;
downX = x;
downY = y;
if (mOnClickListener != null) {
mOnClickListener.onTouch();
}
if (isAreaContainPoint(confirmArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onConfirm(mGraphicPath);
}
} else if (isAreaContainPoint(cancelArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onCancel();
isValid = false;
startX = startY = endX = endY = 0;
adjustMark(0, 0);
}
mGraphicPath.clear();
} else {
isMoveMode = false;
startX = (int) event.getX();
startY = (int) event.getY();
endX = startX;
endY = startY;
mGraphicPath.clear();
mGraphicPath.addPath(x,y);
}
break;
case MotionEvent.ACTION_MOVE:
if (isButtonClicked) {
break;
}
mGraphicPath.addPath(x,y);
break;
case MotionEvent.ACTION_UP:
isUp = true;
if (isButtonClicked) {
break;
}
mGraphicPath.addPath(x,y);
startX = mGraphicPath.getLeft();
startY = mGraphicPath.getTop();
endX = mGraphicPath.getRight();
endY = mGraphicPath.getBottom();
if ((endX-startX)*(endY-startY)>200){
isValid=true;
}
markedArea.set(startX,startY,endX,endY);
if (endY < getHeight() - confirmBitmap.getHeight() * 3){
//Displayed below the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
} else
if (startY > confirmBitmap.getHeight() * 3) {
//Displayed on top of the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
}else if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5)
{
//Displayed in the inner bottom of the selection
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
}
if (cancelArea.left<0){
int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
}
if (!isValid) {
if (mOnClickListener != null) {
mOnClickListener.onCancel();
}
}
break;
case MotionEvent.ACTION_CANCEL:
isUp = true;
break;
}
}
postInvalidate();
return true;
}
}
Код немного больше, если вы хотите перевести на Xamarin, потребуется много времени. Если вы хотите быть более дружественным к пользователю, это много работы.