Proyección de contenido multimedia

La android.media.projection Las APIs presentadas en Android 5 (nivel de API 21) te permiten capturar contenido de un dispositivo se muestra como una transmisión de contenido multimedia en la que puedes reproducir, grabar o transmitir contenido otros dispositivos, como TVs.

Android 14 (nivel de API 34) presenta el uso compartido de pantalla de una app, que permite a los usuarios comparten la ventana de una app en lugar de toda la pantalla del dispositivo, independientemente de la el modo de renderización en ventanas. La opción de compartir pantalla de una app excluye la barra de estado, la barra de navegación notificaciones y otros elementos de la IU del sistema de la pantalla compartida, incluso Cuando se usa la pantalla compartida de una app para capturar una app en pantalla completa. Solo se comparte el contenido de la app seleccionada.

La posibilidad de compartir la pantalla de la app garantiza la privacidad del usuario, aumenta su productividad y mejora la realización de varias tareas a la vez, ya que permite que los usuarios ejecuten múltiples apps, pero restringen para compartir contenido con una sola app.

Tres representaciones de pantalla

Una proyección de contenido multimedia captura el contenido de la pantalla de un dispositivo o la ventana de una app. Luego, proyecta la imagen capturada en una pantalla virtual que la renderiza un objeto Surface.

Pantalla real de un dispositivo proyectada en una pantalla virtual. Contenido de la pantalla virtual escrito en "Surface" que brinda la aplicación.
Figura 1: Pantalla real de un dispositivo o ventana de la app proyectada en pantalla virtual. Pantalla virtual escrita en recursos Surface

La aplicación proporciona el Surface mediante un MediaRecorder, SurfaceTexture o ImageReader, que consume el contenido de la pantalla capturada y te permite administrar las imágenes renderizadas del Surface en tiempo real. Puedes guardar las imágenes como una grabación o transmisión a una TV o a otro dispositivo.

Visualización real

Para iniciar una sesión de proyección de contenido multimedia, obtén un token que le otorgue a tu app la permite capturar el contenido de la pantalla del dispositivo o la ventana de la app. El token se representa mediante una instancia del MediaProjection clase.

Usa el método getMediaProjection() de la Servicio del sistema MediaProjectionManager para crear una instancia de MediaProjection cuando inicies una nueva actividad. Inicia la actividad con un intent desde el Método createScreenCaptureIntent() para especificar una pantalla operación de captura:

Kotlin

val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java)
var mediaProjection : MediaProjection

val startMediaProjection = registerForActivityResult(
    StartActivityForResult()
) { result ->
    if (result.resultCode == RESULT_OK) {
        mediaProjection = mediaProjectionManager
            .getMediaProjection(result.resultCode, result.data!!)
    }
}

startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())

Java

final MediaProjectionManager mediaProjectionManager =
    getSystemService(MediaProjectionManager.class);
final MediaProjection[] mediaProjection = new MediaProjection[1];

ActivityResultLauncher<Intent> startMediaProjection = registerForActivityResult(
    new StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            mediaProjection[0] = mediaProjectionManager
                .getMediaProjection(result.getResultCode(), result.getData());
        }
    }
);

startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

Pantalla virtual

La pieza central de una proyección de contenido multimedia es la pantalla virtual, que creas cuando llamas a createVirtualDisplay() en una instancia de MediaProjection:

Kotlin

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null)

Java

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null);

Los parámetros width y height especifican las dimensiones de la VM pantalla. Para obtener valores de ancho y altura, usa la Se introdujeron las APIs de WindowMetrics en Android 11 (nivel de API 30). (Para obtener más información, consulta la Tamaño de proyección de contenido multimedia).

Superficie

Ajusta el tamaño de la superficie de proyección de contenido multimedia para producir resultados de la resolución. Haz que la superficie sea grande (baja resolución) para transmitir la pantalla a TVs o monitores de computadora y uno pequeño (alta resolución) para grabar la pantalla del dispositivo.

A partir de Android 12L (nivel de API 32), cuando se renderice el contenido capturado en la , el sistema ajusta el contenido de manera uniforme manteniendo la relación de aspecto para que ambas dimensiones del contenido (ancho y alto) sean iguales o menores que las dimensiones correspondientes de la superficie. Luego, el contenido capturado centrado en la superficie.

El enfoque de escalamiento de Android 12L mejora la transmisión de la pantalla a televisores y otras pantallas grandes maximizando el tamaño de la imagen de la superficie y garantizando la relación de aspecto adecuada.

Permiso de servicios en primer plano

Si tu app está orientada a Android 14 o versiones posteriores, su manifiesto debe incluir una la declaración de permisos para el Tipo de servicio en primer plano mediaProjection:

<manifest ...>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <application ...>
        <service
            android:name=".MyMediaProjectionService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false">
        </service>
    </application>
</manifest>

Inicia el servicio de proyección de contenido multimedia con una llamada a startForeground().

Si no especificas el tipo de servicio en primer plano en la llamada, el tipo predeterminado en un entero a nivel de bits de los tipos de servicios en primer plano definidos en el manifiesto. Si el manifiesto no especifica ningún tipo de servicio, el sistema arroja MissingForegroundServiceTypeException

Tu app debe solicitar el consentimiento del usuario antes de cada sesión de proyección de contenido multimedia. R sesión es una llamada única a createVirtualDisplay(). Un token de MediaProjection debe usarse una sola vez para realizar la llamada.

En Android 14 o versiones posteriores, el método createVirtualDisplay() arroja un SecurityException si tu La app realiza cualquiera de las siguientes acciones:

  • Pasa una instancia de Intent que se muestra de createScreenCaptureIntent() a getMediaProjection() más de una vez
  • Llama a createVirtualDisplay() más de una vez en el mismo MediaProjection instancia

Tamaño de proyección de contenido multimedia

Una proyección de contenido multimedia puede capturar toda la pantalla del dispositivo o la ventana de una app. independientemente del modo de renderización en ventanas.

Tamaño inicial

Con la proyección de contenido multimedia en pantalla completa, tu app debe determinar el tamaño de la pantalla del dispositivo. Al compartir pantalla en la app, la app no podrá determinar la tamaño de la pantalla capturada hasta que el usuario seleccione la región de captura. Por lo tanto, el tamaño inicial de cualquier proyección de contenido multimedia es el tamaño de la pantalla del dispositivo.

Usar la plataforma WindowManager getMaximumWindowMetrics() para mostrar un WindowMetrics correspondiente al pantalla del dispositivo incluso si la app host de proyección de contenido multimedia está en el modo multiventana y ocupa solo una parte de la pantalla.

Para brindar compatibilidad hasta el nivel de API 14, usa WindowMetricsCalculator computeMaximumWindowMetrics(). de la biblioteca WindowManager de Jetpack.

Llama al método WindowMetrics getBounds() para obtener el ancho y la altura de la pantalla del dispositivo.

Cambios de tamaño

El tamaño de la proyección de contenido multimedia puede cambiar cuando se rota el dispositivo o que el usuario seleccione una ventana de la app como la región de captura en la pantalla compartida de la app. La proyección de contenido multimedia puede tener formato letterbox si el contenido capturado es una un tamaño diferente al de las métricas máximas de la ventana que se obtienen cuando el se configuró la proyección.

Para garantizar que la proyección de contenido multimedia se alinee con precisión con el tamaño de la imagen contenido para cualquier región capturada y entre las rotaciones de dispositivos, usa el Es la devolución de llamada onCapturedContentResize() para cambiar el tamaño de la captura. (Para obtener más consulta la sección Personalización a continuación).

Personalización

Tu app puede personalizar la experiencia del usuario de proyección de contenido multimedia con lo siguiente APIs de MediaProjection.Callback:

  • onCapturedContentVisibilityChanged(): Permite que la app host (la que inició la proyección de contenido multimedia) muestre o ocultar el contenido compartido.

    Usa esta devolución de llamada para personalizar la IU de tu app según la imagen región es visible para el usuario. Por ejemplo, si tu app es visible para el usuario y muestra el contenido capturado en la IU de la app. La app capturada también es visible para el usuario (como se indica en este el usuario ve el mismo contenido dos veces. Usa la devolución de llamada para actualizar IU de tu app para ocultar el contenido capturado y liberar espacio de diseño en tu para otro contenido.

  • onCapturedContentResize(): Permite que la app host cambie el tamaño de la proyección de contenido multimedia en la pantalla y proyección de contenido multimedia Surface según el tamaño de la imagen región de la Red de Display.

    Se activa cada vez que se captura el contenido (en una sola ventana de la app o completo) pantalla del dispositivo: cambia de tamaño (debido a la rotación del dispositivo o la ingresar a un modo de renderización en ventanas diferente). Usa esta API para cambiar el tamaño una pantalla virtual y una superficie para garantizar que la relación de aspecto coincida con la contenido y la captura no tiene formato letterbox.

Recuperación de recursos

Tu app debe registrar el MediaProjection onStop() para que se te informe cuando la sesión de proyección de contenido multimedia se detenga y se convierta no válido. Cuando se detiene la sesión, la app debe liberar los recursos que que contiene, como la pantalla virtual y la superficie de proyección. Detenido la sesión de proyección de contenido multimedia ya no puede crear una nueva pantalla virtual, incluso si tu app no creó anteriormente una pantalla virtual para esa proyección de contenido multimedia.

Se llama a la devolución de llamada cuando finaliza la proyección de contenido multimedia, ya sea porque usuario detiene la sesión manualmente, o porque el sistema la detiene por por algún motivo.

Si tu app no registra la devolución de llamada, cualquier llamada a createVirtualDisplay() arroja IllegalStateException

Inhabilitar

Android 14 y versiones posteriores permiten compartir la pantalla de una app de forma predeterminada. Cada contenido multimedia de proyección brinda a los usuarios la opción de compartir la ventana de una app o en toda la pantalla.

Tu aplicación puede inhabilitar la función de compartir pantalla llamando al Método createScreenCaptureIntent(MediaProjectionConfig) con un argumento MediaProjectionConfig mostrado de una llamada a createConfigForDefaultDisplay()

Una llamada a createScreenCaptureIntent(MediaProjectionConfig) con un El argumento MediaProjectionConfig se muestra desde una llamada a createConfigForUserChoice() es igual como el comportamiento predeterminado, es decir, una llamada createScreenCaptureIntent().

Apps que pueden cambiar de tamaño

Siempre haz que las apps de proyección de contenido multimedia puedan cambiar de tamaño (resizeableActivity="true"). Redimensionable admiten cambios en la configuración del dispositivo y el modo multiventana (consulta Compatibilidad con el modo multiventana).

Si no se puede cambiar el tamaño de tu app, esta debe consultar los límites de la pantalla desde una ventana contextual y usa getMaximumWindowMetrics() para recuperar el WindowMetrics de el área de visualización máxima disponible para la app :

Kotlin

val windowContext = context.createWindowContext(context.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(context.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

Recursos adicionales

Para obtener más información sobre la proyección de contenido multimedia, consulta Cómo capturar la reproducción de audio y video.