Le API android.media.projection
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 su altri dispositivi, ad esempio le TV.
Android 14 (livello API 34) introduce la condivisione dello schermo dell'app, che consente agli utenti di condividere una singola finestra dell'app anziché l'intero schermo del dispositivo, indipendentemente dalla modalità di visualizzazione delle finestre. La condivisione schermo dell'app esclude dalla visualizzazione condivisa la barra di stato, la barra di navigazione, le notifiche e altri elementi dell'interfaccia utente di sistema, anche quando viene utilizzata per acquisire un'app a schermo intero. Vengono condivisi solo i contenuti dell'app selezionata.
La condivisione schermo dell'app garantisce la privacy degli utenti, aumenta la loro produttività e migliora il multitasking consentendo loro di eseguire più app, ma limitando la condivisione dei contenuti a una sola app.
Tre rappresentazioni del display
Una proiezione multimediale acquisisce i contenuti della finestra di un'app o del display di un dispositivo e poi proietta l'immagine acquisita su un display virtuale che la esegue il rendering su un Surface
.
L'applicazione fornisce il Surface
tramite un MediaRecorder
,
SurfaceTexture
o ImageReader
, che utilizza i contenuti della
visualizzazione acquisita e ti consente di gestire le immagini visualizzate sul Surface
in
tempo reale. Puoi salvare le immagini come registrazione o trasmetterle a una TV o a un altro dispositivo.
Visualizzazione reale
Avvia una sessione di proiezione di contenuti multimediali ottenendo un token che concede alla tua app la possibilità di acquisire i contenuti del display del dispositivo o della finestra dell'app. Il token è rappresentato da un'istanza della classe MediaProjection
.
Utilizza il metodo getMediaProjection()
del servizio di sistema MediaProjectionManager
per creare un'istanza MediaProjection
quando avvii una nuova attività. Avvia l'attività con un'intent dal metodo
createScreenCaptureIntent()
per specificare un'operazione di acquisizione dello schermo:
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];
ActivityResultLauncherstartMediaProjection = 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 fulcro 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 virtuale. Per ottenere i valori di larghezza e altezza, utilizza le API WindowMetrics
introdotte in Android 11 (livello API 30). Per maggiori dettagli, consulta la sezione Dimensioni proiezione media.
Surface
Regola le dimensioni della superficie di proiezione dei contenuti multimediali in modo da produrre un output con la risoluzione appropriata. Rendi la superficie grande (bassa risoluzione) per la trasmissione dello schermo su TV o monitor di computer e piccola (alta risoluzione) per la registrazione del display del dispositivo.
A partire da Android 12L (livello API 32), quando esegue il rendering dei contenuti acquisiti sulla superficie, il sistema li ridimensiona in modo uniforme, mantenendo le proporzioni, in modo che entrambe le dimensioni dei contenuti (larghezza e altezza) siano uguali o inferiori alle dimensioni corrispondenti della superficie. I contenuti acquisiti vengono poi centrati sulla superficie.
L'approccio di ridimensionamento di Android 12L migliora la trasmissione dello schermo su TV e altri display di grandi dimensioni massimizzando le dimensioni dell'immagine della superficie 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 una dichiarazione di autorizzazione per il 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, il tipo predefinito è un numero intero a livello di bit dei tipi di servizio in primo piano definiti nel manifest. Se il manifest non specifica alcun tipo di servizio, il sistema genera un errore MissingForegroundServiceTypeException
.
Consenso dell'utente
L'app deve richiedere il consenso dell'utente prima di ogni sessione di proiezione di contenuti multimediali. Una
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 messaggio di errore
SecurityException
se la tua app esegue una delle seguenti operazioni:
- Passa un'istanza
Intent
restituita dacreateScreenCaptureIntent()
agetMediaProjection()
più volte - Chiama
createVirtualDisplay()
più di una volta nella stessaMediaProjection
istanza
Dimensioni della proiezione di contenuti multimediali
Una proiezione multimediale può acquisire l'intero display del dispositivo o una finestra dell'app indipendentemente dalla modalità di visualizzazione della finestra.
Dimensioni iniziali
Con la proiezione multimediale a schermo intero, l'app deve determinare le dimensioni dello schermo del dispositivo. Nella condivisione schermo dell'app, l'app non potrà determinare le dimensioni del display acquisito finché l'utente non avrà selezionato la regione di acquisizione. Pertanto, le dimensioni iniziali di qualsiasi proiezione multimediale corrispondono alle dimensioni dello schermo del dispositivo.
Utilizza il metodo della piattaforma WindowManager
getMaximumWindowMetrics()
per
restituire un oggetto WindowMetrics
per lo schermo del dispositivo anche se l'app
host di proiezione multimediale è in modalità multifinestra, occupando solo una parte del
display.
Per la compatibilità fino al livello API 14, utilizza il metodo WindowMetricsCalculator
computeMaximumWindowMetrics()
della libreria WindowManager
Jetpack.
Chiama il metodo WindowMetrics
getBounds()
per ottenere la larghezza e l'altezza del display del dispositivo.
Modifiche delle dimensioni
Le dimensioni della proiezione dei contenuti multimediali possono cambiare quando il dispositivo viene ruotato o quando l'utente seleziona una finestra dell'app come regione di acquisizione nella condivisione dello schermo dell'app. La proiezione multimediale potrebbe essere letterbox se le dimensioni dei contenuti acquisiti sono diverse da quelle delle metriche della finestra massima ottenute durante la configurazione della proiezione multimediale.
Per assicurarti che la proiezione dei contenuti multimediali sia perfettamente allineata alle dimensioni dei contenuti acquisiti per qualsiasi regione acquisita e per tutte le rotazioni del dispositivo, utilizza il callback onCapturedContentResize()
per ridimensionare l'acquisizione. (per maggiori informazioni, consulta la sezione Personalizzazione che segue).
Personalizzazione
La tua app può personalizzare l'esperienza utente della proiezione multimediale con le seguenti API MediaProjection.Callback
:
onCapturedContentVisibilityChanged()
: consente all'app host (l'app che ha avviato la proiezione multimediale) di mostrare o nascondere i contenuti condivisi.Utilizza questo callback per personalizzare l'interfaccia utente dell'app in base al fatto che la regione acquisita sia visibile all'utente. Ad esempio, se la tua app è visibile all'utente e mostra i contenuti acquisiti all'interno dell'interfaccia utente dell'app e l'app acquisita è visibile anche all'utente (come indicato tramite questo callback), l'utente vede gli stessi contenuti due volte. Utilizza il callback per aggiornare l'interfaccia utente della tua app in modo da nascondere i contenuti acquisiti e liberare spazio nel layout dell'app per altri contenuti.
onCapturedContentResize()
: consente all'app host di modificare le dimensioni della proiezione dei contenuti multimediali sul display virtuale e della proiezione dei contenuti multimedialiSurface
in base alle dimensioni della regione del display acquisita.Viene attivato ogni volta che i contenuti acquisiti, una singola finestra dell'app o la visualizzazione completa del dispositivo, cambiano dimensione (a causa della rotazione del dispositivo o dell'ingresso dell'app acquisita in una modalità di visualizzazione della finestra diversa). Utilizza questa API per ridimensionare sia il display virtuale sia la superficie per assicurarti che le proporzioni corrispondano ai contenuti acquisiti e che l'acquisizione non sia letterbox.
Recupero delle risorse
L'app deve registrare il callback MediaProjection
onStop()
per essere informata quando la sessione di proiezione multimediale viene interrotta e non è più valida. Quando la sessione viene interrotta, l'app deve rilasciare le risorse che detiene, ad esempio il display virtuale e la superficie di proiezione. Una sessione di proiezione multimediale interrotta non può più creare un nuovo display virtuale, anche se l'app non ha creato precedentemente un display virtuale per quella proiezione multimediale.
Il sistema richiama la funzione di callback al termine della proiezione multimediale. Questo tipo di interruzione può verificarsi per diversi motivi, ad esempio:
- L'utente interrompe la sessione utilizzando l'interfaccia utente dell'app o il chip della barra di stato della proiezione media del sistema
- lo schermo viene bloccato
- viene avviata un'altra sessione di proiezione di contenuti multimediali
- il processo dell'app viene interrotto
Se la tua app non registra il callback, qualsiasi chiamata a createVirtualDisplay()
lancia IllegalStateException
.
Disattiva
Android 14 o versioni successive attiva la condivisione della schermata dell'app per impostazione predefinita. Ogni sessione di proiezione di contenuti multimediali offre agli utenti la possibilità di condividere una finestra dell'app o l'intero display.
La tua app può disattivare la condivisione della schermata dell'app chiamando 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 al comportamento predefinito, ovvero
una chiamata a createScreenCaptureIntent()
.
App ridimensionabili
Rendi sempre ridimensionabili le app di proiezione multimediale (resizeableActivity="true"
). Le app ridimensionabili supportano le modifiche alla configurazione del dispositivo e la modalità multi-finestra (vedi Supporto della modalità Multi-finestra).
Se la tua app non è ridimensionabile, deve eseguire una query sui limiti di visualizzazione da un contesto della finestra e utilizzare getMaximumWindowMetrics()
per recuperare il WindowMetrics
dell'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();
Chip barra di stato e arresto automatico
Gli exploit di proiezione dello schermo espongono i dati utente privati, come le informazioni finanziarie, perché gli utenti non si rendono conto che lo schermo del loro dispositivo viene condiviso.
Android 15 (livello API 35) e versioni successive mostrano un chip della barra delle app grande e in evidenza per avvisare gli utenti di eventuali proiezioni dello schermo in corso. Gli utenti possono selezionare il chip per impedire la condivisione, la trasmissione o la registrazione dello schermo. Inoltre, la proiezione dello schermo si interrompe automaticamente quando lo schermo del dispositivo è bloccato.
Verifica la disponibilità del chip della barra di stato della proiezione multimediale avviando la condivisione schermo, la trasmissione o la registrazione. Il chip dovrebbe apparire nella barra di stato.
Per assicurarti che la tua app rilasci le risorse e aggiorni la sua UI quando la proiezione dello schermo viene interrotta dall'interazione dell'utente con il chip della barra di stato o dall'attivazione della schermata di blocco, svolgi i seguenti passaggi:
Crea un'istanza di
MediaProjection.Callback
.Implementa il metodo di callback
onStop()
. Il metodo viene chiamato quando la proiezione sullo schermo si interrompe. Rilascia le risorse occupate dall'app e aggiorna la UI dell'app in base alle necessità.
Per testare il callback, tocca il chip della barra di stato o blocca lo schermo del dispositivo per interrompere la proiezione dello schermo. Verifica che il metodo onStop()
venga chiamato e che l'app risponda come previsto.
Risorse aggiuntive
Per ulteriori informazioni sulla proiezione di contenuti multimediali, vedi Acquisire il Playback di contenuti video e audio.