一键截屏 5.0以下使用命令模式 5.0以上使用系统截屏

命令模式需要root权限。

截屏代码:

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

你可能感兴趣的:(Android)