Proiezione di contenuti multimediali

La android.media.projection Le API introdotte in Android 5 (livello API 21) ti consentono di acquisire i contenuti del display di un dispositivo come stream multimediale che puoi riprodurre, registrare o trasmettere ad altri dispositivi, ad esempio le TV.

Android 14 (livello API 34) introduce la condivisione schermo delle app, che consente agli utenti di condividono una sola finestra dell'app anziché l'intero schermo del dispositivo, indipendentemente la modalità windowing. La condivisione della schermata dell'app esclude la barra di stato, la barra di navigazione notifiche e altri elementi UI di sistema dal display condiviso, persino quando la condivisione schermo dell'app viene utilizzata per acquisire un'app a schermo intero. Vengono condivisi solo i contenuti dell'app selezionata.

La condivisione della schermata dell'app garantisce la privacy degli utenti, aumenta la produttività degli utenti e migliora il multitasking consentendo agli utenti di eseguire più app, ma limitandone la condivisione di contenuti con una sola app.

Tre rappresentazioni del display

Una proiezione multimediale acquisisce i contenuti del display di un dispositivo o della finestra dell'app e quindi proietta l'immagine acquisita su un display virtuale che esegue il rendering Un Surface.

Display di un dispositivo reale proiettato sul display virtuale. Contenuti di
              display virtuale scritto su "Surface" fornito dall'applicazione.
. Figura 1. Schermo reale del dispositivo o finestra dell'app proiettata su display virtuale. Display virtuale scritto nell'applicazione fornita dall'applicazione Surface.

L'applicazione fornisce Surface tramite un MediaRecorder SurfaceTexture oppure ImageReader, che consuma i contenuti del display acquisito e ti permette di gestire le immagini il cui rendering su Surface in tempo reale. Puoi salvare le immagini come registrazione o trasmetterle a una TV o a un altro dispositivo.

Display reale

Avvia una sessione di proiezione di contenuti multimediali ottenendo un token che conceda alla tua app di acquisire i contenuti del display del dispositivo o della finestra dell'app. Il token è rappresentato da un'istanza MediaProjection .

Utilizza il metodo getMediaProjection() del metodo servizio di sistema MediaProjectionManager per creare un'istanza MediaProjection quando inizi una nuova attività. Inizia l'attività con un intent Metodo createScreenCaptureIntent() per specificare una schermata operazione di acquisizione:

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());

Display virtuale

Il pezzo forte di una proiezione multimediale è il display virtuale, che crei chiamando createVirtualDisplay() su un'istanza 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);

I parametri width e height specificano le dimensioni del display. Per ottenere i valori per larghezza e altezza, utilizza il WindowMetrics API introdotte in Android 11 (livello API 30). Per maggiori dettagli, consulta sezione Dimensioni proiezione contenuti multimediali.

Surface

Dimensiona la superficie di proiezione dei contenuti multimediali per produrre l'output nel risoluzione del problema. Ingrandisci (bassa risoluzione) la superficie per trasmettere lo schermo alla TV o monitor di computer e dispositivi di piccole dimensioni (alta risoluzione) per la registrazione del display del dispositivo.

A partire da Android 12L (livello API 32), durante il rendering dei contenuti acquisiti sulla superficie, il sistema scala i contenuti in modo uniforme, mantenendo le proporzioni, in modo che entrambe le dimensioni dei contenuti (larghezza e altezza) siano uguali o inferiori rispetto alle dimensioni corrispondenti della superficie. I contenuti acquisiti vengono quindi centrata sulla superficie.

L'approccio di scalabilità di Android 12L migliora la trasmissione dello schermo sui televisori e altri display di grandi dimensioni massimizzando le dimensioni dell'immagine della superficie e garantendo al contempo le proporzioni corrette.

Autorizzazione per i servizi in primo piano

Se la tua app ha come target Android 14 o versioni successive, il file manifest dell'app deve includere un dichiarazione delle autorizzazioni per Tipo di servizio in primo piano 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>

Avvia il servizio di proiezione multimediale con una chiamata a startForeground().

Se non specifichi il tipo di servizio in primo piano nella chiamata, viene usato per impostazione predefinita in un numero intero a bit dei tipi di servizi in primo piano definiti nel manifest. Se il manifest non specifica alcun tipo di servizio, il sistema genera MissingForegroundServiceTypeException.

L'app deve richiedere il consenso dell'utente prima di ogni sessione di proiezione di contenuti multimediali. R sessione è una singola chiamata a createVirtualDisplay(). Un token MediaProjection deve essere utilizzato una sola volta per effettuare la chiamata.

Su Android 14 o versioni successive, il metodo createVirtualDisplay() genera un SecurityException se l'app esegue una delle seguenti operazioni:

  • Supera un'istanza Intent restituita da createScreenCaptureIntent() a getMediaProjection() più di una volta
  • Chiama createVirtualDisplay() più volte sullo stesso MediaProjection istanza

Dimensioni di proiezione dei contenuti multimediali

Una proiezione multimediale può acquisire l'intero display del dispositivo o una finestra dell'app indipendentemente dalla modalità windowing.

Dimensione iniziale

Con la proiezione multimediale a schermo intero, l'app deve determinare le dimensioni schermo del dispositivo. Nella condivisione schermo dell'app, l'app non riuscirà a determinare il delle dimensioni del display acquisito fino a quando l'utente non ha selezionato la regione di acquisizione. Pertanto, le dimensioni iniziali di qualsiasi proiezione multimediale sono le dimensioni dello schermo del dispositivo.

Utilizza la piattaforma WindowManager getMaximumWindowMetrics() per restituire un WindowMetrics per l'oggetto schermo del dispositivo anche se l'app host per la proiezione di contenuti multimediali è in modalità multi-finestra che occupa solo una parte dello schermo.

Per la compatibilità fino al livello API 14, utilizza WindowMetricsCalculator computeMaximumWindowMetrics() dalla libreria WindowManager Jetpack.

Chiama il metodo WindowMetrics getBounds() per ottenere la larghezza e l'altezza del display del dispositivo.

Modifiche alle dimensioni

Le dimensioni della proiezione multimediale possono cambiare quando il dispositivo viene ruotato oppure l'utente seleziona una finestra dell'app come regione di acquisizione nella condivisione schermo dell'app. La proiezione dei contenuti multimediali potrebbe avere un formato letterbox se i contenuti acquisiti sono di dimensioni diverse rispetto alle metriche di finestra massima ottenute quando la proiezione del video sia stata configurata.

Per garantire che la proiezione dei contenuti multimediali si allinei con precisione alle dimensioni dell'elemento acquisito per qualsiasi regione acquisita e tra rotazioni del dispositivo, utilizza Callback onCapturedContentResize() per ridimensionare l'acquisizione. Per ulteriori informazioni informazioni, consulta la sezione Personalizzazione che segue.

Personalizzazione

La tua app può personalizzare l'esperienza utente relativa alla proiezione di contenuti multimediali con quanto segue API di MediaProjection.Callback:

  • onCapturedContentVisibilityChanged(): Consente all'app host (l'app che ha avviato la proiezione multimediale) di mostrare o nascondendo i contenuti condivisi.

    Utilizza questo callback per personalizzare l'UI dell'app a seconda che l'app acquisita è visibile all'utente. Ad esempio, se la tua app è visibile all'utente, visualizzando i contenuti acquisiti nell'interfaccia utente dell'app e acquisita è visibile anche all'utente (come indicato in ), l'utente vede gli stessi contenuti due volte. Usa il callback per aggiornare nell'interfaccia utente dell'app per nascondere i contenuti acquisiti e liberare spazio di layout per altri contenuti.

  • onCapturedContentResize(): Consente all'app host di modificare le dimensioni della proiezione multimediale sulla proiezione multimediale e display Surface in base alle dimensioni dell'immagine regione di visualizzazione.

    Si attiva ogni volta che vengono acquisiti i contenuti: una singola finestra dell'app o l'intera app display del dispositivo: cambia le dimensioni (a causa della rotazione del dispositivo o del che entra in una modalità windowing diversa). Utilizza questa API per ridimensionare sia display virtuale e superficie per garantire che le proporzioni corrispondano a quelle acquisite contenuti e l'acquisizione non è letterbox.

Recupero delle risorse

La tua app dovrebbe registrare MediaProjection onStop() per essere informato quando la sessione di proiezione multimediale viene interrotta e non valido. Quando la sessione viene interrotta, l'app dovrebbe rilasciare le risorse che come il display virtuale e la superficie di proiezione. A interrotto sessione di proiezione di contenuti multimediali non può più creare un nuovo display virtuale, anche se la tua app non ha creato in precedenza un display virtuale per quella proiezione multimediale.

Il callback viene chiamato quando termina la proiezione multimediale, perché interrompe manualmente la sessione o perché il sistema la interrompe per qualche motivo.

Se la tua app non registra il callback, qualsiasi chiamata al numero createVirtualDisplay() lanci IllegalStateException.

Disattiva

Android 14 o versioni successive attiva la condivisione schermo dell'app per impostazione predefinita. Ogni contenuto multimediale sessione di proiezione offre agli utenti la possibilità di condividere una finestra dell'app o l'intero display.

Per disattivare la condivisione della schermata dell'app, chiama il Metodo createScreenCaptureIntent(MediaProjectionConfig) con un argomento MediaProjectionConfig restituito da una chiamata a createConfigForDefaultDisplay()

Una chiamata a createScreenCaptureIntent(MediaProjectionConfig) con un Argomento MediaProjectionConfig restituito da una chiamata a createConfigForUserChoice() è uguale come comportamento predefinito, ovvero una chiamata createScreenCaptureIntent().

App ridimensionabili

Rendi sempre ridimensionabili le app di proiezione multimediale (resizeableActivity="true"). Ridimensionabile supportano le modifiche alla configurazione del dispositivo e la modalità multi-finestra (vedi supporto multi-finestra).

Se l'app non è ridimensionabile, deve eseguire query sui limiti di visualizzazione da una finestra contesto e usa getMaximumWindowMetrics() per recuperare WindowMetrics di l'area di visualizzazione massima disponibile per l'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();

Risorse aggiuntive

Per ulteriori informazioni sulla proiezione di contenuti multimediali, vedi Acquisisci la riproduzione video e audio.