Tomar capturas de pantalla programáticamente no captura los contenidos de SurfaceVIew

Tengo una aplicación que quiero poder capturar una captura de pantalla. El fondo del diseño es un SurfaceView que muestra el video de la cámara trasera. El siguiente código es capaz de tomar una captura de pantalla, pero el contenido de la superficie se guarda como negro. Aquí está el código:

btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { Random num = new Random(); int nu=num.nextInt(1000); Bitmap bmp; CamView.setDrawingCacheEnabled(true); CamView.buildDrawingCache(true); Bitmap bmp2 = Bitmap.createBitmap(CamView.getDrawingCache()); //Screenshot of the layout CamView.setDrawingCacheEnabled(false); SurView.setDrawingCacheEnabled(true); SurView.buildDrawingCache(true); Bitmap bmp1 = Bitmap.createBitmap(SurView.getDrawingCache()); //Screenshot of the surfaceView SurView.setDrawingCacheEnabled(false); Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(),bmp1.getConfig()); Canvas canvas = new Canvas(bmOverlay); //Overlaying the 2 bitmaps canvas.drawBitmap(bmp1, 0,0, null); canvas.drawBitmap(bmp2, 0,0, null); bmp=bmOverlay; //saving the file ByteArrayOutputStream bos = new ByteArrayOutputStream(); bmp.compress(CompressFormat.JPEG, 100, bos); byte[] bitmapdata = bos.toByteArray(); ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); String picId=String.valueOf(nu); String myfile="Ghost"+picId+".jpeg"; File dir_image = new File(Environment.getExternalStorageDirectory()+ File.separator+"Ultimate Entity Detector"); dir_image.mkdirs(); try { File tmpFile = new File(dir_image,myfile); FileOutputStream fos = new FileOutputStream(tmpFile); byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) > 0) { fos.write(buf, 0, len); } fis.close(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); 

Actualicé el código. Ahora creo 2 mapas de bits, 1 para el diseño xml y 1 para SurfaceView y luego los superpuso en un solo bitmap. Pero el bitmap de SurfaceView sigue siendo negro

Finalmente resolví esto. A continuación, le doy un código para que cualquiera que quiera saber cómo tomar capturas de pantalla de un diseño, imágenes de la cámara sin intención, capturas de pantalla (más o menos) del contenido de un SurfaceView y guardar la captura de pantalla en una carpeta:

 public class Cam_View extends Activity implements SurfaceHolder.Callback { protected static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 0; private SurfaceView SurView; private SurfaceHolder camHolder; private boolean previewRunning; final Context context = this; public static Camera camera = null; private RelativeLayout CamView; private Bitmap inputBMP = null, bmp, bmp1; private ImageView mImage; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera); CamView = (RelativeLayout) findViewById(R.id.camview);//RELATIVELAYOUT OR //ANY LAYOUT OF YOUR XML SurView = (SurfaceView)findViewById(R.id.sview);//SURFACEVIEW FOR THE PREVIEW //OF THE CAMERA FEED camHolder = SurView.getHolder(); //NEEDED FOR THE PREVIEW camHolder.addCallback(this); //NEEDED FOR THE PREVIEW camHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//NEEDED FOR THE PREVIEW camera_image = (ImageView) findViewById(R.id.camera_image);//NEEDED FOR THE PREVIEW Button btn = (Button) findViewById(R.id.button1); //THE BUTTON FOR TAKING PICTURE btn.setOnClickListener(new OnClickListener() { //THE BUTTON CODE public void onClick(View v) { camera.takePicture(null, null, mPicture);//TAKING THE PICTURE //THE mPicture IS CALLED //WHICH IS THE LAST METHOD(SEE BELOW) } }); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width,//NEEDED FOR THE PREVIEW int height) { if(previewRunning) { camera.stopPreview(); } Camera.Parameters camParams = camera.getParameters(); Camera.Size size = camParams.getSupportedPreviewSizes().get(0); camParams.setPreviewSize(size.width, size.height); camera.setParameters(camParams); try { camera.setPreviewDisplay(holder); camera.startPreview(); previewRunning=true; } catch(IOException e) { e.printStackTrace(); } } public void surfaceCreated(SurfaceHolder holder) { //NEEDED FOR THE PREVIEW try { camera=Camera.open(); } catch(Exception e) { e.printStackTrace(); Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); finish(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { //NEEDED FOR THE PREVIEW camera.stopPreview(); camera.release(); camera=null; } public void TakeScreenshot(){ //THIS METHOD TAKES A SCREENSHOT AND SAVES IT AS .jpg Random num = new Random(); int nu=num.nextInt(1000); //PRODUCING A RANDOM NUMBER FOR FILE NAME CamView.setDrawingCacheEnabled(true); //CamView OR THE NAME OF YOUR LAYOUR CamView.buildDrawingCache(true); Bitmap bmp = Bitmap.createBitmap(CamView.getDrawingCache()); CamView.setDrawingCacheEnabled(false); // clear drawing cache ByteArrayOutputStream bos = new ByteArrayOutputStream(); bmp.compress(CompressFormat.JPEG, 100, bos); byte[] bitmapdata = bos.toByteArray(); ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); String picId=String.valueOf(nu); String myfile="Ghost"+picId+".jpeg"; File dir_image = new File(Environment.getExternalStorageDirectory()+//< --- File.separator+"Ultimate Entity Detector"); //<--- dir_image.mkdirs(); //<--- //^IN THESE 3 LINES YOU SET THE FOLDER PATH/NAME . HERE I CHOOSE TO SAVE //THE FILE IN THE SD CARD IN THE FOLDER "Ultimate Entity Detector" try { File tmpFile = new File(dir_image,myfile); FileOutputStream fos = new FileOutputStream(tmpFile); byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) > 0) { fos.write(buf, 0, len); } fis.close(); fos.close(); Toast.makeText(getApplicationContext(), "The file is saved at :SD/Ultimate Entity Detector",Toast.LENGTH_LONG).show(); bmp1 = null; camera_image.setImageBitmap(bmp1); //RESETING THE PREVIEW camera.startPreview(); //RESETING THE PREVIEW } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private PictureCallback mPicture = new PictureCallback() { //THIS METHOD AND THE METHOD BELOW //CONVERT THE CAPTURED IMAGE IN A JPG FILE AND SAVE IT @Override public void onPictureTaken(byte[] data, Camera camera) { File dir_image2 = new File(Environment.getExternalStorageDirectory()+ File.separator+"Ultimate Entity Detector"); dir_image2.mkdirs(); //AGAIN CHOOSING FOLDER FOR THE PICTURE(WHICH IS LIKE A SURFACEVIEW //SCREENSHOT) File tmpFile = new File(dir_image2,"TempGhost.jpg"); //MAKING A FILE IN THE PATH //dir_image2(SEE RIGHT ABOVE) AND NAMING IT "TempGhost.jpg" OR ANYTHING ELSE try { //SAVING FileOutputStream fos = new FileOutputStream(tmpFile); fos.write(data); fos.close(); //grabImage(); } catch (FileNotFoundException e) { Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); } catch (IOException e) { Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); } String path = (Environment.getExternalStorageDirectory()+ File.separator+"Ultimate EntityDetector"+ File.separator+"TempGhost.jpg");//< --- BitmapFactory.Options options = new BitmapFactory.Options();//<--- options.inPreferredConfig = Bitmap.Config.ARGB_8888;//<--- bmp1 = BitmapFactory.decodeFile(path, options);//<--- *********(SEE BELOW) //THE LINES ABOVE READ THE FILE WE SAVED BEFORE AND CONVERT IT INTO A BitMap camera_image.setImageBitmap(bmp1); //SETTING THE BitMap AS IMAGE IN AN IMAGEVIEW(SOMETHING //LIKE A BACKGROUNG FOR THE LAYOUT) tmpFile.delete(); TakeScreenshot();//CALLING THIS METHOD TO TAKE A SCREENSHOT //********* THAT LINE MIGHT CAUSE A CRASH ON SOME PHONES (LIKE XPERIA T)<----(SEE HERE) //IF THAT HAPPENDS USE THE LINE "bmp1 =decodeFile(tmpFile);" WITH THE METHOD BELOW } }; public Bitmap decodeFile(File f) { //FUNCTION BY Arshad Parwez Bitmap b = null; try { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; FileInputStream fis = new FileInputStream(f); BitmapFactory.decodeStream(fis, null, o); fis.close(); int IMAGE_MAX_SIZE = 1000; int scale = 1; if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) { scale = (int) Math.pow( 2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5))); } // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; fis = new FileInputStream(f); b = BitmapFactory.decodeStream(fis, null, o2); fis.close(); } catch (IOException e) { e.printStackTrace(); } return b; } } 

Si desea tomar una captura de pantalla simple (no se necesita alimentación de cámara) puede usar el método TakeScreenshot solo.

Si no quiere hacer una captura de pantalla de un SurfaceView con la vista de superficie directamente, use mPicture, configure la imagen que captura como fondo y luego llame a TakeScreenshot para tomar su captura de pantalla. (Como se ve arriba)

Si quiere tomar una foto con la cámara sin llamar a otra aplicación de cámara con la intención de usar la toma tomar una fotografía con la mPicture y la vista de superficie del código anterior.

Lo que hace el código anterior si se usa “tal cual” es tomar una captura de pantalla de los contenidos del diseño (botones, imágenes, etc.) y establecer como imagen de fondo de la cámara.

A continuación, también proporciono un diseño básico xml para el código anterior:

 < ?xml version="1.0" encoding="utf-8"?>      

No te olvides de importar lo que necesita ser importado

De acuerdo con el comentario ( https://groups.google.com/forum/#!topic/android-developers/jYjvm7ItpXQ ) realizado por un ingeniero de Android Framework, SurfaceView no se trata como una vista normal:

La vista de la superficie es en realidad DETRÁS de su ventana, y un agujero en la ventana para que pueda verlo. De este modo, puede colocar las cosas encima en su ventana, pero nada en su ventana puede aparecer detrás de ella.

Como está “DETRÁS” de la ventana de la aplicación, en consecuencia, el dibujo de la vista de la ventana no lo contendría. Supongo que la única manera entonces es proporcionar un método en su clase SurfaceView para dibujar su propio contenido en el Canvas / Bitmap provisto.