Solución:
¡Desde Lollipop podemos usar la API de proyección de medios! (API 21+)
Aquí está el siguiente código que utilizo para grabar, tenga en cuenta que primero necesitamos obtener los permisos de usuario para eso;)
private static final int CAST_PERMISSION_CODE = 22;
private DisplayMetrics mDisplayMetrics;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMediaRecorder = new MediaRecorder();
mProjectionManager = (MediaProjectionManager) getSystemService
(Context.MEDIA_PROJECTION_SERVICE);
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
prepareRecording();
}
private void startRecording() {
// If mMediaProjection is null that means we didn't get a context, lets ask the user
if (mMediaProjection == null) {
// This asks for user permissions to capture the screen
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
return;
}
mVirtualDisplay = createVirtualDisplay();
mMediaRecorder.start();
}
private void stopRecording() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.reset();
}
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
}
if (mMediaProjection != null) {
mMediaProjection.stop();
}
prepareRecording();
}
public String getCurSysDate() {
return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
}
private void prepareRecording() {
try {
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
return;
}
final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
return;
}
final File folder = new File(directory);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
String filePath;
if (success) {
String videoName = ("capture_" + getCurSysDate() + ".mp4");
filePath = directory + File.separator + videoName;
} else {
Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
return;
}
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(width, height);
mMediaRecorder.setOutputFile(filePath);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != CAST_PERMISSION_CODE) {
// Where did we get this request from ? -_-
Log.w(TAG, "Unknown request code: " + requestCode);
return;
}
if (resultCode != RESULT_OK) {
Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
return;
}
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
// TODO Register a callback that will listen onStop and release & prepare the recorder for next recording
// mMediaProjection.registerCallback(callback, null);
mVirtualDisplay = getVirtualDisplay();
mMediaRecorder.start();
}
private VirtualDisplay getVirtualDisplay() {
screenDensity = mDisplayMetrics.densityDpi;
int width = mDisplayMetrics.widthPixels;
int height = mDisplayMetrics.heightPixels;
return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
width, height, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}
Este no es el código final, sino una BUENA base para empezar 🙂
EDITAR: Esta respuesta es reemplazada por la siguiente respuesta de Danpe.
La grabación de video mediante programación desde su aplicación requerirá acceso de root. Notarás que las aplicaciones disponibles para hacer esto en Play Store enumeran de manera prominente “REQUIERE ROOT” en las descripciones de sus aplicaciones. También notará que también puede haber algunos requisitos de hardware específicos para que este enfoque funcione (“No funciona en Galaxy Nexus o Tegra 2/3 …”, según la descripción de la aplicación Screencast Video Recorder.
Nunca he escrito este código, pero he reunido una idea de muy alto nivel del enfoque requerido. De esta publicación parece que debe acceder a los datos del búfer de tramas a través de “/ dev / graphics / fb0”. El modo de acceso para el búfer de tramas es 660, lo que significa que necesita acceso de root para acceder a él. Una vez que tenga acceso de root, puede usar los datos del búfer de fotogramas para crear capturas de pantalla (este proyecto podría funcionar para esta tarea) y luego crear un video a partir de estas capturas de pantalla (consulte esta otra pregunta de SO sobre cómo crear un video a partir de una secuencia de imágenes).
He usado la aplicación Screencast y funciona bien en un Samsung Note. Sospecho que este es el enfoque básico que han adoptado.
Las aplicaciones normales de Android carecen de permiso para capturar el búfer de fotogramas (específicamente, no son miembros del grupo AID_GRAPHICS). Esto es por razones de seguridad; de lo contrario, podrían husmear contraseñas, etc.desde el teclado virtual. Entonces, en general, NO PUEDE capturar la pantalla desde una aplicación de Android sin alguna forma de evitar el problema de los privilegios.
Usted PUEDE capturar más o menos una instantánea del área de la pantalla que ocupa actualmente su aplicación atravesando la vista superior en su jerarquía de vista y dibujándola en un mapa de bits usando View.draw (Canvas), sin embargo, esto no registrará la barra de estado, teclado virtual, superficies OpenGL, etc.
Si desea hacerlo mejor, deberá utilizar una herramienta externa. Las herramientas necesitan root o usar la interfaz ADB, ya que los procesos iniciados a través de la interfaz ADB tienen el privilegio AID_GRAPHICS. Con el último método, una aplicación sin privilegios puede conectarse a un servidor privilegiado para realizar la grabación.
A grandes rasgos, las herramientas se pueden dividir en las siguientes categorías:
-
Aplicaciones de grabación de framebuffer solo para root (por ejemplo, Screencast). Estos graban directamente desde el dispositivo / dev / graphics / fb0, pero solo funcionan en dispositivos donde el framebuffer es legible (por ejemplo, no en el Tegra 2 Nexus 7).
-
Aplicaciones de grabación de captura de pantalla solo para root (por ejemplo, SCR, Rec, etc.). Estos capturan la pantalla a través de SurfaceFlinger y funcionan en una gama mucho más amplia de dispositivos.
-
Aplicaciones de grabación de captura de pantalla que no son root (por ejemplo, Recordable, Ascrecorder). Estos requieren que el usuario habilite la depuración USB e inicie un demonio mientras está conectado a través de una PC host. A partir de entonces, la PC host no es necesaria hasta que se reinicia el dispositivo. También puede grabar audio.
-
Herramientas ADB (por ejemplo, la grabadora de pantalla incorporada en Android 4.4). Requiere que esté conectado a través de un USB y no puede capturar audio.
Hace unos meses hice una comparación de las aplicaciones disponibles que está disponible aquí:
http://recordable.mobi/compare
Para completar, también hay herramientas USB (por ejemplo, Mobizen) que transmiten la pantalla a través de USB (limitado por un ancho de banda de USB bajo y no pueden grabar audio) y algunos dispositivos también pueden transmitir la pantalla a través de wifi, que luego se puede capturar en un dispositivo separado .