In this article we are going to learn about Media projection API for Screen capture.
Introduction
Media Projection was introduced in Lollipop and gives us the ability to capture what’s on the screen and also recording screen.
Media Projection API was introduced in Android API level 21. Using this API we can capture the screen.
Foreground permission is required for android 10 and above version but foreground permissions are not required for versions below Android 10 without that we can record screen but for android 10 and above we want foreground permission Have to take it and show foreground notification with it, only then we will be able to record screen in device above Android 10.
Required Permissions For Screen Capture are given below:
- Android SDK v21
- <uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>
- <uses-permission android:name=”android.permission.RECORD_AUDIO”/>
- <uses-permission android:name=”android.permission.FOREGROUND_SERVICE”/>
Setup Your Manifest File(for Android 10 and above version) :
<application <service android:enabled="true" android:name=".ScreenCapturerService" android:foregroundServiceType="mediaProjection"> </service> </application>
Steps For Capture Screen:
Step-1 Send request for permission
Launching this intent will show a dialog to the user which allows them for screen capture.
MediaProjectionManager mProjectionManager (MediaProjectionManager)getSystemService(android.content.Context.MEDIA_PROJECTION_SERVICE); Intent permissionIntent = mProjectionManager.createScreenCaptureIntent(); startActivityForResult(permissionIntent, REQUEST_CODE_CAPTURE_PERM);
When you send request you can show dialog like this given below:
Below Android 10 you can see like this dialog:
Above Android 10 you can See like this dialog:
Step-2 Get call back of request for permission
Once they accept, you can use the result code and data intent returned in onActivityResult, we are able to create a Media Projection.
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (REQUEST_CODE_CAPTURE_PERM == requestCode) { if (resultCode == RESULT_OK) { //permission allow } else { //permission deny } } }
Step-3 Create Media Projection and create notification
private MediaProjection getMediaProjection() { if (mediaProjection == null) { mediaProjection = ApplicationClass.mProjectionManager.getMediaProjection(mResultCode, mResultData); } return mediaProjection; }
Step-4 Then we use Image Reader for capture screen with defined the height and width using the Window’s DisplayMetrics so it exactly matched the screen size. and define the path where you want to save your capture screen.Using this method you can capture the screen.
private MediaProjection mediaProjection; ImageReader mImageReader; String image_ss; String ssImageFilePath; public void captureImage() { if (mediaProjection == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // showNotification(); Toast.makeText(this, "Captured", Toast.LENGTH_SHORT).show(); } else { startForeground(1, new Notification()); } } WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); final DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); Point size = new Point(); display.getRealSize(size); int mWidth = size.x; int mHeight = size.y; int mDensity = metrics.densityDpi; mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2); final Handler handler = new Handler(); int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; if (getMediaProjection() != null) { getMediaProjection().createVirtualDisplay("ScreenShot", mWidth, mHeight, mDensity, flags, mImageReader.getSurface(), null, handler); } mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { reader.setOnImageAvailableListener(null, handler); Image image = reader.acquireLatestImage(); 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 * metrics.widthPixels; // create bitmap Bitmap bmp = Bitmap.createBitmap(metrics.widthPixels + (int) ((float) rowPadding / (float) pixelStride), metrics.heightPixels, Bitmap.Config.ARGB_8888); bmp.copyPixelsFromBuffer(buffer); image.close(); reader.close(); Bitmap realSizeBitmap = Bitmap.createBitmap(bmp, 0, 0, metrics.widthPixels, bmp.getHeight()); bmp.recycle(); FileOutputStream bytes = null; File capturedImages = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES).getAbsolutePath() + "/Screen Recorder"); if (!capturedImages.exists()) { capturedImages.mkdirs(); } image_ss = "Screen_Recording_Image_" + System.currentTimeMillis(); ssImageFilePath = capturedImages + File.separator + image_ss + ".jpg"; Log.d(TAG, ssImageFilePath); File f = null; try { f = new File(ssImageFilePath); bytes = new FileOutputStream(f); realSizeBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes); bytes.flush(); bytes.close(); } catch (IOException e) { e.printStackTrace(); } MediaScannerConnection.scanFile(getApplicationContext(), new String[]{ssImageFilePath}, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { Intent intent1 = new Intent(getApplicationContext(), TransparentActivity.class).addFlags(FLAG_ACTIVITY_NEW_TASK); intent1.putExtra("path", ssImageFilePath); Log.i(TAG, "onActivityResult:Path--->" + ssImageFilePath); startActivity(intent1); Log.d(TAG, ssImageFilePath); stopCapture(); } }); } }, handler); }
Stop Capture Screen method:
private void stopCapture() { if (mediaProjection != null) { mediaProjection.stop(); } mediaProjection = null; }