截屏代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.shangyi.common.util.ShellUtils;
import com.shangyi.common.util.SyHandler;
import com.shangyi.common.util.ShellUtils.CommandResult;
import com.shangyi.sayimo.R;
import com.shangyi.sayimo.app.CommonPath;
import com.shangyi.sayimo.log.SyLog;
import com.shangyi.sayimo.plugin.quickkey.QuickKeyContants;
import com.shangyi.sayimo.plugin.quickkey.QuickKeyManager;
import com.shangyi.sayimo.ui.activity.BaseActivity;
import com.shangyi.sayimo.ui.dialog.CommonUpToast;
import com.shangyi.sayimo.util.AppUtil;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.Image.Plane;
import android.media.ImageReader;
import android.media.ImageReader.OnImageAvailableListener;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Display;
import android.widget.Toast;
/**
* 实现一键截屏
*
*
* @author llp
*
*/
public class ScreenshotsActivity extends BaseActivity {
private static final String TAG = ScreenshotsActivity.class.getSimpleName();
/**
* intent传过来的数据,需要开启5.0系统的截屏功能(使用MediaProjection截屏)
*/
private static final int EXTRAS_CODE_SCREENSHOTS_5 = 0;
/**
* intent穿过来的数据,需要显示截屏结果(系统4.0以上,5.0以下使用的截屏功能-使用root命令截屏)
*/
private static final int EXTRAS_CODE_RESULT = 1;
private static final int ERROR_UNKNOWN = 0;
private static final int ERROR_MKDIR_FAIL = 1;
private static final String EXTRAS_CODE = "extras_code";
private static final String RESULT = "result";
private static final String PATH = "path";
private static final String ERROR_CODE = "error_code";
private static final int REQUEST_MEDIA_PROJECTION = 1;
/**
* 截屏停止延时
*/
private static final int SCREENSHOTS_STOP_DELAY = 400;
/**
* 截屏最终结果处理延时
*/
private static final int SCREENSHOTS_PROCESS_RESULT_DELAY = 500;
private static final int MAX_IMAGES = 5;
private int mResultCode;
private Intent mResultData;
private MediaProjectionManager mMediaProjectionManager;
private static MediaProjection mMediaProjection;
private static VirtualDisplay mVirtualDisplay;
private ImageReader mImageReader;
private Image mImage;
private String mSaveDir;
private String mFileName;
private int mDensityDpi;
private int mWidth;
private int mHeight;
private int mCount = 0;
private Object mLock = new Object();
private int mIndex = 0;
private boolean mIsToastFirst = true;
/**
* 截屏是否成功
*/
private boolean mIsSuccess = true;
/**
* 截屏是否取消
*/
private boolean mIsCancel = false;
private boolean mIsStop = false;
private String mPath;
private static final int NOTIFICATION_ID = 102;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsStop = false;
// 全屏
//getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//设置布局
//setContentView(R.layout.screenshots_layout);
Intent i = getIntent();
if(null != i && null != i.getExtras()){
if(i.hasExtra(EXTRAS_CODE)){
int code = i.getIntExtra(EXTRAS_CODE, -1);
if(code == EXTRAS_CODE_SCREENSHOTS_5){
if(android.os.Build.VERSION.SDK_INT < 21){
String tipStr = getResources().getString(R.string.sdk_low_tip);
CommonUpToast.makeText(this, tipStr, null).show();
}else{
// 使用5.0系统的新截屏功能
mMediaProjectionManager = (MediaProjectionManager)this.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
mSaveDir = getSaveDir(false);
if(checkSaveDir()){
mFileName = getSaveFileName();
mDensityDpi = getResources().getDisplayMetrics().densityDpi;
Display display = getWindowManager().getDefaultDisplay();
Point point = new Point();
display.getSize(point);
this.mWidth = point.x;
this.mHeight = point.y;
startScreenCapture();
}else{
SyLog.e(TAG, "failed to create file storage directory");
String errorStr = getResources().getString(R.string.et_picture_error_des1);
CommonUpToast.makeText(this, errorStr, null).show();
finish();
}
return;
}
} else if(code == EXTRAS_CODE_RESULT){
// 显示命令截屏结果
boolean result = i.getBooleanExtra(RESULT, false);
if(result){
cancelNotification(NOTIFICATION_ID);
String path = i.getStringExtra(PATH);
String type = "image/*";
showSuccessNotification(path, type);
//CommonUpToast.makeText(this, getResources().getString(R.string.screenshots_success) + path, null, Toast.LENGTH_LONG).show();
}else{
int errorCode = i.getIntExtra(ERROR_CODE, ERROR_UNKNOWN);
String errorStr = "";
if(errorCode == ERROR_MKDIR_FAIL) {
errorStr = getResources().getString(R.string.et_picture_error_des1);
} else {
errorStr = getResources().getString(R.string.screenshots_fail);
}
CommonUpToast.makeText(this, errorStr, null).show();
}
finish();
return;
}
}else{
SyLog.e(TAG, " no EXTRAS_CODE data ");
}
}else{
SyLog.e(TAG, " Extras is null ");
}
// 弹出异常提示
CommonUpToast.makeText(this, getResources().getString(R.string.screenshots_fail), null).show();
finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_MEDIA_PROJECTION){
if(resultCode == RESULT_OK){
SyLog.i(TAG, "Starting screen capture");
mResultCode = resultCode;
mResultData = data;
mPath = mSaveDir + mFileName;
SyLog.d(TAG, " save path: " + mPath);
setUpMediaProjection();
setUpImageReader();
setImageReaderListener();
setUpVirtualDisplay();
mHandler.postDelayed(new ResultTask(), SCREENSHOTS_PROCESS_RESULT_DELAY);
}else{
// 取消截屏
SyLog.e(TAG, "result no ok !!!");
mIsCancel = true;
finish();
}
}
}
@Override
public void onStop() {
super.onStop();
//mIsStop = true;
//stopScreenCapture();
}
@Override
protected void onDestroy() {
if(mIsCancel){
stopScreenCapture();
tearDownMediaProjection();
//String errorStr = getResources().getString(R.string.screenshots_cancel);
//CommonUpToast.makeText(this, errorStr, null).show();
}
super.onDestroy();
}
@Override
public void onBackPressed() {
// 取消返回事件
}
/**
* 设置截屏接受对象
*/
private void setUpImageReader(){
mIsToastFirst = true;
mIsSuccess = false;
mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, MAX_IMAGES);
}
private void setImageReaderListener(){
mImageReader.setOnImageAvailableListener(new OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
/*if(mIsStop){
SyLog.w(TAG, "screenshots is stoped!");
if(!mIsSuccess){
mIsCancel = true;
finish();
}
return;
}*/
try {
if(mCount >= MAX_IMAGES - 1){
SyLog.w(TAG, "acquire image count(" + mCount + ") is more than MAX!");
return;
}
acquireImageCount();
SyLog.d(TAG, " index: " + mIndex + " count: " + mCount);
mImage = reader.acquireLatestImage();
if(null != mImage){
savePicture(mIndex);
mIsSuccess = true;
//mIsStop = true;
}else{
SyLog.e(TAG, " acquire Latest image is null!" + " >>index: " + mIndex);
destoryImageCount();
}
} catch (Exception e) {
SyLog.e(TAG, "acquire error" + " >>index: " + mIndex, e);
}
// 结束整个界面,但是延迟一定时间停止截屏,以便截屏时去掉系统弹出框
finishScreenShots();
}
}, mHandler);
}
private void finishScreenShots(){
if(mIsToastFirst){
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
stopScreenCapture();
tearDownMediaProjection();
}
}, SCREENSHOTS_STOP_DELAY);
mIsToastFirst = false;
}
finish();
}
private class ResultTask implements Runnable {
public void run() {
/*if(mIsCancel){
String errorStr = getResources().getString(R.string.screenshots_cancel);
CommonUpToast.makeText(ScreenshotsActivity.this, errorStr, null).show();
}else */
if(mIsSuccess){
cancelNotification(NOTIFICATION_ID);
//CommonUpToast.makeText(ScreenshotsActivity.this, getResources().getString(R.string.screenshots_success) + mPath, null, Toast.LENGTH_LONG).show();
String type = "image/*";
showSuccessNotification(mPath, type);
}else{
String errorStr = getResources().getString(R.string.screenshots_fail);
CommonUpToast.makeText(ScreenshotsActivity.this, errorStr, null).show();
}
}
};
private void acquireImageCount(){
synchronized (mLock) {
mCount ++;
mIndex ++;
}
}
private void destoryImageCount(){
synchronized (mLock) {
mCount --;
}
}
/**
* 设置MediaProjection
*/
private void setUpMediaProjection() {
SyLog.i(TAG, "Setting up MediaProjection");
mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);
}
/**
* 设置虚拟显示
*/
private void setUpVirtualDisplay() {
SyLog.i(TAG, "Setting up a VirtualDisplay");
mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
mWidth, mHeight, mDensityDpi,
9,
mImageReader.getSurface(), null, mHandler);
}
/**
* 销毁mediaProjection
*/
private void tearDownMediaProjection() {
if (mMediaProjection != null) {
SyLog.i(TAG, "stop MediaProjection");
mMediaProjection.stop();
mMediaProjection = null;
}
}
/**
* 开始截屏
*/
private void startScreenCapture(){
if (mMediaProjection != null) {
setUpVirtualDisplay();
} else if (mResultCode != 0 && mResultData != null) {
setUpMediaProjection();
setUpVirtualDisplay();
} else {
SyLog.i(TAG, "Requesting confirmation");
// This initiates a prompt dialog for the user to confirm screen projection.
startActivityForResult(
mMediaProjectionManager.createScreenCaptureIntent(),
REQUEST_MEDIA_PROJECTION);
}
}
/**
* 停止截屏
*/
private void stopScreenCapture(){
if(mVirtualDisplay == null){
return ;
}
SyLog.i(TAG, " release Virtual Display ");
mVirtualDisplay.release();
mVirtualDisplay = null;
}
/**
* 保存截屏图片
*/
private void savePicture(int index){
SyLog.d(TAG, " savePicture " + " >>index: " + index);
new Thread(new SavePictureTask(index,mImage, mPath)).start();
}
private class SavePictureTask implements Runnable {
private int index;
private Image image;
private String path;
public SavePictureTask(int index, Image image, String path){
this.index = index;
this.image = image;
this.path = path;
}
@Override
public void run() {
long sTime = System.currentTimeMillis();
if(image == null){
SyLog.e(TAG, "image is null!!!" + " >>index: " + index);
return;
}
Bitmap bitmap = null;
try {
Plane[] planes = image.getPlanes();
if(planes == null || planes.length < 1){
SyLog.e(TAG, "planes is null!!!" + " >>index: " + index);
return;
}
Plane plane = planes[0];
if(plane == null){
SyLog.e(TAG, " plane 0 is null" + " >>index: " + index);
return;
}
ByteBuffer buffer = plane.getBuffer();
int pixelStride = plane.getPixelStride();
int rowStride = plane.getRowStride();
int rowPadding = rowStride - pixelStride * mWidth;
//int w = mWidth+rowPadding/pixelStride;
//SyLog.d(TAG, " width: " + w + " height: " + mHeight + " x:" + mWidth);
bitmap = Bitmap.createBitmap(mWidth+rowPadding/pixelStride, mHeight, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
buffer.position(0);
if(image != null){
image.close();
image = null;
destoryImageCount();
}
long iTime = System.currentTimeMillis();
SyLog.d(TAG, " CREATE BITMAP TIME: " + (iTime - sTime) + " >>index: " + index);
} catch (Exception e) {
SyLog.e(TAG, " get bitmap error" + " >>index: " + index, e);
} catch (OutOfMemoryError e){
SyLog.e(TAG, " Out Of Memory error" + " >>index: " + index, e);
}
FileOutputStream out = null;
try {
if(bitmap == null || bitmap.isRecycled()){
SyLog.w(TAG, " bitmap is null or Recycled" + " >>index: " + index);
return;
}
long iTime = System.currentTimeMillis();
File file = new File(path);
if(!file.exists() || file.delete()){
file.createNewFile();
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
SyLog.i(TAG, "save file success!!!" + " >>index: " + index);
} else {
SyLog.e(TAG, "create save file failed!!!" + " >>index: " + index);
}
SyLog.d(TAG, " Save file time: " + (System.currentTimeMillis() - iTime) + " >>index: " + index);
} catch (Exception e) {
SyLog.e(TAG, " save file error" + " >>index: " + index, e);
} catch (OutOfMemoryError e){
SyLog.e(TAG, " Out Of Memory error" + " >>index: " + index, e);
} finally {
if(out != null){
try {
out.close();
} catch (IOException e) {
}
}
if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
}
}
}
}
/**
* 检测截屏图片保存路径是否创建
*
* @return
*/
private boolean checkSaveDir(){
File dir = new File(mSaveDir);
if(dir.exists() || dir.mkdirs()){
return true;
}
return false;
}
public static void screenshots(final Context context){
if(android.os.Build.VERSION.SDK_INT >= 21){
Intent intent = new Intent(context, ScreenshotsActivity.class);
intent.putExtra(EXTRAS_CODE, EXTRAS_CODE_SCREENSHOTS_5);
intent.addFlags(336592896);
context.startActivity(intent);
} else {
screenshotsByCmd(context);
}
}
/**
* 使用命令截图
*
* sdk >= 14
*
* @param context
*/
public static void screenshotsByCmd(final Context context){
new Thread(new Runnable() {
@Override
public void run() {
SyLog.d(TAG, " LONG_CLICK_SCREENSHOTS!!! ");
String dir = getSaveDir(true);
File file = new File(dir);
if(file.exists() || file.mkdirs()){
String fileName = getSaveFileName();
String path = dir + fileName;
String cmd = "screencap -p " + path;
SyLog.d(TAG, " cmd : " + cmd);
CommandResult result = ShellUtils.execCommand(cmd, true);
if(context != null){
Intent intent = new Intent(context, ScreenshotsActivity.class);
intent.putExtra(EXTRAS_CODE, EXTRAS_CODE_RESULT);
boolean success = false;
if(result.result == 0){
success = true;
intent.putExtra(PATH, path);
SyLog.d(TAG, " LONG_CLICK_SCREENSHOTS SUCCESS ");
}else{
success = false;
intent.putExtra(ERROR_CODE, ERROR_UNKNOWN);
SyLog.e(TAG, " LONG_CLICK_SCREENSHOTS error !!!");
}
intent.putExtra(RESULT, success);
intent.addFlags(336592896);
context.startActivity(intent);
}
}else{
Intent intent = new Intent(context, ScreenshotsActivity.class);
intent.putExtra(EXTRAS_CODE, EXTRAS_CODE_RESULT);
intent.putExtra(RESULT, false);
intent.putExtra(ERROR_CODE, ERROR_MKDIR_FAIL);
intent.addFlags(336592896);
context.startActivity(intent);
SyLog.e(TAG, " LONG_CLICK_SCREENSHOTS mkdir fail !!!");
}
}
}).start();
}
/**
* 获取截屏图片保存路径
*
* @param isCmd 是否命令截屏方式
* @return
*/
private static String getSaveDir(boolean isCmd){
if(isCmd){
return "/sdcard/" +
CommonPath.FOLDER_NAME_ROOT + File.separator +
CommonPath.FOLDER_NAME_SCREENSHOTS + File.separator;
}
return CommonPath.mScreenshotsPath + File.separator;
}
/**
* 获取截屏图片名称
*
* @return
*/
private static String getSaveFileName(){
return new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(System.currentTimeMillis()))+".png";
}
private Handler mHandler = new SyHandler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private void showSuccessNotification(String path, String type){
SyLog.d(TAG, "showSuccessNotification");
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File file = new File(path);
intent.setDataAndType(Uri.fromFile(file), type);
PendingIntent localPendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Notification.Builder localBuilder = new Notification.Builder(this)
.setTicker(getResources().getString(R.string.screenshots_result_title))
.setSmallIcon(R.drawable.logo_notify_small)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.logo_notify))
.setContentTitle(getResources().getString(R.string.screenshots_result_title))
.setContentText(getResources().getString(R.string.screenshots_result_content))
.setLights(-256, 500, 1000)
.setAutoCancel(true);
localBuilder.setContentIntent(localPendingIntent);
notificationManager.notify(NOTIFICATION_ID, localBuilder.build());
}
private void cancelNotification(int id){
SyLog.d(TAG, "cancelNotification");
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
}
调用方式:
ScreenshotsActivity.screenshots(mContext);