2015/03/10

Android 5.0 MediaProjection API : A simple example

This example is to take a screenshot and save it as image on Android devices
using MediaProjection API.

MainActivity.java

public class MainActivity extends Activity
{
    private static final int PERMISSION_CODE = 1;
    private static final List RESOLUTIONS = new ArrayList() 
    {{
        add(new Resolution(640,360));
        add(new Resolution(960,540));
        add(new Resolution(1366,768));
        add(new Resolution(1600,900));
    }};
    private int mScreenDensity;
    private MediaProjectionManager mProjectionManager;
    private int mDisplayWidth;
    private int mDisplayHeight;
    private boolean mScreenSharing;
    private MediaProjection mMediaProjection;
    private VirtualDisplay mVirtualDisplay;
    private Surface mSurface;
    private SurfaceView mSurfaceView;

    private ImageReader mImageReader;
    DisplayMetrics metrics;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    int count = 0;
 
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        mScreenDensity = metrics.densityDpi;
     
        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
        mSurface = mSurfaceView.getHolder().getSurface();
mProjectionManager=(MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

        ArrayAdapter arrayAdapter = new ArrayAdapter(
                this, android.R.layout.simple_list_item_1, RESOLUTIONS);
     
        Spinner s = (Spinner) findViewById(R.id.spinner);
        s.setAdapter(arrayAdapter);
        s.setOnItemSelectedListener(new ResolutionSelector());
        s.setSelection(0);
     
        // start capture handling thread
   new Thread()
   {
    @Override
    public void run()
    {
    Looper.prepare();
    mHandler = new Handler();
    Looper.loop();
    }
   }.start();
    }
 
    @Override
    public void onDestroy()
    {
        super.onDestroy();
     
        if (mMediaProjection != null)
        {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }
 
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
    if (requestCode == PERMISSION_CODE)
    {
       if (requestCode != PERMISSION_CODE)
       {
                return;
            }
            if (resultCode != RESULT_OK)
            {
                return;
            }
         
            mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
            mVirtualDisplay = createVirtualDisplay();
         
            if (mMediaProjection != null)
            {
            final DisplayMetrics metrics = getResources().getDisplayMetrics();
        int density = metrics.densityDpi;
      int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        final int width = size.x;
        final int height = size.y;
       
        mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 5);
        mMediaProjection.createVirtualDisplay("screencap", width, height, density, flags, mImageReader.getSurface(), new VirtualDisplayCallback(), mHandler);
       
        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener()
        {
                    @Override
                    public void onImageAvailable(ImageReader reader)
                    {
                    FileOutputStream fos = null;
                         Bitmap bitmap = null;
                         Image img = null;
                       
                         try
                         {
                             img = reader.acquireLatestImage();
                           
                             if (img != null)
                             {
                                 Image.Plane[] planes = img.getPlanes();
                                 if (planes[0].getBuffer() == null)
                                 {
                                     return;
                                 }
                                 int width = img.getWidth();
                                 int height = img.getHeight();
                                 int pixelStride = planes[0].getPixelStride();
                                 int rowStride = planes[0].getRowStride();
                                 int rowPadding = rowStride - pixelStride * width;

                                 int offset = 0;
                            bitmap = Bitmap.createBitmap(metrics,width, height, Bitmap.Config.ARGB_8888);
                                 ByteBuffer buffer = planes[0].getBuffer();
                                 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 |= (buffer.get(offset + 3) & 0xff) << 24; // A
                                         bitmap.setPixel(j, i, pixel);
                                         offset += pixelStride;
                                     }
                                     offset += rowPadding;
                                 }
                                 String name = "/myscreen" + count + ".png";
                                 count++;
                                 File file = new File(Environment.getExternalStorageDirectory(), name);
                                 fos = new FileOutputStream(file);
                                 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                                 img.close();
                             }
                         }
                         catch (Exception e)
                         {
                         }
                         finally
                         {
                             if (null != fos)
                             {
                                 try
                                 {
                                     fos.close();
                                 }
                                 catch (Exception e)
                                 {
                                 }
                             }
                           
                             if (null != bitmap)
                             {
                                 bitmap.recycle();
                             }
                           
                             if (null != img)
                             {
                                 img.close();
                             }
                         }
                    }
                }, mHandler);
            }
    }
    }
 
    private class VirtualDisplayCallback extends VirtualDisplay.Callback
    {
@Override
public void onPaused()
{
 super.onPaused();
}

@Override
public void onResumed()
{
 super.onResumed();
}

@Override
public void onStopped()
{
 super.onStopped();
}
    }
 
    public void onToggleScreenShare(View view)
    {
        if (((ToggleButton) view).isChecked())
        {
            shareScreen();
        }
        else
        {
            stopScreenSharing();
        }
    }
 
    private void shareScreen()
    {
        mScreenSharing = true;
     
        if (mSurface == null)
        {
            return;
        }
     
        if (mMediaProjection == null)
        {
     startActivityForResult(mProjectionManager.createScreenCaptureIntent(), PERMISSION_CODE);
            return;
        }
    }
 
    private void stopScreenSharing()
    {
        mScreenSharing = false;
     
        if (mVirtualDisplay == null)
        {
            return;
        }
        mVirtualDisplay.release();
    }
 
    private VirtualDisplay createVirtualDisplay()
    {
        return mMediaProjection.createVirtualDisplay("ScreenSharingDemo",
                mDisplayWidth, mDisplayHeight, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mSurface, null /*Callbacks*/, null /*Handler*/);
    }
 
    private class ResolutionSelector implements Spinner.OnItemSelectedListener
    {
        @Override
        public void onItemSelected(AdapterView parent, View v, int pos, long id)
        {
            Resolution r = (Resolution) parent.getItemAtPosition(pos);
            ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
         
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
            {
                mDisplayHeight = r.y;
                mDisplayWidth = r.x;
            }
            else
            {
                mDisplayHeight = r.x;
                mDisplayWidth = r.y;
            }
            lp.height = mDisplayHeight;
            lp.width = mDisplayWidth;
            mSurfaceView.setLayoutParams(lp);
        }
     
        @Override
        public void onNothingSelected(AdapterView parent) { /* Ignore */ }
    }

    private static class Resolution
    {
        int x;
        int y;
     
        public Resolution(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
     
        @Override
        public String toString()
        {
            return x + "x" + y;
        }
    }
}

References:
http://goo.gl/drn3ZD
http://goo.gl/MnoIds