Android关于MediaProject截图的正确姿势(最新)

Posted 写Bug的渣渣高

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android关于MediaProject截图的正确姿势(最新)相关的知识,希望对你有一定的参考价值。

在使用 MediaProject 的过程种,遇到了N种错误,自己一直也没有解决

下面来分享一个我找到的资料,我对作者的代码进行了小部分的修改来完成我的功能。在这里非常感谢作者,
我在各种平台都搜集了很久,没有找到一个可用的 MeidaPorject 截屏代码,而网上的教程各式各样,但是实操都会遇到各种各样的问题。由于作者好像在除了 github 平台发布了代码之外,在其他平台并没有找到。
特此,使用了作者代码截屏的部分,并修改了部分代码,作者的github仓库

sdk 28

MainActivity

public class MainActivity extends BaseActivity implements View.OnClickListener 

    private static final int REQUEST_CODE = 100;
    private static MediaProjection sMediaProjection;
    Button mBtnCapture;
    private MediaProjectionManager mProjectionManager;
    private ScreenCapturer mSC;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtnCapture = findViewById(R.id.btn_capture);
        mBtnCapture.setOnClickListener(this);
        mProjectionManager = (MediaProjectionManager) getSystemService(
                Context.MEDIA_PROJECTION_SERVICE);

    

    @Override
    protected void onResume() 
        super.onResume();
    

    @Override
    public void onClick(View v) 
        switch (v.getId()) 
            case R.id.btn_capture:
                startActivityForResult(mProjectionManager.createScreenCaptureIntent(),
                        REQUEST_CODE);
                break;
            default:
                break;
        
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        super.onActivityResult(requestCode, resultCode, data);
        Log.d("WOW", "on result : requestCode = " + requestCode + " resultCode = " + resultCode);
        if (RESULT_OK == resultCode && REQUEST_CODE == requestCode) 
            sMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
            if (sMediaProjection != null) 
                Log.d("WOW", "Start capturing...");
                new ScreenCapturer(this, sMediaProjection, "").startProjection();
            
        
    


BaseActivity

public class BaseActivity extends AppCompatActivity 

    private static final int REQUEST_CODE = 9527;

    private static String[] PERMISSIONS = 
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.CAMERA
    ;

    @Override
    protected void onResume() 
        super.onResume();
        checkPermissions();
    

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
            grantResults) 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (REQUEST_CODE == requestCode) 
            boolean isAllGranted = false;
            for (int result : grantResults) 
                if (result != PackageManager.PERMISSION_GRANTED) 
                    isAllGranted = false;
                    break;
                
                isAllGranted = true;
            
            if (!isAllGranted) 
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage("Need Permission");
                builder.setPositiveButton("Grant now", new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        intent.addCategory(Intent.CATEGORY_DEFAULT);
                        intent.setData(Uri.parse("package:" + getPackageName()));
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                        startActivity(intent);
                    
                );
                builder.setNegativeButton("Fuck yourself", null);
                builder.show();
             else 

            
        
    

    //permission
    private void checkPermissions() 
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) 
            return;
        

        Boolean isAllPermissionGranted = false;
        for (String permission : PERMISSIONS) 
            if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) 
                isAllPermissionGranted = false;
                break;
            
            isAllPermissionGranted = true;
        

        if (!isAllPermissionGranted) 
            requestPermissions(PERMISSIONS, REQUEST_CODE);
        
    

ScreenCapture

public class ScreenCapturer 
    private static MediaProjection sMediaProjection;
    boolean isScreenCaptureStarted;
    OnImageCaptureScreenListener listener;
    private int mDensity;
    private Display mDisplay;
    private int mWidth;
    private int mHeight;
    private ImageReader mImageReader;
    private VirtualDisplay mVirtualDisplay;
    private Handler mHandler;
    private String STORE_DIR;
    private Context mContext;

    public ScreenCapturer(Context context, MediaProjection mediaProjection, String savePath) 
        sMediaProjection = mediaProjection;
        mContext = context;

        isScreenCaptureStarted = false;

        new Thread() 
            @Override
            public void run() 
                Looper.prepare();
                mHandler = new Handler();
                Looper.loop();
            
        .start();


        if (TextUtils.isEmpty(savePath)) 
            File externalFilesDir = mContext.getExternalFilesDir(null);
            Log.d("WOW", "externalFilesDir:" + externalFilesDir.getAbsolutePath());
            if (externalFilesDir != null) 
                STORE_DIR = externalFilesDir.getAbsolutePath() + "/myScreenshots";
             else 
                Toast.makeText(mContext, "No save path assigned!", Toast.LENGTH_SHORT).show();
            
         else 
            STORE_DIR = savePath;
        
    

    public ScreenCapturer startProjection() 
        if (sMediaProjection != null) 
            File storeDir = new File(STORE_DIR);
            if (!storeDir.exists()) 
                boolean success = storeDir.mkdirs();
                if (!success) 
                    Log.d("WOW", "mkdir " + storeDir + "  failed");
                    return this;
                 else 
                    Log.d("WOW", "mkdir " + storeDir + "  success");
                
             else 
                Log.d("WOW", " " + storeDir + "  exist");
            

         else 
            Log.d("WOW", "get mediaprojection failed");
        

        try 
            Thread.sleep(500); // 防止截屏截到 显示截屏权限的窗口
            isScreenCaptureStarted = true;
         catch (InterruptedException e) 
                e.printStackTrace();
        
        WindowManager window = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        mDisplay = window.getDefaultDisplay();
        final DisplayMetrics metrics = new DisplayMetrics();
        // use getMetrics is 2030, use getRealMetrics is 2160, the diff is NavigationBar's height
        mDisplay.getRealMetrics(metrics);
        mDensity = metrics.densityDpi;
        Log.d("WOW", "metrics.widthPixels is " + metrics.widthPixels);
        Log.d("WOW", "metrics.heightPixels is " + metrics.heightPixels);
        mWidth = metrics.widthPixels;
        mHeight = metrics.heightPixels;

        //start capture reader
        mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2);
        mVirtualDisplay = sMediaProjection.createVirtualDisplay(
                "ScreenShot",
                mWidth,
                mHeight,
                mDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                mImageReader.getSurface(),
                null,
                mHandler);

        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() 
            @Override
            public void onImageAvailable(ImageReader reader) 

                if (isScreenCaptureStarted) 

                    Image image = null;
                    FileOutputStream fos = null;
                    Bitmap bitmap = null;

                    try 
                        image = reader.acquireLatestImage();
                        if (image != null) 
//                            bitmap = ImageUtils.image_ARGB8888_2_bitmap(metrics, image);
                            bitmap = ImageUtils.image_2_bitmap(image, Bitmap.Config.ARGB_8888);
                            if (null != listener) 
                                listener.imageCaptured(ImageUtils.bitmap2byte(bitmap, 80));
                            

                            Date currentDate = new Date();
                            SimpleDateFormat date = new SimpleDateFormat("yyyyMMddhhmmss");
                            String fileName = STORE_DIR + "/myScreen_" + date.format(
                                    currentDate) + ".png";
                            fos = new FileOutputStream(fileName);
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                            Log.d("WOW", "End now!!!!!!  Screenshot saved in " + fileName);
                            Toast.makeText(mContext, "Screenshot saved in " + fileName,
                                    Toast.LENGTH_LONG).show();
                            stopProjection();
                        
                     catch (FileNotFoundException e) 
                        e.printStackTrace();
                     finally 
                        if (null != fos) 
                            try 
                                fos.close();
                             catch (IOException e) 
                                e.printStackTrace();
                            
                        
                        if (null != bitmap) 
                            bitmap.recycle();
                        
                        if (null != image) 
                            image.close();
                        
                    
                
            
        , mHandler);
        sMediaProjection.registerCallback(new MediaProjectionStopCallback(), mHandler);
        return this;
    

    public ScreenCapturer stopProjection() 
        isScreenCaptureStarted = false;
        Log.d("WOW", "Screen captured");
        mHandler.post(new Runnable() 
            @Override
            public void run() 
                if (sMediaProjection != null) 
                    sMediaProjection.stop();
                
            
        );
        return this;
    

    public ScreenCapturer setListener(OnImageCaptureScreenListener listener) 
        this.listener = listener;
        return this;
    

    public interface OnImageCaptureScreenListener 
        public void imageCaptured(byte[] image);
    

    private class MediaProjectionStopCallback extends MediaProjection.Callback 
        @Override
        public void onStop() 
            mHandler.post(new Runnable() 
                @Override
                public void run() 
                    if (mVirtualDisplay != null) 
                        mVirtualDisplay.release();
                    
                    if (mImageReader != null) 
                        mImageReader.setOnImageAvailableListener(null, null);
                    
                    sMediaProjection.unregisterCallback(MediaProjectionStopCallback.this);
                
            );
        
    

ImageUtils

public class ImageUtils 

    public static Bitmap image_ARGB8888_2_bitmap(DisplayMetrics metrics, Image image) 
        Image.Plane[] planes = image.getPlanes();
        ByteBuffer buffer = planes[0].getBuffer();

        int width = image.getWidth();
        int height = image.getHeight();
        int pixelStride = planes[0].getPixelStride();
        int rowStride = planes[0].getRowStride();
        int rowPadding = rowStride - pixelStride * width;

        int offset = 0;
        Bitmap bitmap;
        bitmap = Bitmap.createBitmap(metrics, width, height, Bitmap.Config.ARGB_8888);
        for (int i = 0; i < height; ++i) 
            for (int j = 0; j < width; ++j) 
                int pixel = 0;
                pixel |= (buffer.get(offset) & 0xff) << 16;     // R
                pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
                pixel |= (buffer.get(offset + 2) & 0xff);       // B
                pixel |= (buf

以上是关于Android关于MediaProject截图的正确姿势(最新)的主要内容,如果未能解决你的问题,请参考以下文章

急急急!求教关于android2.3.4添加藏文语言后,大部分能够显示,但是上、下加字叠加严重,显示不正确

关于日期的正序倒序问题

关于Android滑动冲突的解决方法

关于Android开发中的证书和密钥等问题

Android浮动活动与滑动关闭

怎么查看手机的安卓系统版本