Android toma una captura de pantalla en un dispositivo enraizado
ACTUALIZACIÓN Hay un número de otros puestos preguntando cómo obtener una captura de pantalla en android, pero ninguno parecía tener una respuesta completa de cómo hacerlo. Originalmente publiqué esto como una pregunta debido a una edición particular que funcionaba mientras que intentaba abrir una corriente al amortiguador del capítulo. Ahora he cambiado a dumping el búfer del marco a un archivo así que he puesto al día mi poste para demostrar cómo conseguí allí. Para referencia (y reconocimiento), encontré el comando para enviar el FrameBuffer a un archivo de esta publicación (por desgracia no proporcionó cómo llegó a ese punto). Sólo estoy perdiendo cómo convertir los datos sin procesar que extraje de la memoria intermedia de marco en un archivo de imagen real.
Mi intención era tomar un volcado completo de la pantalla real en un dispositivo Android. La única manera que pude encontrar para hacerlo sin usar el puente adb era acceder directamente al Buffer de marco del sistema. Obviamente este enfoque requerirá privilegios de root en el dispositivo y para la aplicación que lo ejecuta! Afortunadamente para mis propósitos tengo control sobre cómo se configura el Dispositivo y tener el dispositivo enraizado con privilegios de root proporcionados a mi aplicación es factible. Mi prueba se está realizando actualmente en un viejo Droid que ejecuta 2.2.3.
- Android toma una imagen de pantalla
- COCOS 2D captura de pantalla es negro en Android
- VideoView getDrawingCache devuelve negro
- Deshabilitar la captura de capturas de pantalla en todas las aplicaciones
- Error al ejecutar el comando adb mediante programación
Encontré mis primeras sugerencias sobre cómo abordarlo desde https://stackoverflow.com/a/6970338/1446554 . Después de un poco más de investigación encontré otro artículo que describe cómo ejecutar correctamente los comandos shell como root . Lo estaban utilizando para ejecutar un reinicio, lo utilizo para enviar el búfer de cuadro actual a un archivo real. Mis pruebas actuales sólo han llegado hasta el punto de hacerlo a través de ADB y en una actividad básica (cada raíz proporcionada). Voy a hacer más pruebas de un servicio de ejecución en el fondo, las actualizaciones a venir! Aquí está mi actividad de prueba completa que puede exportar la pantalla actual a un archivo:
public class ScreenshotterActivity extends Activity { public static final String TAG = "ScreenShotter"; private Button _SSButton; private PullScreenAsyncTask _Puller; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); _SSButton = (Button)findViewById(R.id.main_screenshotButton); _SSButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { if (_Puller != null) return; //TODO: Verify that external storage is available! Could always use internal instead... _Puller = new PullScreenAsyncTask(); _Puller.execute((Void[])null); } }); } private void runSuShellCommand(String cmd) { Runtime runtime = Runtime.getRuntime(); Process proc = null; OutputStreamWriter osw = null; StringBuilder sbstdOut = new StringBuilder(); StringBuilder sbstdErr = new StringBuilder(); try { // Run Script proc = runtime.exec("su"); osw = new OutputStreamWriter(proc.getOutputStream()); osw.write(cmd); osw.flush(); osw.close(); } catch (IOException ex) { ex.printStackTrace(); } finally { if (osw != null) { try { osw.close(); } catch (IOException e) { e.printStackTrace(); } } } try { if (proc != null) proc.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream()))); sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream()))); } private String readBufferedReader(InputStreamReader input) { BufferedReader reader = new BufferedReader(input); StringBuilder found = new StringBuilder(); String currLine = null; String sep = System.getProperty("line.separator"); try { // Read it all in, line by line. while ((currLine = reader.readLine()) != null) { found.append(currLine); found.append(sep); } } catch (IOException e) { e.printStackTrace(); } finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots"); if (ssDir.exists() == false) { Log.i(TAG, "Screenshot directory doesn't already exist, creating..."); if (ssDir.mkdirs() == false) { //TODO: We're kinda screwed... what can be done? Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!"); return null; } } File ss = new File(ssDir, "ss.raw"); if (ss.exists() == true) { ss.delete(); Log.i(TAG, "Deleted old Screenshot file."); } String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath(); runSuShellCommand(cmd); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); _Puller = null; } } }
Esto también requiere agregar el permiso android.permission.WRITE_EXTERNAL_STORAGE
al Manifiesto. Como se sugiere en este post . De lo contrario se ejecuta, no se queja, no crea los directorios ni el archivo.
Originalmente no pude obtener datos utilizables desde el Buffer de trama debido a no entender cómo ejecutar correctamente comandos de shell. Ahora que he cambiado a usar las corrientes para ejecutar comandos puedo usar '>' para enviar los datos actuales de la memoria intermedia de marco a un archivo real …
- ¿Cómo tomar una captura de pantalla de la vista de superficie de Android?
- Cómo crear y guardar una captura de pantalla desde una vista de superficie?
- Mostrar pantalla de Android 4.0 dispositivo en la computadora
- Toma una captura de pantalla en Android
- ¿Cómo capturar el contenido de la pantalla del dispositivo Android?
- Adb shell screencap - "permiso denegado"
- API para Android 4.4 de grabación de pantalla?
- ¿Hay una manera de capturar la pantalla como video en tiempo real?
Eso sería diferente para los diferentes teléfonos. Depende del formato gráfico subyacente de su dispositivo. Puede consultar qué formato de gráficos utiliza las llamadas al sistema. Si sólo va a ejecutar esto en los dispositivos que usted conoce el formato gráfico de usted puede escribir un convertidor que lo convierte en un formato conocido.
Puedes echar un vistazo al siguiente proyecto: http://code.google.com/p/android-fb2png/
Si observa el código fuente de fb2png.c, puede ver que encuesta FBIOGET_VSCREENINFO que contiene información acerca de cómo el dispositivo almacena la imagen de la pantalla en la memoria. Una vez que lo sepas, deberías poder convertirlo en un formato que puedas usar.
Espero que esto ayude.
Programáticamente puede ejecutar "adb shell / system / bin / screencap -p /sdcard / img.png" como se muestra a continuación:
Process sh = Runtime.getRuntime().exec("su", null,null); OutputStream os = sh.getOutputStream(); os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII")); os.flush(); os.close(); sh.waitFor();
Una solución fácil para los dispositivos ICS es utilizar lo siguiente desde la línea de comandos
adb shell /system/bin/screencap -p /sdcard/screenshot.png adb pull /sdcard/screenshot.png screenshot.png
Esto salvará el archivo screenshot.png en el directorio actual.
Probado en un Samsung Galaxy SII que ejecuta 4.0.3.
- Cómo acceder a una cadena utilizando un nombre de cadena dinámica en android (similar a eval en javascript)?
- Cómo obtener la altura del elemento recyclerview en "onBindViewHolder"